Saya sudah mencoba untuk mengatasi masalah serupa. Pengguna saya perlu diautentikasi untuk setiap permintaan yang mereka buat. Saya telah fokus untuk mendapatkan pengguna diautentikasi setidaknya sekali oleh aplikasi backend (validasi token JWT), tetapi setelah itu, saya memutuskan saya tidak perlu memerlukan backend lagi.
Saya memilih untuk menghindari memerlukan plugin Nginx yang tidak disertakan secara default. Kalau tidak, Anda dapat memeriksa skrip nginx-jwt atau Lua dan ini mungkin akan menjadi solusi yang bagus.
Mengatasi otentikasi
Sejauh ini saya sudah melakukan yang berikut:
Mendelegasikan otentikasi ke Nginx menggunakan auth_request
. Ini panggilan internal
lokasi yang melewati permintaan ke titik akhir validasi token backend saya. Ini saja tidak membahas masalah penanganan sejumlah besar validasi sama sekali.
Hasil validasi token di-cache menggunakan proxy_cache_key "$cookie_token";
direktif. Setelah validasi token berhasil, backend menambahkan Cache-Control
arahan yang memberitahu Nginx untuk hanya men-cache token hingga 5 menit. Pada titik ini, setiap token autentikasi yang divalidasi ada di cache, permintaan selanjutnya dari pengguna / token yang sama tidak menyentuh backend auth lagi!
Untuk melindungi aplikasi backend saya dari potensi banjir oleh token yang tidak valid, saya juga cache validasi ditolak, ketika endpoint backend saya mengembalikan 401. Yang ini hanya di-cache untuk jangka waktu singkat untuk menghindari kemungkinan mengisi cache Nginx dengan permintaan seperti itu.
Saya telah menambahkan beberapa peningkatan tambahan seperti titik akhir logout yang membatalkan token dengan mengembalikan 401 (yang juga di-cache oleh Nginx) sehingga jika pengguna mengklik logout, token tidak dapat digunakan lagi bahkan jika itu tidak kedaluwarsa.
Juga, cache Nginx saya berisi untuk setiap token, pengguna terkait sebagai objek JSON, yang menyelamatkan saya dari mengambilnya dari DB jika saya memerlukan informasi ini; dan juga menyelamatkan saya dari mendekripsi token.
Tentang token seumur hidup dan menyegarkan token
Setelah 5 menit, token akan kedaluwarsa dalam cache, jadi backend akan ditanyai lagi. Ini untuk memastikan bahwa Anda dapat membatalkan token, karena pengguna logout, karena telah dikompromikan, dan sebagainya. Validasi ulang berkala tersebut, dengan implementasi yang tepat di backend, menghindari saya harus menggunakan token penyegaran.
Token penyegaran secara tradisional akan digunakan untuk meminta token akses baru; mereka akan disimpan di backend Anda dan Anda akan memverifikasi bahwa permintaan untuk token akses dibuat dengan token penyegaran yang cocok dengan yang Anda miliki di database untuk pengguna khusus ini. Jika pengguna keluar, atau token dikompromikan, Anda akan menghapus / membatalkan token penyegaran dalam DB Anda sehingga permintaan berikutnya untuk token baru menggunakan token penyegaran tidak valid akan gagal.
Singkatnya, token penyegaran biasanya memiliki validitas panjang dan selalu diperiksa terhadap backend. Mereka digunakan untuk menghasilkan token akses yang memiliki validitas yang sangat singkat (beberapa menit). Token akses ini biasanya mencapai backend Anda, tetapi Anda hanya memeriksa tanda tangan dan tanggal kedaluwarsanya.
Di sini, di pengaturan saya, kami menggunakan token dengan validitas yang lebih lama (bisa berjam-jam atau sehari), yang memiliki peran dan fitur yang sama seperti token akses dan token refresh. Karena kami memiliki cache validasi dan pembatalannya oleh Nginx, mereka hanya sepenuhnya diverifikasi oleh backend setiap 5 menit sekali. Jadi kami tetap memanfaatkan penggunaan token penyegaran (dapat dengan cepat membatalkan token) tanpa kerumitan tambahan. Dan validasi sederhana tidak pernah mencapai backend Anda yang setidaknya 1 urutan besarnya lebih lambat dari cache Nginx, bahkan jika digunakan hanya untuk memeriksa tanda tangan dan tanggal kadaluwarsa.
Dengan pengaturan ini, saya dapat menonaktifkan otentikasi di backend saya, karena semua permintaan masuk mencapai auth_request
arahan Nginx sebelum menyentuhnya.
Itu tidak sepenuhnya menyelesaikan masalah jika Anda perlu melakukan segala jenis otorisasi per sumber daya, tetapi setidaknya Anda telah menyimpan bagian otorisasi dasar. Dan Anda bahkan dapat menghindari mendekripsi token atau melakukan pencarian DB untuk mengakses data token karena respons autentik yang di-cache Nginx dapat berisi data dan meneruskannya kembali ke backend.
Sekarang, kekhawatiran terbesar saya adalah bahwa saya mungkin melanggar sesuatu yang jelas terkait dengan keamanan tanpa menyadarinya. Yang sedang berkata, setiap token yang diterima masih divalidasi setidaknya sekali sebelum di-cache oleh Nginx. Setiap token yang di-tempered akan berbeda sehingga tidak menekan cache karena kunci cache juga akan berbeda.
Juga, mungkin perlu disebutkan bahwa otentikasi dunia nyata akan berjuang melawan pencurian token dengan menghasilkan (dan memverifikasi) Nonce tambahan atau sesuatu.
Berikut adalah ekstrak disederhanakan dari konfigurasi Nginx saya untuk aplikasi saya:
# 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;
}
}
Sekarang, inilah ekstrak konfigurasi untuk /auth
titik akhir internal , termasuk di atas sebagai /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;
}
.
Mengatasi penyajian konten
Sekarang otentikasi dipisahkan dari data. Karena Anda memberi tahu itu identik untuk setiap pengguna, konten itu sendiri juga bisa di-cache oleh Nginx (dalam contoh saya, di content_cache
zona).
Skalabilitas
Skenario ini berfungsi dengan baik dengan asumsi Anda memiliki satu server Nginx. Dalam skenario dunia nyata Anda mungkin memiliki ketersediaan tinggi, yang berarti beberapa instance Nginx, berpotensi juga menjadi hosting aplikasi backend (Laravel) Anda. Dalam hal itu, permintaan apa pun yang dibuat pengguna Anda dapat dikirim ke server Nginx Anda, dan sampai mereka semua memiliki cache token lokal, mereka akan terus menjangkau backend Anda untuk memverifikasinya. Untuk sejumlah kecil server, menggunakan solusi ini masih akan membawa manfaat besar.
Namun, penting untuk dicatat bahwa dengan beberapa server Nginx (dan karenanya cache) Anda kehilangan kemampuan untuk logout di sisi server karena Anda tidak dapat membersihkan (dengan memaksa penyegaran) cache token pada semua server tersebut, seperti /auth/logout
lakukan dalam contoh saya. Anda hanya tersisa dengan durasi cache token 5 juta yang akan memaksa backend Anda segera ditanyakan, dan akan memberi tahu Nginx bahwa permintaan ditolak. Solusi parsial adalah dengan menghapus token header atau cookie pada klien saat logout.
Setiap komentar akan sangat disambut dan dihargai!