La faiblesse de la sécurité des applications Web la plus courante est l'échec de valider correctement les entrées du client ou de l'environnement.
OWASP, validation des données (2 juillet 2017)
Le non-traitement correctement géré les entrées non fiables laisse une application vulnérable aux attaques d'injection de code, telles que les scripts du site croisé (XSS). "Une certaine forme de gaignation visible sur la contribution du client ou des sources non fiables" est une contre-mesure recommandée par OWASP, dans le cadre d'une stratégie de défense en profondeur.
Ce module Python "Taints" non mis en fiction en les emballant en types spéciaux. Ces types se comportent à bien des égards comme les types de python natifs, mais vous empêchent d'utiliser leurs valeurs accidentellement. Cela ne fournit pas seulement le "tenion visible", mais les garanties d'exécution et (éventuellement) la sécurité de type statiquement visible avec MyPy.
Les stratégies pour désinfecter, échapper, normaliser ou valider l'entrée sont hors de portée pour ce module.
Ce module doit convenir à une utilisation en production, avec les mises en garde suivantes:
untrusted.sequence Le type de séquence est manquant de tests et peut être incompletuntrusted.mapping Le type de cartographie est manquant de tests et peut être incompletunstrusted.<*>Of n'est pas entièrement testéTout code avec des considérations de sécurité mérite les normes les plus élevées de contrôle. Veuillez exercer votre jugement avant d'utiliser ce module.
Le logiciel est fourni "tel quel", sans garantie d'aucune sorte.
Testé pour Python> = 3,4, mais les versions antérieures peuvent fonctionner.
sudo pip3 install untrusted --upgrade
(Si vous avez uniquement installé Python3, vous n'aurez peut-être besoin que pip - pas 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 , mais ne peut pas être sorti sans s'échapperstr natifsstr native et untrusted.string Taints str Valeurs / Les favorise les types de string untrusted.string .Exemple de gestion du HTML non fiable:
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! Voir untrustedStringExample.py pour composer plusieurs fonctions d'échappement, passer des arguments aux fonctions d'échappement, etc.
Ce module fournit des types pour envelopper paresseusement des collections de valeurs non fiables. Les valeurs sont enveloppées avec un type untrusted.*
untrusted.iteratoruntrusted.* Typeuntrusted.string , mais il peut également être un itérateur sur les collections non fiablesExemple:
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 ())) Voir examples/untrustedIteratorExample.py pour une liste imbriquée non fiable (par exemple, un untrusted.iterator fiction de untrusted.iterator de untrusted.string ).
untrusted.sequencelist contenant des valeurs non fiables.untrusted.* Typeuntrusted.string , mais il peut également être un itérateur sur les collections non fiablesExemple:
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 comme des clés de confiance ou non fiables aux valeurs non fiables.untrusted.* Type.str -> untrusted.string untrusted.string en unstrusted.string .Exemple:
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 )Exemple:
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 ))Les conteneurs imbriqués paresseux sont également entièrement pris en charge.
Utilisez untrusted.iteratorOf(valueType) , untrusted.sequenceOf(valueType) untrusted.mappingOf(keyType, valueType) .
Exemple:
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 ))) Prend en charge la plupart des méthodes str natives, mais peut éventuellement avoir des types de retour différents.
La valeur sous-jacente - Toujours une instance non aucune de str .
untrusted.string(s)
untrusted.string un objet s untrusted.string str
Dans le cas d'un untrusted.string untrusted.string fiction. L'échappant donnera un str , pas un untrusted.string .
untrusted.string.escape(escape_function, [*args, **kwargs]) -> str
Applique l' escape_function , une fonction str -> str qui échappe à une chaîne et la renvoie, avec des arguments facultatifs et des arguments de mots clés.
untrusted.string.valid(valid_function, [*args, **kwargs]) -> bool
Applique le valid_function , une fonction str -> bool , qui vérifie une chaîne et renvoie vrai ou faux, avec des arguments facultatifs et des arguments de mots clés.
untrusted.string.valid(validate_function, [*args, **kwargs]) -> any
Applique le valid_function , une fonction str -> any , qui vérifie une chaîne et renvoie une valeur (par exemple, une liste de raisons pour lesquelles une chaîne n'a pas validé), avec des arguments facultatifs et des arguments de mots clés.
untrusted.string / escape_expr Pour une expression d'évasion, untrusted.string("value") / escape_expr -> str
Une escape_expr ici est soit une fonction str -> str qui échappe à une chaîne, soit un 3-Tuple (escape_function, args, kwargs_dict) , par exemple:
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 ) Où collection est une des iterator , sequence (listes), mapping (de type dict) ou d'un type personnalisé construit par l'utilisateur.
Prend en charge la plupart des méthodes de collecte native, mais peut éventuellement avoir des types de retour différents.
Chaque collection est consciente de son type de valeur (par défaut untrusted.string ).
Les mappages sont également conscients de leur type de clé ( str par défaut)
La valeur sous-jacente - Toujours un objet non non pas qui est une instance du type de valeur de la collection.
Créez un type d'itérateur à l'aide untrusted.iteratorOf(type) .
Créez un type de séquence à l'aide untrusted.sequenceOf(type) .
Créez un type de mappage à l'aide untrusted.sequenceOf(keyType, valueType) .
Ces définitions sont récursives.
Par exemple:
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 ) N'oubliez pas, juste parce que vous avez utilisé une méthode pour échapper à un untrusted.string en un str , il peut ne pas être sûr dans d'autres contextes. Par exemple, ce qui est sûr pour HTML pourrait encore être dangereux SQL. Au moment où la saisie de l'utilisateur est capturée, elle peut ne pas être connue à l'avance le contexte dans lequel il doit être utilisé - et donc on ne sait pas encore quelle est la stratégie de validation et d'échappement correcte. Il est préférable de retarder l'échappement jusqu'au dernier point d'utilisation - gardez une valeur untrusted.* Pour le plus longtemps possible.
Ce module n'est pas une solution magique. C'est un outil à utiliser judicieusement. Ne tombez pas dans le piège de penser à une valeur "C'est un str maintenant, donc c'est complètement sûr".
Ce n'est pas parce qu'une chaîne peut être échappée en toute sécurité, cela ne signifie pas qu'il a été validé comme entrée autorisée. Par exemple, vous pouvez mettre une limite minimale sur un mot de passe. Ou vous pourriez exiger qu'une entrée ne soit pas un nom de fichier réservé.
De belles façons de procéder sont d'utiliser une méthode unstruted.string.valid , qui renvoie une méthode booléenne, untrusted.string.validate , qui renvoie une valeur (par exemple, cela pourrait être une liste de raisons pour lesquelles l'entrée n'a pas valorisé), ou de lancer une ValueError à partir d'une fonction qui s'échappe à la fois et aux validations.
Parfois, vous gérez vous-même HTML et vous échapper est quelque chose que vous devez faire.
Parfois, une interface sépare toujours les paramètres du code, comme la plupart des bibliothèques SQL modernes. Dans ce cas, le pilote de base de données gérera mieux les entrées non fiables que vous ne pourriez espérer, et l'échapper n'est pas la bonne chose à faire.
Vous pouvez marquer l'entrée comme non fiable pour d'autres raisons - par exemple pour appliquer une longueur maximale sur une requête de recherche, ou parce que vous devez la valider contre la logique métier.
Les types de collecte non fiables, comme untrusted.sequence . Si l'objet sous-jacent change, l'objet que vous voyez à travers le type de collection non fiable. En d'autres termes: c'est une référence au même objet, pas une copie. Si ce n'est pas ce que vous voulez, utilisez le module de copie.
Nous espérons que cela devrait être un comportement évident et unpris, pas du tout unique à ce module, mais il peut trébucher les gens.
Il s'agit d'un logiciel gratuit (licence 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.