Kelemahan keamanan aplikasi web yang paling umum adalah kegagalan untuk memvalidasi input dengan benar dari klien atau lingkungan.
OWASP, Validasi Data (2 Juli 2017)
Kegagalan untuk menangani input yang tidak dipercayai dengan benar membuat aplikasi rentan terhadap serangan injeksi kode, seperti scripting lintas situs (XSS). "Beberapa bentuk yang terlihat pada input dari klien atau sumber yang tidak dipercaya" adalah salah satu penanggulangan yang direkomendasikan oleh OWASP, sebagai bagian dari strategi pertahanan secara mendalam.
Modul Python ini "mencemari" input yang tidak dipercaya dengan membungkusnya dalam tipe khusus. Jenis -jenis ini berperilaku dalam banyak hal seperti jenis python asli, tetapi mencegah Anda menggunakan nilai -nilai mereka secara tidak sengaja. Ini tidak hanya memberikan "penilaian yang terlihat", tetapi jaminan runtime dan (secara opsional) jenis keamanan yang dapat diverifikasi secara statis dengan mypy.
Strategi untuk membersihkan, melarikan diri, menormalkan, atau memvalidasi input di luar ruang lingkup untuk modul ini.
Modul ini harus cocok untuk penggunaan produksi, dengan peringatan berikut:
untrusted.sequence Tipe Usaha tidak ada tes yang hilang dan mungkin tidak lengkapuntrusted.mapping Jenis Pemancing tidak ada tes yang hilang dan mungkin tidak lengkapunstrusted.<*>Of tidak sepenuhnya diujiKode apa pun dengan pertimbangan keamanan layak mendapatkan standar pengawasan tertinggi. Harap lakukan penilaian Anda sebelum menggunakan modul ini.
Perangkat lunak ini disediakan "sebagaimana adanya", tanpa jaminan apa pun.
Diuji untuk Python> = 3.4, tetapi versi sebelumnya dapat berfungsi.
sudo pip3 install untrusted --upgrade
(Jika Anda hanya menginstal python3, Anda mungkin hanya perlu pip - bukan 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 , tetapi tidak bisa output tanpa melarikan diristr aslistr asli dan untrusted.string Noda str /mempromosikannya ke tipe untrusted.string .Contoh penanganan html yang tidak dipercaya:
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! Lihat untrustedStringExample.py untuk menyusun beberapa fungsi pelarian, lulus argumen untuk melarikan diri dari fungsi, dll.
Modul ini memberikan jenis untuk membungkus koleksi dengan malas dari nilai -nilai yang tidak dipercaya. Nilai -nilai dibungkus dengan tipe untrusted.* Jenis saat diakses.
untrusted.iteratoruntrusted.*untrusted.stringContoh:
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 ())) Lihat examples/untrustedIteratorExample.py untuk daftar bersarang yang tidak terpercaya (misalnya untrusted.iterator untrusted.iterator of untrusted.string ).
untrusted.sequencelist apa pun yang berisi nilai -nilai yang tidak dipercaya.untrusted.*untrusted.stringContoh:
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 atau kunci yang tidak dipercaya untuk nilai -nilai yang tidak dipercaya.untrusted.*str -> untrusted.string , tetapi juga bisa menjadi pemetaan yang untrusted.string unstrusted.stringContoh:
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 )Contoh:
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 ))Wadah bersarang yang malas juga didukung sepenuhnya.
Gunakan untrusted.iteratorOf(valueType) , untrusted.sequenceOf(valueType) untrusted.mappingOf(keyType, valueType) .
Contoh:
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 ))) Mendukung sebagian besar metode str asli, tetapi mungkin memiliki jenis pengembalian yang berbeda.
Nilai yang mendasarinya - selalu merupakan contoh str .
untrusted.string(s)
Membangun objek untrusted.string , di mana s adalah instance non-non-tidak dari str atau untrusted.string .
Dalam kasus untrusted.string String dibangun dengan argumen untrusted.string , nilai baru hanya dibungkus sekali. Melarikan diri dari itu akan memberikan str , bukan untrusted.string .
untrusted.string.escape(escape_function, [*args, **kwargs]) -> str
Menerapkan escape_function , fungsi str -> str yang lolos dari string dan mengembalikannya, dengan argumen opsional dan argumen kata kunci.
untrusted.string.valid(valid_function, [*args, **kwargs]) -> bool
Menerapkan valid_function , fungsi str -> bool , yang memeriksa string dan mengembalikan true atau false, dengan argumen opsional dan argumen kata kunci.
untrusted.string.valid(validate_function, [*args, **kwargs]) -> any
Menerapkan valid_function , fungsi str -> any , yang memeriksa string dan mengembalikan nilai apa pun (misalnya daftar alasan mengapa string tidak divalidasi), dengan argumen opsional dan argumen kata kunci.
untrusted.string / escape_expr Untuk beberapa ekspresi melarikan diri, untrusted.string("value") / escape_expr -> str
escape_expr di sini adalah fungsi str -> str yang lolos dari string, atau 3 -tuple (escape_function, args, kwargs_dict) , misalnya:
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 ) Di mana collection adalah salah satu iterator , sequence (seperti daftar), mapping (seperti dikt), atau jenis kustom yang dibangun pengguna.
Mendukung sebagian besar metode pengumpulan asli, tetapi mungkin memiliki jenis pengembalian yang berbeda.
Setiap koleksi mengetahui tipe nilainya (default untrusted.string ).
Pemetaan juga menyadari jenis kunci mereka ( str default)
Nilai yang mendasari - selalu objek non -non -non yang merupakan instance dari tipe nilai koleksi.
Buat tipe Iterator menggunakan untrusted.iteratorOf(type) .
Buat tipe urutan menggunakan untrusted.sequenceOf(type) .
Buat tipe pemetaan menggunakan untrusted.sequenceOf(keyType, valueType) .
Definisi ini bersifat rekursif.
Misalnya:
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 ) Ingat, hanya karena Anda telah menggunakan satu metode untuk melarikan diri untrusted.string Menyusun ke str , itu mungkin tidak aman dalam konteks lain. Misalnya, apa yang aman untuk HTML mungkin masih berbahaya SQL. Pada saat input pengguna ditangkap, mungkin tidak diketahui terlebih dahulu konteks di mana ia akan digunakan - dan oleh karena itu belum diketahui apa validasi dan strategi yang benar -benar melarikan diri. Yang terbaik adalah menunda melarikan diri sampai titik penggunaan terakhir - menjaga nilai tetap untrusted.* Selama mungkin.
Modul ini bukan solusi ajaib. Ini adalah alat untuk digunakan dengan bijak. Jangan jatuh ke dalam perangkap berpikir tentang nilai "Ini adalah str sekarang jadi benar -benar aman".
Hanya karena sebuah string dapat dilarikan dengan aman, itu tidak berarti bahwa itu telah divalidasi sebagai input yang diijinkan. Misalnya, Anda dapat memberikan batas minimum pada kata sandi. Atau Anda mungkin mensyaratkan bahwa input bukan nama file yang dipesan.
Cara -cara yang bagus untuk melakukan ini adalah dengan menggunakan metode unstruted.string.valid , yang mengembalikan ValueError boolean, untrusted.string.validate dipercaya.
Terkadang, Anda menghasilkan HTML sendiri dan melarikan diri adalah sesuatu yang perlu Anda lakukan.
Terkadang, antarmuka selalu memisahkan parameter dari kode, seperti kebanyakan pustaka SQL modern. Dalam hal ini driver database akan menangani input yang berpotensi tidak terpercaya lebih baik dari yang Anda harapkan, dan melarikan diri adalah hal yang salah untuk dilakukan.
Anda dapat menandai input sebagai tidak dipercaya karena alasan lain - misalnya untuk menegakkan panjang maksimum pada permintaan pencarian, atau karena Anda perlu memvalidasi terhadap logika bisnis.
Jenis koleksi yang tidak percaya, seperti untrusted.sequence , adalah "pandangan" di atas objek yang underling. Jika objek yang mendasari berubah, begitu pula objek yang Anda lihat melalui jenis koleksi yang tidak dipercaya. Dengan kata lain: itu referensi ke objek yang sama, bukan salinan. Jika bukan itu yang Anda inginkan, gunakan modul salin.
Mudah -mudahan ini seharusnya menjadi perilaku yang jelas dan tidak melampaui, sama sekali tidak unik untuk modul ini, tetapi dapat membuat orang tersandung.
Ini adalah perangkat lunak gratis (lisensi 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.