Benzer bir sorunu çözmeye çalışıyorum. Kullanıcılarımın yaptıkları her istek için kimliğinin doğrulanması gerekiyor. Kullanıcıların arka uç uygulaması (JWT jetonunun doğrulanması) tarafından en az bir kez kimlik doğrulaması yapmaya odaklandım, ancak bundan sonra artık arka uca ihtiyacım olmaması gerektiğine karar verdim.
Varsayılan olarak dahil olmayan herhangi bir Nginx eklentisi gerektirmekten kaçınmayı seçtim. Aksi takdirde nginx-jwt veya Lua komut dosyasını kontrol edebilirsiniz ve bunlar muhtemelen harika çözümler olacaktır.
Kimlik doğrulama adresleme
Şimdiye kadar aşağıdakileri yaptım:
Kullanarak kimlik doğrulamasını Nginx'e devretti auth_request
. Bu internal
, isteği arka uç belirteç doğrulama uç noktama ileten bir konumu çağırır . Bu tek başına, çok sayıda onaylamanın ele alınması sorununu ele almaz.
Belirteç doğrulamasının sonucu bir proxy_cache_key "$cookie_token";
yönerge kullanılarak önbelleğe alınır . Başarılı jeton doğrulaması üzerine, arka uç Cache-Control
Nginx'e jetonu yalnızca 5 dakikaya kadar önbelleğe almasını söyleyen bir yönerge ekler . Bu noktada, bir kez onaylanan herhangi bir doğrulama jetonu önbellektir, aynı kullanıcı / jetondan sonraki istekler artık doğrulama arkasına dokunmaz!
Arka uç uygulamamı geçersiz belirteçlerle potansiyel sellere karşı korumak için, arka uç uç noktam 401 değerini döndürdüğünde reddedilen doğrulamaları da önbelleğe alırım. Bunlar, Nginx önbelleğini bu tür isteklerle doldurmayı önlemek için yalnızca kısa bir süre için önbelleğe alınır.
401 döndürerek (Nginx tarafından da önbelleğe alınır) bir jetonu geçersiz kılan oturum kapatma uç noktası gibi birkaç ek iyileştirme ekledim, böylece kullanıcı oturumu kapatırsa, simge süresi dolmamış olsa bile artık kullanılamaz.
Ayrıca, benim Nginx önbellek her jeton, bir JSON nesnesi olarak ilişkili kullanıcı içerir, bu bilgi gerekiyorsa DB onu getirmekten beni kurtarır; ve ayrıca jetonun şifresini çözmekten de kurtarıyor.
Simge ömrü ve yenileme simgeleri hakkında
5 dakika sonra jetonun önbellekte süresi dolar, bu nedenle arka uç tekrar sorgulanır. Bu, bir simgeyi geçersiz kılabildiğinizden emin olmak içindir, çünkü kullanıcı oturumu kapatır, çünkü güvenliği ihlal edilmiştir vb. Arka uçta doğru uygulama ile bu tür periyodik revalidasyon, yenileme jetonlarını kullanmamı engeller.
Yeni bir erişim belirteci istemek için geleneksel olarak yenileme belirteçleri kullanılır; bunlar arka ucunuzda depolanır ve bu özel kullanıcı için veritabanında bulunana uyan bir yenileme belirteci isteğiyle yapıldığını doğrularsınız. Kullanıcı oturumu kapatırsa veya belirteçler ele geçirilirse, geçersiz kılınmış yenileme belirtecini kullanarak yeni bir belirteç isteğinin başarısız olması için DB'nizdeki yenileme belirtecini siler / geçersiz kılabilirsiniz.
Kısacası, yenileme simgeleri genellikle uzun bir geçerliliğe sahiptir ve her zaman arka uca göre kontrol edilir. Çok kısa geçerliliği olan (birkaç dakika) erişim belirteçleri oluşturmak için kullanılırlar. Bu erişim belirteçleri normalde arka ucunuza ulaşır, ancak yalnızca imza ve son kullanma tarihlerini kontrol edersiniz.
Burada kurulumumda, hem erişim belirteci hem de yenileme belirteciyle aynı role ve özelliklere sahip daha uzun geçerliliğe sahip (saat veya gün olabilir) belirteçler kullanıyoruz. Doğrulama ve geçersiz kılma Nginx tarafından önbelleğe alındığından, arka uç tarafından her 5 dakikada bir tamamen doğrulanır. Bu nedenle, ilave karmaşıklık olmadan yenileme jetonlarını (bir jetonu hızla geçersiz kılabilmek) kullanmanın avantajını koruyoruz. Ve basit doğrulama, yalnızca imza ve son kullanma tarihi kontrolü için kullanılsa bile, Nginx önbelleğinden en az 1 derece daha büyük olan arka ucunuza asla ulaşmaz.
Bu kurulumla, gelen tüm istekler auth_request
dokunmadan önce Nginx yönergesine ulaştığından arka ucumdaki kimlik doğrulamasını devre dışı bırakabilirim .
Kaynak başına yetkilendirme yapmanız gerekiyorsa bu sorunu tam olarak çözmez, ancak en azından temel yetkilendirme bölümünü kaydettiniz. Ayrıca, Nginx önbelleğe alınmış kimlik doğrulaması veri içerebileceğinden ve arka uca geri gönderebileceğinden, belirtecin şifresini çözmeyi önleyebilir veya belirteç verilerine erişmek için DB araması yapabilirsiniz.
Şimdi, en büyük endişem farkında olmadan güvenlikle ilgili bariz bir şeyi kırıyor olabilirim. Bununla birlikte, alınan herhangi bir belirteç, Nginx tarafından önbelleğe alınmadan önce en az bir kez hala doğrulanır. Herhangi bir temperlenmiş simge farklı olacaktır, bu yüzden önbellek anahtarı da farklı olacağından önbelleğe basmaz.
Ayrıca, gerçek bir dünya kimlik doğrulamasının ek bir Nonce veya başka bir şey üreterek (ve doğrulayarak) jeton çalmaya karşı savaşacağından bahsetmeye değer.
İşte benim app için benim Nginx yapılandırma basitleştirilmiş bir özü:
# Cache for internal auth checks
proxy_cache_path /usr/local/var/nginx/cache/auth levels=1:2 keys_zone=auth_cache:10m max_size=128m inactive=10m use_temp_path=off;
# Cache for content
proxy_cache_path /usr/local/var/nginx/cache/resx levels=1:2 keys_zone=content_cache:16m max_size=128m inactive=5m use_temp_path=off;
server {
listen 443 ssl http2;
server_name ........;
include /usr/local/etc/nginx/include-auth-internal.conf;
location /api/v1 {
# Auth magic happens here
auth_request /auth;
auth_request_set $user $upstream_http_X_User_Id;
auth_request_set $customer $upstream_http_X_Customer_Id;
auth_request_set $permissions $upstream_http_X_Permissions;
# The backend app, once Nginx has performed internal auth.
proxy_pass http://127.0.0.1:5000;
proxy_set_header X-User-Id $user;
proxy_set_header X-Customer-Id $customer;
proxy_set_header X-Permissions $permissions;
# Cache content
proxy_cache content_cache;
proxy_cache_key "$request_method-$request_uri";
}
location /api/v1/Logout {
auth_request /auth/logout;
}
}
Şimdi, iç /auth
uç nokta için yukarıda belirtilen yapılandırma özeti şöyledir /usr/local/etc/nginx/include-auth-internal.conf
:
# Called before every request to backend
location = /auth {
internal;
proxy_cache auth_cache;
proxy_cache_methods GET HEAD POST;
proxy_cache_key "$cookie_token";
# Valid tokens cache duration is set by backend returning a properly set Cache-Control header
# Invalid tokens are shortly cached to protect backend but not flood Nginx cache
proxy_cache_valid 401 30s;
# Valid tokens are cached for 5 minutes so we can get the backend to re-validate them from time to time
proxy_cache_valid 200 5m;
proxy_pass http://127.0.0.1:1234/auth/_Internal;
proxy_set_header Host ........;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Accept application/json;
}
# To invalidate a not expired token, use a specific backend endpoint.
# Then we cache the token invalid/401 response itself.
location = /auth/logout {
internal;
proxy_cache auth_cache;
proxy_cache_key "$cookie_token";
# Proper caching duration (> token expire date) set by backend, which will override below default duration
proxy_cache_valid 401 30m;
# A Logout requests forces a cache refresh in order to store a 401 where there was previously a valid authorization
proxy_cache_bypass 1;
# This backend endpoint always returns 401, with a cache header set to the expire date of the token
proxy_pass http://127.0.0.1:1234/auth/_Internal/Logout;
proxy_set_header Host ........;
proxy_pass_request_body off;
}
.
İçerik sunumunu adresleme
Şimdi kimlik doğrulama verilerden ayrılmıştır. Her kullanıcı için aynı olduğunu söylediğiniz için, içeriğin kendisi de Nginx tarafından önbelleğe alınabilir (benim örneğimde, content_cache
bölgede).
Ölçeklenebilirlik
Bu senaryo, bir Nginx sunucunuz olduğunu varsayarak kutudan çıkar çıkmaz çalışır. Gerçek bir dünya senaryosunda muhtemelen yüksek kullanılabilirliğe sahip olursunuz, yani birden fazla Nginx örneği, potansiyel olarak (Laravel) arka uç uygulamanızı da barındırır. Bu durumda, kullanıcılarınızın istediği herhangi bir istek Nginx sunucularınızdan herhangi birine gönderilebilir ve hepsi belirteci yerel olarak önbelleğe alana kadar, doğrulamak için arka ucunuza ulaşmaya devam eder. Az sayıda sunucu için, bu çözümü kullanmak yine de büyük faydalar sağlayacaktır.
Bununla birlikte, birden fazla Nginx sunucusunda (ve böylece önbelleklerde), sunucu tarafında oturum kapatma yeteneğini kaybettiğinizi, çünkü hepsinde token önbelleğini temizleyemediğinizi (bir yenileme zorlayarak) unutmayın. /auth/logout
benim örneğimde. Yalnızca arka ucunuzu yakında sorgulanmaya zorlayacak ve Nginx'e isteğin reddedildiğini söyleyecek olan 5mn jeton önbellek süresi kaldı. Kısmi bir geçici çözüm, oturumu kapatırken istemcideki belirteç başlığını veya çerezini silmektir.
Herhangi bir yorum çok memnuniyetle karşılanacaktır ve takdir edilecektir!