إن ضعف أمان تطبيق الويب الأكثر شيوعًا هو الفشل في التحقق من صحة المدخلات من العميل أو البيئة بشكل صحيح.
OWASP ، التحقق من صحة البيانات (2 يوليو 2017)
يؤدي الفشل في التعامل بشكل صحيح مع الإدخال غير الموثوق إلى ترك تطبيق عرضة لهجمات حقن التعليمات البرمجية ، مثل البرمجة النصية للموقع (XSS). "شكل من أشكال التزحلق المرئي على المدخلات من العميل أو المصادر غير الموثوقة" هو أحد الإجراءات المضادة التي أوصى بها OWASP ، كجزء من استراتيجية للدفاع بعمق.
وحدة Python هذه "taints" مدخلات غير موثوق بها عن طريق لفها في أنواع خاصة. تتصرف هذه الأنواع في معظم النواحي تمامًا مثل أنواع الثعبان الأصلية ، ولكنها تمنعك من استخدام قيمها عن طريق الخطأ. هذا لا يوفر فقط "السحب المرئي" ، ولكن ضمانات وقت التشغيل و (اختياريا) سلامة النوع الثابت مع 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.stringstr ، ولكن لا يمكن الإخراج دون الهروبstr الأصليةstr الأصلي و untrusted.string taints 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مثال:
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 للاطلاع على قائمة متداخلة غير موثوق untrusted.string (على سبيل المثال ، 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.*untrusted.string هذا هو رسم str -غير 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.mappingOf(keyType, valueType) untrusted.sequenceOf(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)
str كائن s untrusted.string untrusted.string
في حالة untrusted.string يتم بناء 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 ، التي تتحقق من السلسلة وإرجاع صحيح أو خطأ ، مع وسيطات اختيارية وطائرات الكلمات الرئيسية.
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 -tuple (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 )
القيمة الأساسية - دائمًا كائن غير لا يتجاوز نوعًا من نوع قيمة المجموعة.
قم بإنشاء نوع Iterator باستخدام 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 ، لذا فهي آمنة تمامًا".
فقط لأنه يمكن الهروب من السلسلة بأمان ، فهذا لا يعني أنه تم التحقق من صحة الإدخال المسموح به. على سبيل المثال ، قد تضع الحد الأدنى على كلمة المرور. أو قد تطلب أن لا يكون الإدخال اسم ملف محجوز.
طرق لطيفة للقيام بذلك ValueError untrusted.string.validate طريقة unstruted.string.valid .
في بعض الأحيان ، تقوم بإنشاء 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.