5.5 KiB
HTTP Basic Auth
En basit senaryolarda HTTP Basic Auth kullanabilirsiniz.
HTTP Basic Auth’ta uygulama, içinde kullanıcı adı ve şifre bulunan bir header bekler.
Eğer bunu almazsa HTTP 401 "Unauthorized" hatası döndürür.
Ayrıca değeri Basic olan ve isteğe bağlı realm parametresi içerebilen WWW-Authenticate header’ını da döndürür.
Bu da tarayıcıya, kullanıcı adı ve şifre için entegre giriş penceresini göstermesini söyler.
Ardından kullanıcı adı ve şifreyi yazdığınızda tarayıcı bunları otomatik olarak header içinde gönderir.
Basit HTTP Basic Auth
HTTPBasicveHTTPBasicCredentialsimport edin.HTTPBasickullanarak bir "securityscheme" oluşturun.- path operation’ınızda bir dependency ile bu
security’yi kullanın. - Bu,
HTTPBasicCredentialstipinde bir nesne döndürür:- İçinde gönderilen
usernamevepasswordbulunur.
- İçinde gönderilen
{* ../../docs_src/security/tutorial006_an_py39.py hl[4,8,12] *}
URL’yi ilk kez açmaya çalıştığınızda (veya dokümanlardaki "Execute" butonuna tıkladığınızda) tarayıcı sizden kullanıcı adınızı ve şifrenizi ister:
Kullanıcı adını kontrol edin
Daha kapsamlı bir örneğe bakalım.
Kullanıcı adı ve şifrenin doğru olup olmadığını kontrol etmek için bir dependency kullanın.
Bunun için kullanıcı adı ve şifreyi kontrol ederken Python standart modülü olan secrets’i kullanın.
secrets.compare_digest(); bytes ya da yalnızca ASCII karakterleri (İngilizce’deki karakterler) içeren bir str almalıdır. Bu da Sebastián içindeki á gibi karakterlerle çalışmayacağı anlamına gelir.
Bunu yönetmek için önce username ve password değerlerini UTF-8 ile encode ederek bytes’a dönüştürürüz.
Sonra secrets.compare_digest() kullanarak credentials.username’in "stanleyjobson" ve credentials.password’ün "swordfish" olduğundan emin olabiliriz.
{* ../../docs_src/security/tutorial007_an_py39.py hl[1,12:24] *}
Bu, kabaca şuna benzer olurdu:
if not (credentials.username == "stanleyjobson") or not (credentials.password == "swordfish"):
# Return some error
...
Ancak secrets.compare_digest() kullanarak, "timing attacks" denilen bir saldırı türüne karşı güvenli olursunuz.
Timing Attacks
Peki "timing attack" nedir?
Bazı saldırganların kullanıcı adı ve şifreyi tahmin etmeye çalıştığını düşünelim.
Ve johndoe kullanıcı adı ve love123 şifresi ile bir request gönderiyorlar.
Uygulamanızdaki Python kodu o zaman kabaca şuna denk olur:
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
...
Ancak Python, johndoe içindeki ilk j ile stanleyjobson içindeki ilk s’i karşılaştırdığı anda False döndürür; çünkü iki string’in aynı olmadığını zaten anlar ve "kalan harfleri karşılaştırmak için daha fazla hesaplama yapmaya gerek yok" diye düşünür. Uygulamanız da "Incorrect username or password" der.
Sonra saldırganlar bu sefer stanleyjobsox kullanıcı adı ve love123 şifresi ile dener.
Uygulama kodunuz da şuna benzer bir şey yapar:
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
...
Bu kez Python, iki string’in aynı olmadığını fark etmeden önce hem stanleyjobsox hem de stanleyjobson içinde stanleyjobso kısmının tamamını karşılaştırmak zorunda kalır. Bu nedenle "Incorrect username or password" yanıtını vermesi birkaç mikro saniye daha uzun sürer.
Yanıt süresi saldırganlara yardımcı olur
Bu noktada saldırganlar, server’ın "Incorrect username or password" response’unu göndermesinin birkaç mikro saniye daha uzun sürdüğünü fark ederek bir şeyleri doğru yaptıklarını anlar; yani başlangıçtaki bazı harfler doğrudur.
Sonra tekrar denerken, bunun johndoe’dan ziyade stanleyjobsox’a daha yakın bir şey olması gerektiğini bilerek devam edebilirler.
"Profesyonel" bir saldırı
Elbette saldırganlar bunu elle tek tek denemez; bunu yapan bir program yazarlar. Muhtemelen saniyede binlerce ya da milyonlarca test yaparlar ve her seferinde yalnızca bir doğru harf daha elde ederler.
Böylece birkaç dakika ya da birkaç saat içinde doğru kullanıcı adı ve şifreyi, yanıt süresini kullanarak ve uygulamamızın "yardımıyla" tahmin etmiş olurlar.
secrets.compare_digest() ile düzeltin
Ancak bizim kodumuzda secrets.compare_digest() kullanıyoruz.
Kısacası, stanleyjobsox ile stanleyjobson’u karşılaştırmak için geçen süre, johndoe ile stanleyjobson’u karşılaştırmak için geçen süreyle aynı olur. Şifre için de aynı şekilde.
Bu sayede uygulama kodunuzda secrets.compare_digest() kullanarak bu güvenlik saldırıları ailesine karşı güvenli olursunuz.
Hatayı döndürün
Credential’ların hatalı olduğunu tespit ettikten sonra, 401 status code ile (credential verilmediğinde dönenle aynı) bir HTTPException döndürün ve tarayıcının giriş penceresini yeniden göstermesi için WWW-Authenticate header’ını ekleyin:
{* ../../docs_src/security/tutorial007_an_py39.py hl[26:30] *}