Jawaban di bawah ini terutama berkaitan dengan Cookie yang Ditandatangani , sebuah implementasi konsep sesi (seperti yang digunakan dalam aplikasi web). Flask menawarkan cookie normal (unsigned) (via request.cookies
dan response.set_cookie()
) dan cookie bertanda tangan (viaflask.session
). Jawabannya memiliki dua bagian, yang pertama menjelaskan bagaimana Cookie yang Ditandatangani dibuat, dan yang kedua disajikan dalam bentuk QA yang membahas berbagai aspek skema. Sintaks yang digunakan untuk contoh adalah Python3, tetapi konsepnya juga berlaku untuk versi sebelumnya.
Apa itu SECRET_KEY
(atau bagaimana cara membuat Cookie yang Ditandatangani)?
Menandatangani cookie adalah tindakan pencegahan terhadap gangguan cookie. Selama proses penandatanganan cookie, fileSECRET_KEY
digunakan dengan cara yang mirip dengan bagaimana "garam" akan digunakan untuk mengacaukan sandi sebelum melakukan hashing. Berikut adalah deskripsi konsep yang (sangat) disederhanakan. Kode dalam contoh dimaksudkan sebagai ilustrasi. Banyak langkah telah dihilangkan dan tidak semua fungsi benar-benar ada. Tujuannya di sini adalah untuk memberikan pemahaman tentang gagasan umum, implementasi aktual akan sedikit lebih terlibat. Juga, perlu diingat bahwa Flask melakukan sebagian besar untuk Anda di latar belakang. Jadi, selain menetapkan nilai ke cookie Anda (melalui API sesi) dan menyediakan SECRET_KEY
, tidak hanya tidak disarankan untuk menerapkan ulang ini sendiri, tetapi tidak perlu melakukannya:
Tanda tangan kue pria miskin
Sebelum mengirimkan Tanggapan ke browser:
(1) Pertama a SECRET_KEY
didirikan. Ini seharusnya hanya diketahui oleh aplikasi dan harus dijaga agar relatif konstan selama siklus hidup aplikasi, termasuk melalui restart aplikasi.
# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')
(2) buat cookie
>>> cookie = make_cookie(
... name='_profile',
... content='uid=382|membership=regular',
... ...
... expires='July 1 2030...'
... )
>>> print(cookie)
name: _profile
content: uid=382|membership=regular...
...
...
expires: July 1 2030, 1:20:40 AM UTC
(3) untuk membuat tanda tangan, menambahkan (atau menambahkan) SECRET_KEY
ke string byte cookie, lalu menghasilkan hash dari kombinasi tersebut.
# encode and salt the cookie, then hash the result
>>> cookie_bytes = str(cookie).encode('utf8')
>>> signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
>>> print(signature)
7ae0e9e033b5fa53aa....
(4) Sekarang tambahkan tanda tangan di salah satu ujung content
bidang cookie asli.
# include signature as part of the cookie
>>> cookie.content = cookie.content + '|' + signature
>>> print(cookie)
name: _profile
content: uid=382|membership=regular|7ae0e9... <--- signature
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
dan itulah yang dikirim ke klien.
# add cookie to response
>>> response.set_cookie(cookie)
# send to browser -->
Setelah menerima cookie dari browser:
(5) Saat browser mengembalikan cookie ini kembali ke server, hapus tanda tangan dari bidang cookie content
untuk mendapatkan kembali cookie asli.
# Upon receiving the cookie from browser
>>> cookie = request.get_cookie()
# pop the signature out of the cookie
>>> (cookie.content, popped_signature) = cookie.content.rsplit('|', 1)
(6) Gunakan cookie asli dengan aplikasi SECRET_KEY
untuk menghitung ulang tanda tangan menggunakan metode yang sama seperti pada langkah 3.
# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
(7) Bandingkan hasil yang dihitung dengan tanda tangan yang sebelumnya muncul dari cookie yang baru diterima. Jika cocok, kami tahu bahwa cookie tersebut belum diubah. Namun jika hanya ada spasi yang ditambahkan ke cookie, tanda tangan tidak akan cocok.
# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature
(8) Jika tidak cocok, maka Anda dapat merespons dengan sejumlah tindakan, mencatat acara, membuang cookie, mengeluarkan cookie baru, mengalihkan ke halaman login, dll.
>>> if not good_cookie:
... security_log(cookie)
Kode Otentikasi Pesan (HMAC) berbasis hash
Jenis tanda tangan yang dihasilkan di atas yang memerlukan kunci rahasia untuk memastikan integritas beberapa konten dalam kriptografi disebut Kode Otentikasi Pesan atau MAC .
Saya tentukan sebelumnya bahwa contoh di atas adalah penyederhanaan yang berlebihan dari konsep itu dan itu bukan ide yang baik untuk menerapkan penandatanganan Anda sendiri. Itu karena algoritme yang digunakan untuk menandatangani cookie di Flask disebut HMAC dan sedikit lebih banyak terlibat daripada langkah-demi-langkah sederhana di atas. Ide umumnya sama, tetapi karena alasan di luar cakupan diskusi ini, rangkaian komputasi sedikit lebih kompleks. Jika Anda masih tertarik untuk membuat DIY, seperti biasanya, Python memiliki beberapa modul untuk membantu Anda memulai :) berikut adalah blok awal:
import hmac
import hashlib
def create_signature(secret_key, msg, digestmod=None):
if digestmod is None:
digestmod = hashlib.sha1
mac = hmac.new(secret_key, msg=msg, digestmod=digestmod)
return mac.digest()
Documentaton untuk hmac dan hashlib .
"Demistifikasi" dari SECRET_KEY
:)
Apa yang dimaksud dengan "tanda tangan" dalam konteks ini?
Ini adalah metode untuk memastikan bahwa beberapa konten belum dimodifikasi oleh orang lain selain orang atau entitas yang berwenang untuk melakukannya.
Salah satu bentuk tanda tangan yang paling sederhana adalah " checksum ", yang memverifikasi bahwa dua bagian data adalah sama. Misalnya, saat menginstal perangkat lunak dari sumber, penting untuk terlebih dahulu memastikan bahwa salinan kode sumber Anda identik dengan milik pembuatnya. Pendekatan umum untuk melakukan ini adalah dengan menjalankan sumber melalui fungsi hash kriptografi dan membandingkan keluaran dengan checksum yang dipublikasikan di halaman beranda proyek.
Katakanlah misalnya Anda akan mengunduh sumber proyek dalam file gzip dari cermin web. Checksum SHA1 yang dipublikasikan di halaman web proyek adalah 'eb84e8da7ca23e9f83 ....'
# so you get the code from the mirror
download https://mirror.example-codedump.com/source_code.tar.gz
# you calculate the hash as instructed
sha1(source_code.tar.gz)
> eb84e8da7c....
Kedua hash itu sama, Anda tahu bahwa Anda memiliki salinan yang identik.
Apa itu cookie?
Diskusi ekstensif tentang cookie akan melampaui cakupan pertanyaan ini. Saya memberikan gambaran umum di sini karena pemahaman minimal dapat berguna untuk memiliki pemahaman yang lebih baik tentang bagaimana dan mengapa SECRET_KEY
bermanfaat. Saya sangat menganjurkan Anda untuk menindaklanjuti beberapa bacaan pribadi tentang Cookie HTTP.
Praktik umum dalam aplikasi web adalah menggunakan klien (browser web) sebagai cache ringan. Cookies adalah salah satu implementasi dari praktik ini. Cookie biasanya adalah beberapa data yang ditambahkan oleh server ke respons HTTP melalui headernya. Itu disimpan oleh browser yang kemudian mengirimkannya kembali ke server saat mengeluarkan permintaan, juga melalui header HTTP. Data yang terdapat dalam cookie dapat digunakan untuk meniru apa yang disebut statefulness, ilusi bahwa server mempertahankan sambungan yang sedang berlangsung dengan klien. Hanya, dalam kasus ini, alih-alih kabel untuk menjaga koneksi "hidup", Anda hanya memiliki snapshot dari status aplikasi setelah menangani permintaan klien. Snapshot ini dilakukan bolak-balik antara klien dan server. Setelah menerima permintaan, server terlebih dahulu membaca konten cookie untuk membangun kembali konteks percakapannya dengan klien. Ini kemudian menangani permintaan dalam konteks itu dan sebelum mengembalikan respons ke klien, memperbarui cookie. Ilusi sesi yang sedang berlangsung dipertahankan.
Seperti apa rupa cookie itu?
Cookie tipikal akan terlihat seperti ini:
name: _profile
content: uid=382|status=genie
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
Cookie sangat mudah untuk digunakan dengan teliti dari browser modern manapun. Di Firefox misalnya, buka Preferensi> Privasi> Riwayat> hapus cookie satu per satu .
The content
lapangan adalah yang paling relevan dengan aplikasi. Bidang lain sebagian besar membawa instruksi meta untuk menentukan berbagai cakupan pengaruh.
Mengapa menggunakan cookie sama sekali?
Jawaban singkatnya adalah kinerja. Menggunakan cookie, meminimalkan kebutuhan untuk mencari sesuatu di berbagai penyimpanan data (cache memori, file, database, dll), sehingga mempercepat pekerjaan di sisi aplikasi server. Perlu diingat bahwa semakin besar cookie, semakin berat payload melalui jaringan, jadi apa yang Anda simpan dalam pencarian database di server mungkin akan hilang melalui jaringan. Pertimbangkan dengan cermat apa yang harus disertakan dalam cookie Anda.
Mengapa cookie perlu ditandatangani?
Cookie digunakan untuk menyimpan semua jenis informasi, beberapa di antaranya bisa sangat sensitif. Mereka juga pada dasarnya tidak aman dan memerlukan sejumlah tindakan pencegahan tambahan agar dianggap aman dengan cara apa pun untuk kedua belah pihak, klien dan server. Menandatangani cookie secara khusus menangani masalah yang dapat diotak-atik dalam upaya untuk menipu aplikasi server. Ada langkah-langkah lain untuk mengurangi jenis kerentanan lainnya, saya mendorong Anda untuk membaca lebih lanjut tentang cookie.
Bagaimana cookie dapat dirusak?
Cookie berada di klien dalam bentuk teks dan dapat diedit dengan mudah. Cookie yang diterima oleh aplikasi server Anda mungkin telah dimodifikasi karena sejumlah alasan, beberapa di antaranya mungkin tidak wajar. Bayangkan aplikasi web yang menyimpan informasi izin tentang penggunanya di cookie dan memberikan hak istimewa berdasarkan informasi tersebut. Jika cookie tidak tahan mengutak-atik, siapa pun dapat mengubah status mereka dari "role = visitor" menjadi "role = admin" dan aplikasinya tidak akan lebih bijak.
Mengapa SECRET_KEY
perlu menandatangani cookie?
Memverifikasi cookie sedikit berbeda dari memverifikasi kode sumber seperti yang dijelaskan sebelumnya. Dalam kasus kode sumber, penulis asli adalah wali amanat dan pemilik sidik jari referensi (checksum), yang akan disimpan untuk umum. Yang tidak Anda percayai adalah kode sumbernya, tetapi Anda memercayai tanda tangan publiknya. Jadi untuk memverifikasi salinan sumber Anda, Anda hanya ingin hash terhitung Anda cocok dengan hash publik.
Dalam kasus cookie, namun aplikasi tidak melacak tanda tangannya, ia tetap melacaknya SECRET_KEY
. Itu SECRET_KEY
adalah sidik jari referensi. Cookies bepergian dengan tanda tangan yang mereka klaim sah. Legitimasi di sini berarti bahwa tanda tangan dikeluarkan oleh pemilik cookie, yaitu aplikasinya, dan dalam hal ini, klaim tersebut yang tidak Anda percayai dan Anda perlu memeriksa validitas tanda tangan. Untuk melakukan itu, Anda perlu menyertakan elemen dalam tanda tangan yang hanya diketahui oleh Anda, yaitu SECRET_KEY
. Seseorang dapat mengubah cookie, tetapi karena mereka tidak memiliki bahan rahasia untuk menghitung tanda tangan yang valid dengan benar, mereka tidak dapat memalsukannya. Seperti yang disebutkan sebelumnya, jenis sidik jari ini, di mana di bagian atas checksum juga tersedia kunci rahasia,
Bagaimana dengan Sesi?
Sesi dalam penerapan klasiknya adalah cookie yang hanya membawa ID di content
bidangnya, yaitu session_id
. Tujuan sesi sama persis dengan cookie yang ditandatangani, yaitu untuk mencegah gangguan cookie. Sesi klasik memiliki pendekatan yang berbeda. Setelah menerima cookie sesi, server menggunakan ID untuk mencari data sesi di penyimpanan lokalnya sendiri, yang bisa berupa database, file, atau terkadang cache di memori. Cookie sesi biasanya disetel untuk kedaluwarsa saat browser ditutup. Karena langkah pencarian penyimpanan lokal, implementasi sesi ini biasanya menghasilkan kinerja yang buruk. Cookie yang ditandatangani menjadi alternatif yang disukai dan begitulah cara sesi Flask diimplementasikan. Dengan kata lain, sesi Flask adalahcookie yang ditandatangani, dan untuk menggunakan cookie yang ditandatangani di Flask cukup gunakan Session
API -nya .
Mengapa tidak juga mengenkripsi cookie?
Terkadang konten cookie dapat dienkripsi sebelum ditandatangani . Ini dilakukan jika mereka dianggap terlalu sensitif untuk dilihat dari browser (enkripsi menyembunyikan konten). Namun, cukup menandatangani cookie, memenuhi kebutuhan yang berbeda, di mana ada keinginan untuk mempertahankan tingkat visibilitas dan kegunaan cookie di browser, sambil mencegahnya dicampuri.
Apa yang terjadi jika saya mengubah SECRET_KEY
?
Dengan mengubah SECRET_KEY
Anda membatalkan semua cookie yang ditandatangani dengan kunci sebelumnya. Ketika aplikasi menerima permintaan dengan cookie yang telah ditandatangani dengan sebelumnya SECRET_KEY
, itu akan mencoba menghitung tanda tangan dengan yang baruSECRET_KEY
, dan kedua tanda tangan tidak cocok, cookie ini dan semua datanya akan ditolak, seolah-olah browser menghubungkan ke server untuk pertama kali. Pengguna akan keluar dan cookie lama mereka akan dilupakan, bersama dengan apa pun yang disimpan di dalamnya. Perhatikan bahwa ini berbeda dengan cara menangani cookie yang kedaluwarsa. Cookie yang kedaluwarsa mungkin diperpanjang sewanya jika tanda tangannya sudah diperiksa. Tanda tangan yang tidak valid hanya menunjukkan cookie yang tidak valid.
Jadi, kecuali Anda ingin membatalkan semua cookie yang ditandatangani, cobalah untuk tetap SECRET_KEY
sama untuk waktu yang lama.
Apa yang bagus SECRET_KEY
?
Kunci rahasia harus sulit ditebak. Dokumentasi Sesi memiliki resep bagus untuk pembuatan kunci acak:
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
Anda menyalin kunci dan menempelkannya di file konfigurasi Anda sebagai nilai SECRET_KEY
.
Selain menggunakan kunci yang dibuat secara acak, Anda dapat menggunakan bermacam-macam kata, angka, dan simbol yang rumit, mungkin disusun dalam kalimat yang hanya Anda ketahui, yang dikodekan dalam bentuk byte.
Jangan tidak mengatur SECRET_KEY
secara langsung dengan fungsi yang menghasilkan kunci yang berbeda setiap kali itu disebut. Misalnya, jangan lakukan ini:
# this is not good
SECRET_KEY = random_key_generator()
Setiap kali aplikasi Anda di-restart, itu akan diberikan kunci baru, sehingga membatalkan kunci sebelumnya.
Sebagai gantinya, buka shell python interaktif dan panggil fungsinya untuk menghasilkan kunci, lalu salin dan tempel ke konfigurasi.