假设我使用Flask创建一个简单的Web服务器,并且允许人们使用__import__
语句查询我在不同python文件中调制的某些内容,那么使用用户提供的信息会被视为安全风险吗?
示例:
from flask import Flask
app = Flask(__name__)
@app.route("/<author>/<book>/<chapter>")
def index(author, book, chapter):
return getattr(__import__(author), book)(chapter)
# OR
return getattr(__import__("books." + author), book)(chapter)
我在审核代码时最近看到过这样的案例,但对我来说并不合适。
答案 0 :(得分:2)
这是完全不安全的,你的系统很容易受到攻击。您的第一个return
行并不限制可以导入的名称类型,这意味着用户可以在任何可导入的Python模块中执行任意任意调用。
包括:
/pickle/loads/<url-encoded pickle data>
pickle是lets you execute arbitrary Python code的堆栈语言,攻击者可以完全控制您的服务器。
如果攻击者还可以在__import__
中的文件系统上放置文件,那么即使是带前缀的PYTHONPATH
也不安全;他们所需要的只是路径前面的books
目录。然后,他们可以使用此路线在Flask过程中执行文件,再次让他们完全控制。
我根本不会在这里使用__import__
。只需在开始导入这些模块,并使用字典映射author
到已导入的模块。您可以在启动时使用__import__
仍然发现这些模块,但现在删除了从文件系统加载任意代码的选项。
还应避免允许不受信任的数据直接调用模块中的任意对象(包括getattr()
)。同样,对系统具有有限访问权限的攻击者可以利用此路径大大扩展破解。始终将输入限制为可能选项的白名单(例如,您在开始时加载的模块,以及每个模块,实际可以在其中调用的对象)。
答案 1 :(得分:0)
不仅仅是一种安全风险,这是一个坏主意,例如:我可以通过访问网址轻松崩溃您的网络应用程序:
/sys/exit/anything
转换为:
...
getattr(__import__('sys'), 'exit')('anything')
不要为用户导入/执行任何内容。正如明确指出的@MartijnPieters那样,通过使用允许导入字典来限制可能性。