使用 Roslyn 在服务器端 API 上安全执行代码 [英] Safe code execution on server side API with Roslyn

查看:49
本文介绍了使用 Roslyn 在服务器端 API 上安全执行代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了给我的用户更大的灵活性并让他们编写自己的表达式,我希望允许他们在文本字段中编写非常简单的 C# 语句,这些语句在服务器端执行以进行一些自定义计算.我正在与 Roslyn 一起存档.
这里.

To give my users more flexibility and to let them write their own expressions, I want to allow them to write very simple C# statements in a text field that are executed on server side to do some custom calculations. I am archiving this with Roslyn.
A good example to start for me can be found here.

我让用户在评估函数中注入代码,如下所示:

I let users inject code inside an evaluation function, like this:

        string codeToCompile = @"
        using System;
        using System.Collections.Generic;
        namespace Evaluator
        {
            public class Evaluator
            {
                public string Eval()
                {
                    " + {POTENTIALLY_DANGEROUS_CODE_GOES_HERE} + @"                      
                }
            }
        }";

你可以看到注入的代码总是在一个 Eval-Function 中,最后应该返回一个字符串.
用户可以决定如何计算这个字符串.
我现在正在考虑安全性,因为我对注入的代码没有任何控制权.

You can see that the injected code is always inside an Eval-Function and should return a string in the end.
The user can decide how this string is calculated.
I am now thinking of security, because I do not have any control of the injected code.

实际上我的用户应该只能:

Actually my users should only be able to:

  • 使用数学表达式
  • 原始变量
  • if 语句

因此,注入代码的示例可能如下所示:

So an example injected code could look like this:

int a = 5;
int b = 10;

if(a < b) 
{
   return "a is smaller";
}
else
{
   return "a is bigger or equal";
}

您可以在上面的示例代码中看到,命名空间仅限于System";和System.Collections.Generic",所以很多东西将不再可能(比如从服务器的文件系统中读取一些东西并将这些信息作为字符串输出)

You can see in the sample code above, that the namespace is limited to "System" and "System.Collections.Generic", so a lot of stuff wont be possible anymore (like reading something from the file system of the server and outputting this information as a string)

我还替换了所有出现的循环,因此像 while、for、foreach 等表达式...从字符串中删除.

I also replace all occurences of loops, so expressions like while, for, foreach etc... are removed from the string.

但我仍然不确定这个解决方案是否安全.

But I am still pretty unsure if this solution is secure.

  1. 潜在攻击者现在还能做什么?(特别是两个提供的命名空间的选项)
  2. 在这种情况下,我可以采取哪些最佳做法来防止攻击?

推荐答案

根据您的需要,这非常很难做到.很难.如果你非要问怎么做,你可能会不知所措";难的.一些有趣的事情需要考虑:

Depending on your needs, this is very hard to get right. Very hard. "If you have to ask how to do it you might be over your head" hard. Some fun things to consider:

  1. 仅仅因为您限制了文件顶部的命名空间,并不意味着有人不能将其代码片段中的某些内容明确限定为不同的命名空间.所以重要的是你必须遍历整个代码,看看是否有任何其他类型的用途.我不知道您允许的显式列表是否隐式禁止所有方法调用或对象创建.
  2. 在假设 System 中的任何内容都是安全的时要小心.考虑 System.Activator,它允许您调用 CreateInstance 并传入另一种类型的字符串名称来创建它.仅这种类型就可以让您绕过您可能执行的任何其他检查.当我按字母顺序提取 System 命名空间中的文档时,这只是第一个跳出来的!
  3. ...当然不要只是专门阻止 System.Activator.每当您更新人们针对哪个框架编写代码时,都可能会出现有问题的新类型.

还要考虑您的潜在安全攻击类型:即使您无法写入文件,您是否仍会从您的服务器泄漏信息(例如用户名或机器名称),这可能允许用户以其他方式闯入您的系统.或者他们只是编写一个消耗服务器资源的无限循环.您提到您将删除循环,但不要忘记诸如 goto 之类的事情,或者只是编写某种会导致堆栈溢出的递归函数.

Also consider your types of potential security attacks: even if you can't write files, can you still leak information from your server (like the username or machine name) that might allow the user to break into your system some other way. Or they just write an infinite loop which consumes server resources. You mentioned that you'll remove loops, but don't forget things like goto, or just writing some sort of recursive function that does a stack overflow.

我不会说只做 X 就安全了",因为我什至不相信自己会写那个.但是:

I'm not going to say "just do X and it's safe", because I don't even trust myself to write that. But:

  1. 使用您的操作系统来帮助您隔离:在具有较少权限或没有权限等的单独进程中运行它.如果您可以执行单独的 VM/容器,那就太好了.在这里隔离得越多越好.
  2. 如果您要进行代码检查,请不要拒绝您知道不好的模式;而是编写仅接受您知道安全"的模式的代码.这可能会导致很多工作来选择愚蠢的事情,但替代方案要求您列举所有不好的事情.

这篇关于使用 Roslyn 在服务器端 API 上安全执行代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆