最常见的Web应用程序安全弱点是未能从客户端或环境中正确验证输入。
Owasp,数据验证(2017年7月2日)
无法正确处理不受信任的输入将使易受代码注入攻击的应用程序,例如跨站点脚本(XSS)。 Owasp推荐的一种对策是“客户或不信任来源的某种形式的可见污染”,这是一项深入的防御策略的一部分。
这个Python模块“ Taints”不受信任的输入将其包裹在特殊类型中。这些类型在大多数方面的行为就像本地python类型一样,但阻止您意外使用其价值。这不仅提供了“可见的污染”,还提供了运行时的保证和((可选)静态验证的类型安全性,并具有mypy。
该模块的消毒,逃脱,正常化或验证输入的策略不超出范围。
该模块应适合生产使用,并有以下警告:
untrusted.sequence 。untrusted.mapping类型缺少测试,可能不完整unstrusted.<*>Of未完全测试任何具有安全考虑的代码都应得到最高的审查标准。在使用此模块之前,请执行您的判断。
该软件是“原样”提供的,没有任何形式的保证。
测试了Python> = 3.4,但更早的版本可能会起作用。
sudo pip3 install untrusted --upgrade
(如果您只安装了Python3,则可能只需要pip而不是pip3 )
import html # for html.escape
import untrusted
line = untrusted . string ( input ( "Enter some text, HTML will be escaped: " ))
try :
# You're not allowed to print an untrusted.string!
# This raises a TypeError!
print ( "<b>You typed:</b> " + line )
except TypeError :
pass # Expected
# Safely escape the HTML!
print ( "<b>You typed:</b> " + line / html . escape )
# / is overloaded as shorthand for:
# print("<b>You typed:</b> " + line.escape(html.escape)) untrusted.string弦类型str类型,但无法逃脱而无法输出str类型无缝互操作str和untrusted.string用法。String污染str值/将其促进到untrusted.string刺激类型。处理不信任的HTML的示例:
import html # for html.escape()
import untrusted
# example of a string that could be provided by an untrusted user
firstName = untrusted . string ( "Grace" )
lastName = untrusted . string ( "<script>alert('hack attempt!');</script>" )
# works seamlessly with native python strings
fullName = firstName + " " + lastName
# fullName was tainted and keeps the untrusted.string type
print ( repr ( fullName )) # <untrusted.string of length 46>
# the normal string methods still work as you would expect
fullName = fullName . title ()
# but you can't accidentally use it where a `str` is expected
try :
print ( fullName ) # raises TypeError - untrusted.string used as a `str`!
fullName . encode ( 'utf8' ) # also raises TypeError
except TypeError :
print ( "We caught an error, as expected!" )
# instead, you are forced to explicitly escape your string somehow
print ( "<b>Escaped output:</b> " + fullName . escape ( html . escape )) # prints safe HTML!
print ( "<b>Escaped output:</b> " + fullName / html . escape ) # use this easy shorthand!有关构成多个逃生功能,通过参数以逃脱功能等,请参见untrustedStringExample.py
该模块为懒惰的不信任值的收集提供了类型。这些值用适当的untrusted.*访问时类型。
untrusted.iteratoruntrusted.*类型untrusted.string ,但它也可以是不受信任的收藏例子:
import html # for html.escape
import untrusted
it = untrusted . iterator ( open ( "example.txt" ))
for i , s in enumerate ( it ):
print ( "Line %d: %s" % ( i , s . escape ( html . escape ). strip ()))有关不信任untrusted.iterator untrusted.string列表,请参见examples/untrustedIteratorExample.py untrusted.iterator 。
untrusted.sequencelist视图 - 包含不信任值的对象。untrusted.*类型untrusted.string ,但它也可以是不受信任的收藏例子:
import html # for html.escape
import untrusted
# list of strings from an untrusted source
animals = [ "cat" , "dog" , "monkey" , "elephant" , "<big>mouse</big>" ]
untrustedAnimalList = untrusted . sequence ( animals )
assert "cat" in untrustedAnimalList untrusted.mappingdict的对象映射受信任或不信任的键的视图。untrusted.*类型。str > untrusted.string ,但也可能是一个unstrusted.string映射。STRING-> untrusted.string ,或映射到不信任的集合。例子:
import html # for html.escape
import untrusted
user = untrusted . mapping ({
'username' : 'example-username<b>hack attempt</b>' ,
'password' : 'example-password' ,
})
try :
print ( user . get ( "username" ))
except TypeError :
print ( "Caught the error we expected!" )
print ( user . get ( "username" , "default-username" ) / html . escape )例子:
import html # for html.escape
import untrusted
untrustedType = untrusted . mappingOf ( untrusted . string , untrusted . string )
args = untrustedType ({ 'animal' : 'cat' , '<b>hack</b>' : 'attempt' })
for k , v in args . items ():
print ( "%s: %s" % ( k / html . escape , v / html . escape ))懒惰的嵌套容器也得到了充分的支持。
使用Un trusted.iteratorof( untrusted.sequenceOf(valueType) untrusted.iteratorOf(valueType) , untrusted.mappingOf(keyType, valueType) 。
例子:
import html # for html.escape
import untrusted
people = [
{
'id' : 'A101' ,
'name.first' : 'Grace' ,
'name.last' : 'Hopper' ,
'name.other' : 'Brewster Murray' ,
'dob' : '1906-12-09' ,
},
{
'id' : 'A102' ,
'name.first' : 'Alan' ,
'name.last' : 'Turing' ,
'name.other' : 'Mathison' ,
'dob' : '1912-06-23' ,
},
{
'id' : 'HACKER' ,
'name.first' : 'Robert ' ); DROP TABLE Students;--' ,
'name.last' : '£Hacker' ,
'dob' : '<b>Potato</b>'
},
]
# a list of dicts with trusted keys, but untrusted values
mappingType = untrusted . sequenceOf ( untrusted . mapping )
# aka (setting defaults explicitly)
mappingType = untrusted . sequenceOf ( untrusted . mappingOf ( str , untrusted . string ))
for person in mappingType ( people ):
for key , value in person . items ():
print ( " %s: %s" % ( key , value . escape ( html . escape )))支持大多数本机str方法,但可能具有不同的返回类型。
基础值 - 始终是str的非某人实例。
untrusted.string(s)
构建一个untrusted.string对象,其中s是str或untrusted.string的非某人实例。
在untrusted.string的情况下,用untrusted.string论点构造出来,新值仅包装一次。逃脱它将给出一个str ,而不是untrusted.string 。
untrusted.string.escape(escape_function, [*args, **kwargs]) -> str
应用escape_function ,一个函数str -> str它可以通过可选的参数和关键字参数来逃脱字符串并将其返回。
untrusted.string.valid(valid_function, [*args, **kwargs]) -> bool
应用valid_function ,一个函数str -> bool ,该函数可以检查字符串并返回真或错误,并使用可选的参数和关键字参数。
untrusted.string.valid(validate_function, [*args, **kwargs]) -> any
应用valid_function ,一个函数str -> any ,检查字符串并返回任何值(例如,字符串未验证的原因列表),带有可选的参数和关键字参数。
untrusted.string / escape_expr对于某些逃生表达式, untrusted.string("value") / escape_expr -> str
escape_expr在这里是一个函数str -> str ,可以逃脱字符串,或者是3个支马(escape_function, args, kwargs_dict) ,例如:
import html # for html.escape
import untrusted
myString = untrusted . string ( "<b>Exam " ple</b>" )
myEscape = ( html . escape , [], { 'quote' : False })
print ( myString / html . escape )
print ( myString / myEscape )其中collection是iterator之一, sequence (列表状), mapping (类似于dict)或用户构造的自定义类型。
支持大多数本机收集方法,但可能具有不同的返回类型。
每个集合都知道其价值类型(默认的untrusted.string )。
映射也知道其关键类型(默认str )
基本值 - 始终是该集合值类型的实例的非对象。
使用untrusted.iteratorOf(type)创建迭代类型。
使用untrusted.sequenceOf(type)创建序列类型。
使用untrusted.sequenceOf(keyType, valueType)创建映射类型。
这些定义是递归的。
例如:
import untrusted
itType = untrusted . iteratorOf ( untrusted . iteratorOf ( untrusted . string ))
seqType = untrusted . sequenceOf ( itType )
mappingType = untrusted . mappingOf ( untrusted . string , seqType )
someDict = {}
myMapping = mappingType ( someDict )
# or, as a less readable one-liner
myMapping = untrusted . mappingOf ( untrusted . string , seqType )( someDict )请记住,仅仅因为您使用了一种方法来逃避untrusted.string方法。弹簧进入str ,它在其他情况下可能并不安全。例如,对HTML的安全可能仍然是危险的SQL。在捕获用户输入时,可能不知道它要使用的上下文 - 因此,尚不知道正确的验证和逃脱策略是什么。最好将逃逸延迟到最终使用点 - 保持untrusted.*尽可能长时间。
这个模块不是神奇的解决方案。这是可以明智使用的工具。不要陷入思考一个价值的陷阱:“现在已经是str ,所以它是完全安全的”。
仅仅因为可以安全地逃脱字符串,这并不意味着它已被验证为允许输入。例如,您可能会对密码提出最小限制。或者您可能要求输入不是预留的文件名。
做到这一点的好方法是使用unstruted.string.valid方法,该方法返回一个布尔, untrusted.string.validate方法,该方法返回任何值(例如,这可能是输入没有valdiate的原因列表),或者从Escapes and Vellate和验证的函数中抛出ValueError 。
有时,您会自己生成HTML并逃脱是您需要做的事情。
有时,接口总是像大多数现代SQL库一样将参数与代码分开。在这种情况下,数据库驱动程序将比您希望的更好地处理潜在的不受信任的输入,并且逃脱是错误的。
由于其他原因,您可能会将输入标记为不信任 - 例如,在搜索查询上执行最大长度,或者是因为您需要根据业务逻辑进行验证。
不受信任的收集类型,例如untrusted.sequence序列。如果基础对象发生了变化,则您通过不信任的收集类型看到的对象也会发生。换句话说:它是对同一对象的引用,而不是副本。如果不是您想要的,请使用复制模块。
希望这应该是显而易见的,且不夸张的行为,而不是这个模块所独有的,但它可以绊倒人们。
这是免费软件(麻省理工学院许可证)。
untrusted - write safer Python with special untrusted types
Copyright © 2017 - 2018 Ben Golightly <[email protected]>
Copyright © 2017 - 2018 Tawesoft Ltd <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.