允许用户输入python的__import__会有安全风险吗?

时间:2017-06-27 09:37:43

标签: python security

假设我使用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)  

我在审核代码时最近看到过这样的案例,但对我来说并不合适。

2 个答案:

答案 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那样,通过使用允许导入字典来限制可能性。