가장 일반적인 웹 응용 프로그램 보안 약점은 클라이언트 또는 환경에서 입력을 올바르게 검증하지 못하는 것입니다.
OWASP, 데이터 검증 (2017 년 7 월 2 일)
신뢰할 수없는 입력을 올바르게 처리하지 않으면 응용 프로그램이 크로스 사이트 스크립팅 (XSS)과 같은 코드 주입 공격에 취약합니다. "클라이언트 또는 신뢰할 수없는 소스의 입력에 대한 가시 오염의 일부 형태"는 OWASP가 깊이있는 방어 전략의 일부로 권장하는 한 가지 대책입니다.
이 파이썬 모듈은 특수 유형으로 감싸서 신뢰할 수없는 입력을 "테인트"합니다. 이러한 유형은 대부분의 측면에서 기본 파이썬 유형과 마찬가지로 행동하지만 실수로 값을 사용하지 못하게합니다. 이것은 "가시 오염"뿐만 아니라 런타임 보장을 제공하며 (선택적으로) 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 혼합 사용. 스트링 테인트 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 입니다 .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 ())) 신뢰할 수없는 중첩 목록에 대해서는 examples/untrustedIteratorExample.py 신중한 at wented List (예 : untrusted.iterator untrusted.iterator of untrusted.string )에 대한 예제를 참조하십시오.
untrusted.sequencelist 과 같은 객체에 대한보기입니다.untrusted.* 유형untrusted.string 입니다 .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 이지만, untrusted.string unstrusted.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)
untrusted.string 객체를 구성합니다. 여기서 s str 또는 untrusted.string 인스턴스입니다.
untrusted.string 로 구성되는 경우가없는 경우, untrusted.string 인수로 구성된 경우, 새로운 가치는 한 번만 포장됩니다. 탈출하면 untrusted.string 아니라 str 줄 것입니다.
untrusted.string.escape(escape_function, [*args, **kwargs]) -> str
옵션 인수와 키워드 인수로 문자열을 빠져 나가고 반환하는 함수 str -> str escape_function 적용합니다.
untrusted.string.valid(valid_function, [*args, **kwargs]) -> bool
옵션 인수 및 키워드 인수로 문자열을 확인하고 true 또는 false를 반환하는 valid_function , function str -> bool 적용합니다.
untrusted.string.valid(validate_function, [*args, **kwargs]) -> any
옵션 인수 및 키워드 인수를 사용하여 문자열을 확인하고 값 (예 : 문자열이 검증되지 않은 이유 목록)을 반환하는 valid_function , 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-like) 또는 사용자 구성 사용자 정의 유형 인 경우.
대부분의 기본 수집 방법을 지원하지만 반환 유형이 다를 수 있습니다.
각 컬렉션은 해당 값 유형 (기본값이 untrusted.string )을 알고 있습니다.
Mappings는 또한 주요 유형 (기본 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 이므로 완전히 안전하다"는 가치에 대해 생각하는 함정에 빠지지 마십시오.
문자열을 안전하게 탈출 할 수 있다고해서 허용 가능한 입력으로 검증되었음을 의미하지는 않습니다. 예를 들어, 비밀번호에 최소 제한을 가질 수 있습니다. 또는 입력이 예약 된 파일 이름이 아니라고 요구할 수 있습니다.
이 작업을 수행하는 좋은 방법은 부울, untrusted.string.validate 메소드를 반환하는 unstruted.string.valid 메소드를 사용하는 것입니다.이 ValueError 을 반환합니다 (예 : 입력이 valdiate하지 않은 이유의 목록 일 수 있음).
때때로, 당신은 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.