【问题标题】:Running Untrusted Python Code in AWS-LAMBDA using Exec or Eval使用 Exec 或 Eval 在 AWS-LAMBDA 中运行不受信任的 Python 代码
【发布时间】:2020-10-30 16:57:39
【问题描述】:

一直在做大量的研究。我只是一个学徒,但是,我有一个项目,我必须从网站上运行用户不受信任的 Python3 代码。

如果这个问题有一些移动部分,我也提前道歉。

  • 我正在寻找一种尽可能安全的方法。这不需要 100% 完美,除非存在泄露极其敏感数据的巨大风险

主要问题

  • 我的 AWS-lambda 计划是否存在泄露敏感数据的极端风险?
  • 我是否应该采取任何其他简单的预防措施来使这项工作在 AWS-lambda 中更安全?
  • exec() 是否有办法脱离 AWS-lambda 容器并建立任何其他网络连接(如果我连接的只是单个 AWS-lambda 容器) strong>AWS-api-gateway 用于 REST 调用?
  • 我什至需要限制 __builtins__ 和本地人,还是 AWS-lambda 容器足够安全?

背景

似乎大多数公司使用 KubernetesDocker 容器 来执行不受信任的 Python 代码(例如 LeetcodeProgramizhackerRank)。

查看这些有用的链接:

我的计划

我认为我可以将我的任意 Python 代码作为 微服务 发布到 AWS Lambda 函数,而不是使用 他们的 容器化/缩放而不是建立我自己的。在 Lambda 容器中,我可以通过一个简单的 execeval 函数运行代码,可能会有一些限制,如下所示:

"

safe_list = ['math','acos', 'asin', 'atan', 'print','atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh'] 
    safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ]) 
    safe_dict['abs'] = abs
    exec(userCode,{"**__builtins__"**:None},safe_dict )

特别说明:

  • 我不太担心无限循环或崩溃,因为我只会超时并告诉用户再试一次。
  • 我需要做的就是运行 非常简单 python 代码(通常少于几行) 并返回异常、stdout、打印,然后运行检查结果。需要运行:
    • 数学运算符、列表、循环、lambda 函数、映射、过滤器、声明方法、声明具有属性的类、打印。
  • 对于成千上万的用户来说,这不需要是一个完美的项目。我只是想有一个现场网站来增加简历,也许可以在广告上赚点钱来帮助降低成本。
  • 如果有严重的限制,我最终可以在 Kubernetes 中实现它(如上面的链接中所示),但希望这个解决方案能够运行良好。
  • 我只是希望它能够相对较好地工作,并且不会花费太长时间来构建或花费太多钱。
  • 我不想泄露任何敏感信息。

我已经计划做的安全事情:

  • AWS lambda:将 超时 限制在 1-2 秒
  • AWS lambda:将 内存使用量 限制为 128mb
  • 我自己的代码:使用 regex 确保没有人传入 双下划线 badstuff
  • 尽量减少此微服务(仅连接单个 AWS-API 网关)。

其他说明:

  • 我认为我无法在 AWS Lambda 中使用 restrictedPythonPyPy 的沙盒 功能,因为我无法访问这些依赖项OOB。我希望这些对于这个用例来说不是必需的。
  • 如果使用 exec() 无法做到这一点,那么 GitHub 上是否有 安全的 Python 解释器 或者我可以从字面上复制粘贴到 AWS-lambda 中的文件的地方然后打电话给他们?
  • 我计划允许用户从 exec 打印,如下所示:

"

@contextlib.contextmanager
def stdoutIO(stdout=None):
    old = sys.stdout
    if stdout is None:
        stdout = StringIO()
    sys.stdout = stdout
    yield stdout
    sys.stdout = old

    
with stdoutIO() as s:
    try:
        exec(userCode)
    except:
        print("Something wrong with the code")
print( s.getvalue())
print(i)

如果您有任何问题或建议,请告诉我。

___编辑**添加架构图___

【问题讨论】:

  • 你最终选择了那条路吗,@hippomano?
  • 还没有。自从我得到一份新工作后就搁置了这个项目,但我认为 LAMBDA 功能的容器化目前还不错。需要对此进行大量试验。

标签: python amazon-web-services aws-lambda architecture aws-api-gateway


【解决方案1】:

我也在研究这个问题,并且对是否可以使用 AWS lambda 运行不受信任的代码感兴趣。大多数情况下,您的逻辑看起来很合理,但有几件事很突出

使用正则表达式确保没有人传入双下划线坏东西

不要这样做!不可能(或几乎不可能)检查包含 python 代码的字符串是否是恶意的。想想有人要你给这个打电话:

eval(base64.b64decode(b'cHJpbnQoInRoaXMgaXNuJ3QgYmFkLCBidXQgeW91IGRvbid0IGtub3cgdGhhdCEiKQ=='))

这样安全吗?它会被正则表达式提取吗?很好,你可以模拟eval(),但接下来呢?我绝对不怀疑一个半胜任的 Python 开发人员可以找到绕过它的路线。

半安全比不安全更糟糕

您将开始信任它,构建另一个依赖于半安全层的功能并最终被黑客入侵。


解决方案

  1. 使用许多人和大公司都依赖的语言或功能,这样泄露的风险很小(如果有人确实发现了零日漏洞,那么会有比你更有利可图的人来破解) .如果您可以使用 Javascript,这里可能是一个不错的选择,您也可以尝试将 pypy 或 RustPython 编译为 Web 程序集。
  2. 接受您的代码根本不安全,并依靠 OS/PAAS 来保护您。换句话说,让用户在 AWS lambda 中运行他们喜欢的任何东西,并让 Amazon 将其隔离。

我的问题

我想使用第二个选项,但我担心敌对开发人员会污染 lambda 容器,然后另一个无辜的开发人员会使用该容器成为受害者。

假设我们有一个有效地调用eval(user_written_code) 并返回结果的AWS lambda,它还可能设置了一堆可以在user_written_code 中引用的环境变量。

当代码被调用时,lambda 可以防止他们做任何恶意的事情——例如。 lambda 用户凭据无权访问任何可怕的东西。他们可以发出请求、耗尽内存、占用 CPU、挂起 - 所有这些都由 AWS 负责。

但是如何停止以下向量:

  1. 恶意用户执行模拟内置方法的代码,当调用该方法时,当前代码上下文和环境变量已发布到某个服务器。
  2. 无辜用户在同一个 lambda 容器上执行他们的代码,AWS lambda 巧妙地重用该过程来提高性能。
  3. 无辜用户的代码和凭据(环境变量)被发布到恶意用户服务器。

我很想知道是否有其他人已经确认了是否有有效的方法来防止 lambda 容器受到这样的污染?

【讨论】:

    【解决方案2】:

    有趣的帖子,我也在考虑使用现有的 AWS 基础设施来运行不受信任的 python 代码,而不是使用可能很快变得昂贵的 docker 容器。我才刚刚开始研究这个,但我更喜欢使用受限制的 Python 来添加一些安全防护。

    我对 python 开发和 lambda 都很陌生,但你提到受限 Python 不是开箱即用的,当然你需要做的就是将它作为依赖项包含在 zip 中并将其上传到 lambda ?除非我错过了什么?

    也不确定你是否看过这个,但我发现这个视频很有帮助:https://www.youtube.com/watch?v=sL_syMmRkoU

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 1970-01-01
      • 2017-11-05
      • 2017-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多