Die häufigste Schwäche für die Sicherheit von Webanwendungen ist das Versäumnis, die Eingaben aus dem Client oder der Umgebung ordnungsgemäß zu validieren.
OWASP, Datenvalidierung (2. Juli 2017)
Wenn Sie nicht vertrauenswürdige Eingaben ordnungsgemäß behandeln, wird eine Anwendung anfällig für Code -Injektionsangriffe wie Cross -Site -Skripten (XSS). "Eine Form von sichtbaren Zauberspflichten bei Eingaben des Kunden oder nicht vertrauenswürdigen Quellen" ist eine von OWASP empfohlene Gegenmaßnahme als Teil einer Tiefenstrategie.
Dieses Python -Modul "Taints" nicht vertrauenswürdig, indem sie sie in spezielle Typen einwickelt. Diese Typen verhalten sich in den meisten Fällen genauso wie native Python -Typen, verhindern jedoch, dass Sie ihre Werte versehentlich verwenden. Dies liefert nicht nur "sichtbare Verklemmungen", sondern auch Laufzeitgarantien und (optional) statisch überprüfbare Art mit MyPY.
Strategien zur Desinfektion, Flucht, Normalisierung oder Validierung der Eingaben sind für dieses Modul nicht mehr in den Rahmen.
Dieses Modul sollte für den Produktionsgebrauch mit den folgenden Einschränkungen geeignet sein:
untrusted.sequenceuntrusted.mappingunstrusted.<*>Of ist nicht vollständig getestetJeder Code mit Sicherheitsüberlegungen verdient die höchsten Prüfungsstandards. Bitte fangen Sie Ihr Urteilsvermögen vor, bevor Sie dieses Modul verwenden.
Die Software wird "so wie" ohne Garantie jeglicher Art bereitgestellt.
Getestet auf python> = 3,4, aber frühere Versionen können funktionieren.
sudo pip3 install untrusted --upgrade
(Wenn Sie nur Python3 installiert haben, benötigen Sie möglicherweise nur pip - nicht 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 -Typstr -Typ an, kann aber nicht ausgeben, ohne zu entkommenstr -Typenstr Verwendung von nativem str und untrusted.string untrusted.stringBeispiel für den Umgang mit nicht vertrauenswürdigem 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! Siehe untrustedStringExample.py Ablagerung.
Dieses Modul bietet Typen, mit denen Sammlungen nicht vertrauenswürdiger Werte faul wickeln können. Die Werte sind mit einem geeigneten untrusted.* Typ beim Zugriff.
untrusted.iteratoruntrusted.* Typuntrusted.stringBeispiel:
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 examples/untrustedIteratorExample.py untrusted.string untrusted.iterator
untrusted.sequencelist -ähnliches Objekt, das nicht vertrauenswürdige Werte enthält.untrusted.* Typ eingepackt.* Typuntrusted.stringBeispiel:
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 Objektzuordnung, die vertrauenswürdige oder nicht vertrauenswürdige Schlüssel zu nicht vertrauenswürdigen Werten ist.untrusted.* Typ.unstrusted.string Mapping str -> untrusted.string untrusted.string .Beispiel:
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 )Beispiel:
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 ))Auch faul verschachtelte Container werden vollständig unterstützt.
Verwenden Sie untrusted.iteratorOf(valueType) , untrusted.sequenceOf(valueType) untrusted.mappingOf(keyType, valueType) .
Beispiel:
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 ))) Unterstützt die meisten nativen str -Methoden, kann jedoch möglicherweise unterschiedliche Rückgabetypen haben.
Der zugrunde liegende Wert - immer eine Nicht -NONE -Instanz von str .
untrusted.string(s)
Konstruiert ein untrusted.string -Objekt, wobei s eine nicht-none-Instanz von str oder untrusted.string ist.
Bei einem untrusted.string , der mit einem untrusted.string -Argument konstruiert wird, wird der neue Wert nur einmal eingewickelt. Es gibt einen str , der nicht untrusted.string .
untrusted.string.escape(escape_function, [*args, **kwargs]) -> str
Wendet die escape_function an, eine Funktion str -> str , die einer Zeichenfolge entgeht und sie mit optionalen Argumenten und Keyword -Argumenten zurückgibt.
untrusted.string.valid(valid_function, [*args, **kwargs]) -> bool
Wendet die valid_function , eine Funktion str -> bool an, die eine Zeichenfolge überprüft und True oder False mit optionalen Argumenten und Keyword -Argumenten zurückgibt.
untrusted.string.valid(validate_function, [*args, **kwargs]) -> any
Wendet die valid_function , eine Funktion str -> any , die einen String überprüft und einen Wert zurückgibt (z. B. eine Liste von Gründen, warum eine Zeichenfolge nicht bestätigt wurde), mit optionalen Argumenten und Keyword -Argumenten.
untrusted.string / escape_expr Für einen Escape -Expression, untrusted.string("value") / escape_expr -> str
Ein escape_expr hier ist entweder eine Funktion str -> str , die einer Zeichenfolge entgeht, oder ein 3 -Tupel (escape_function, args, kwargs_dict) , zum Beispiel:
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 ) Wobei collection einer iterator , sequence (listenartig), mapping (diktartig) oder einem benutzerkonstruierten benutzerdefinierten Typ gehört.
Unterstützt die meisten nativen Sammlungsmethoden, kann jedoch möglicherweise unterschiedliche Rückgabetypen haben.
Jede Sammlung ist sich ihres Werttyps bewusst (Standard untrusted.string ).
Zuordnungen sind sich auch des Schlüsseltyps bewusst (Standard str )
Der zugrunde liegende Wert - immer ein nicht -nones Objekt, das eine Instanz des Wertes der Sammlung ist.
Erstellen Sie einen Iteratortyp mit untrusted.iteratorOf(type) .
Erstellen Sie einen Sequenztyp mit untrusted.sequenceOf(type) .
Erstellen Sie einen Zuordnungstyp mit untrusted.sequenceOf(keyType, valueType) .
Diese Definitionen sind rekursiv.
Zum Beispiel:
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 ) Denken Sie str , nur weil Sie eine Methode verwendet haben, um einem nicht untrusted.string zu entkommen. Zum Beispiel ist das, was für HTML sicher ist, immer noch gefährlich SQL. Zum Zeitpunkt der Eingabe des Benutzereingangs ist dies möglicherweise nicht im Voraus im Kontext bekannt, in dem er verwendet werden soll - und daher ist es noch nicht bekannt, was die richtige Validierung und Fluchtstrategie ist. Es ist am besten, die Flucht bis zum endgültigen Gebrauchspunkt zu verzögern - einen Wert als untrusted.* So lange wie möglich.
Dieses Modul ist keine magische Lösung. Es ist ein Werkzeug, das mit Bedacht verwendet werden kann. Fallen Sie nicht in die Falle, über einen Wert nachzudenken. "Es ist jetzt ein str , also ist es völlig sicher".
Nur weil eine Saite sicher entkommen kann, bedeutet dies nicht, dass sie als zulässige Eingabe validiert wurde. Beispielsweise können Sie ein Mindestgrenze für ein Passwort einlegen. Oder Sie benötigen möglicherweise, dass ein Eingang kein reservierter Dateiname ist.
Schöne Möglichkeiten, dies zu unstruted.string.valid , besteht darin, ValueError nicht untrusted.string.validate .
Manchmal erzeugen Sie HTML selbst und es ist etwas, was Sie tun müssen.
Manchmal trennt eine Schnittstelle die Parameter immer von Code, wie die meisten modernen SQL -Bibliotheken. In diesem Fall wird der Datenbank -Treiber potenziell nicht vertrauenswürdige Eingaben besser behandeln, als Sie es jemals hoffen könnten, und es ist falsch zu entkommen.
Sie können die Eingabe aus anderen Gründen als nicht vertrauenswürdig markieren - z. B. um eine maximale Länge einer Suchabfrage durchzusetzen, oder weil Sie sie gegen Geschäftslogik validieren müssen.
Nicht vertrauenswürdige Sammlungstypen wie untrusted.sequence Sequenz sind "Ansichten" über das Unterblindobjekt. Wenn sich das zugrunde liegende Objekt ändert, wird auch das Objekt, das Sie durch den nicht vertrauenswürdigen Sammlungstyp sehen. Mit anderen Worten: Es ist ein Verweis auf dasselbe Objekt, nicht auf eine Kopie. Wenn Sie das nicht wollen, verwenden Sie das Kopiermodul.
Dies sollte hoffentlich offensichtlich und unübertroffenes Verhalten sein, überhaupt nicht einzigartig in diesem Modul, aber es kann Menschen aufsetzen.
Dies ist kostenlose Software (MIT -Lizenz).
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.