A fraqueza mais comum de segurança do aplicativo da Web é a falha em validar adequadamente a entrada do cliente ou do ambiente.
OWASP, Validação de dados (2 de julho de 2017)
A falha em lidar adequadamente com a entrada não confiável deixa um aplicativo vulnerável a ataques de injeção de código, como scripts de sites transversais (XSS). "Alguma forma de contagem visível sobre a entrada do cliente ou fontes não confiáveis" é uma contra -permissão recomendada pela OWASP, como parte de uma estratégia de defesa em profundidade.
Este módulo Python "mancha" a entrada não confiável, envolvendo -as em tipos especiais. Esses tipos se comportam na maioria dos aspectos, assim como os tipos nativos de Python, mas impedem que você use seus valores acidentalmente. Isso fornece não apenas "contas visíveis", mas o tempo de execução garante e (opcionalmente) a segurança do tipo estaticamente verificável com o MyPy.
Estratégias para higienizar, escapar, normalizar ou validar a entrada estão fora de escopo para este módulo.
Este módulo deve ser adequado para o uso da produção, com as seguintes advertências:
untrusted.sequence O tipo de sequência está ausente de testes e pode estar incompletountrusted.mapping O tipo de mapeamento está ausente de testes e pode estar incompletounstrusted.<*>Of Não é totalmente testadoQualquer código com considerações de segurança merece os mais altos padrões de escrutínio. Por favor, exercite seu julgamento antes de usar este módulo.
O software é fornecido "como está", sem garantia de qualquer tipo.
Testado para python> = 3,4, mas versões anteriores podem funcionar.
sudo pip3 install untrusted --upgrade
(Se você tiver apenas o Python3 instalado, pode precisar apenas pip - não 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.stringstr , mas não pode ser produzido sem escaparstr nativosstr nativo e untrusted.string Valores str /promove -os para os tipos untrusted.string .Exemplo de lidar com HTML não confiável:
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! Consulte untrustedStringExample.py para compor várias funções de fuga, aprovando argumentos para funções de escapar, etc.
Este módulo fornece tipos para coleções preguiçosas de valores não confiáveis. Os valores são embrulhados com um tipo untrusted.* Tipo quando acessado.
untrusted.iteratoruntrusted.* Tipountrusted.string é confiável.Exemplo:
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 ())) Consulte examples/untrustedIteratorExample.py para uma lista aninhada não untrusted.iterator (por exemplo, um untrusted.iterator untrusted.string .
untrusted.sequencelist que contenha valores não confiáveis.untrusted.* Tipountrusted.string é confiável.Exemplo:
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 , como teclas confiáveis ou não confiáveis para valores não confiáveis.untrusted.* Tipo.unstrusted.string str de mapeamento -> untrusted.string untrusted.string .Exemplo:
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 )Exemplo:
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 ))Os recipientes preguiçosamente aninhados também são totalmente suportados.
Use untrusted.iteratorOf(valueType) , untrusted.sequenceOf(valueType) untrusted.mappingOf(keyType, valueType) .
Exemplo:
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 ))) Suporta a maioria dos métodos nativos str , mas pode ter diferentes tipos de retorno.
O valor subjacente - sempre uma instância não -None de str .
untrusted.string(s)
Construa um untrusted.string s untrusted.string str
No caso de um untrusted.string untrusted.string Escapá -lo dará um str , não um untrusted.string .
untrusted.string.escape(escape_function, [*args, **kwargs]) -> str
Aplica a escape_function , uma função str -> str que escapa de uma string e a retorna, com argumentos opcionais e argumentos de palavras -chave.
untrusted.string.valid(valid_function, [*args, **kwargs]) -> bool
Aplica o valid_function , uma função str -> bool , que verifica uma string e retorna verdadeiro ou falso, com argumentos opcionais e argumentos de palavras -chave.
untrusted.string.valid(validate_function, [*args, **kwargs]) -> any
Aplica o valid_function , uma função str -> any , que verifique uma string e retorna qualquer valor (por exemplo, uma lista de razões pelas quais uma string não valida), com argumentos opcionais e argumentos de palavras -chave.
untrusted.string / escape_expr Para alguma expressão de fuga, untrusted.string("value") / escape_expr -> str
Um escape_expr aqui é uma função str -> str que escapa de uma string, ou uma tupla de 3 -tuple (escape_function, args, kwargs_dict) , por exemplo:
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 ) Onde collection é de iterator , sequence (semelhante à lista), mapping (tipo dict) ou um tipo personalizado construído pelo usuário.
Suporta a maioria dos métodos de coleta nativa, mas pode ter diferentes tipos de retorno.
Cada coleção está ciente de seu tipo de valor (padrão untrusted.string ).
Os mapeamentos também estão cientes de seu tipo de chave ( str padrão)
O valor subjacente - sempre um objeto que não é uma que é uma instância do tipo de valor da coleção.
Crie um tipo de iterador usando untrusted.iteratorOf(type) .
Crie um tipo de sequência usando untrusted.sequenceOf(type) .
Crie um tipo de mapeamento usando untrusted.sequenceOf(keyType, valueType) .
Essas definições são recursivas.
Por exemplo:
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 ) Lembre str , apenas porque você usou um método para escapar de um untrusted.string . Por exemplo, o que é seguro para o HTML ainda pode ser o SQL perigoso. Na época em que a entrada do usuário é capturada, pode não ser conhecida antecipadamente o contexto em que deve ser usado - e, portanto, ainda não se sabe qual é a validação correta e a estratégia de fuga. É melhor adiar a fuga até o ponto final de uso - mantenha um valor como untrusted.* Pelo maior tempo possível.
Este módulo não é uma solução mágica. É uma ferramenta a ser usada com sabedoria. Não caia na armadilha de pensar em um valor "é um str agora, então é completamente seguro".
Só porque uma string pode ser escapada com segurança, não significa que ela tenha sido validada como entrada permitida. Por exemplo, você pode colocar um limite mínimo em uma senha. Ou você pode precisar que uma entrada não seja um nome de arquivo reservado.
As maneiras agradáveis de fazer isso ValueError usar o untrusted.string.validate unstruted.string.valid .
Às vezes, você gera HTML e escapar é algo que você precisa fazer.
Às vezes, uma interface sempre separa os parâmetros do código, como a maioria das bibliotecas SQL modernas. Nesse caso, o driver do banco de dados lidará melhor com a entrada potencialmente não confiável do que você jamais poderia esperar, e escapar é a coisa errada a fazer.
Você pode marcar a entrada como não confiável por outros motivos - por exemplo, para aplicar um comprimento máximo em uma consulta de pesquisa ou porque precisa validá -la contra a lógica de negócios.
Os tipos de coleta não confiáveis, como untrusted.sequence Sequence, são "visualizações" sobre o objeto Underling. Se o objeto subjacente mudar, o objeto que você vê através do tipo de coleção não confiável. Em outras palavras: é uma referência ao mesmo objeto, não uma cópia. Se não é isso que você deseja, use o módulo de cópia.
Esperamos que isso seja um comportamento óbvio e sem conta, nada exclusivo para este módulo, mas pode atravessar as pessoas.
Este é um software livre (MIT Licença).
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.