Наиболее распространенной слабостью безопасности веб -приложений является неспособность должным образом проверить ввод от клиента или среды.
OWASP, проверка данных (2 июля 2017 г.)
Неспособность должным образом обрабатывать ненадежный вход оставляет приложение уязвимым для атак впрыскивания кода, такими как сценарии кросс -сайта (XSS). «Некоторая форма видимого улова при вводе от клиента или ненадежных источников» - это одна контрмеза, рекомендованная OWASP, как часть стратегии защиты глубины.
Этот модуль 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 , но не может быть выводом без выходаstrstr str и untrusted.string 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.string examples/untrustedIteratorExample.py для ненадежного вложенного списка (например untrusted.iterator 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 без 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 ))Лзико вложенные контейнеры также полностью поддерживаются.
Используйте untrusted.iteratorOf(valueType) , untrusted.sequenceOf(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)
s untrusted.string untrusted.string str
В случае 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 , которая проверяет строку и возвращает true или false, с необязательными аргументами и аргументами ключевых слов.
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 -uple (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 (диктаподобное) или созданный пользователем пользовательский тип.
Поддерживает большинство местных методов сбора, но, возможно, могут иметь разные типы возврата.
Каждая коллекция знает о своем типе значения (по умолчанию 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 ) Помните, только потому, что вы использовали один метод, чтобы str untrusted.string . Например, то, что безопасно для HTML, может быть опасным SQL. В то время, когда ввод пользователя запечатлен, он может быть заранее не известен контекст, в котором он должен использоваться - и поэтому еще не известно, какова правильная стратегия проверки и ухода. Лучше всего отложить сбегание до окончательной точки использования - сохранить значение как untrusted.* Как можно дольше.
Этот модуль не волшебным решением. Это инструмент, который можно использовать с умом. Не попадайте в ловушку, думая о ценности «Теперь это str , так что это совершенно безопасно».
Тот факт, что строку можно безопасно избежать, это не означает, что она была проверена как допустимый вход. Например, вы можете положить минимальный предел пароля. Или вы можете потребовать, чтобы вход не был зарезервированным именем файла.
Хорошие способы сделать это - использовать метод unstruted.string.valid , который возвращает ValueError , untrusted.string.validate метод.
Иногда вы сами генерируете HTML и выберите - это то, что вам нужно сделать.
Иногда интерфейс всегда отделяет параметры от кода, как и большинство современных библиотек SQL. В этом случае драйвер базы данных будет обращаться с потенциально ненадежным входом лучше, чем вы когда -либо могли надеяться, и избежать его, - это неправильное, что нужно сделать.
Вы можете отметить входной вход как неуверенный по другим причинам - например, для обеспечения максимальной длины в поисковом запросе или потому, что вам необходимо проверить его против бизнес -логики.
Недоверенные типы сбора, такие как untrusted.sequence , являются «взглядами» над подчиненным объектом. Если базовый объект меняется, то и объект, который вы видите, через неуверенный тип сбора. Другими словами: это ссылка на тот же объект, а не копия. Если это не то, что вы хотите, используйте модуль копирования.
Надеемся, что это должно быть очевидным и неопрессиционным поведением, совсем не уникальным для этого модуля, но оно может сбить с толку людей.
Это бесплатное программное обеспечение (лицензия MIT).
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.