Opsi auth untuk sistem terdistribusi

9

Saya sedang dalam proses mendesain 3 komponen yang akan bekerja secara simfoni satu sama lain:

  • Sebuah layanan web yang tenang yang membutuhkan BasicAuthlebih dari HTTPS pada semua panggilan, dan yang merupakan apa sebenarnya yang mengangkat semua berat untuk sistem saya (melakukan pekerjaan)
  • UI web yang menerjemahkan tindakan pengguna akhir menjadi panggilan API ke layanan web yang disebutkan di atas; karenanya UI "didukung oleh" WS
  • Alat antarmuka baris perintah (CLI) yang dapat diinstal dan dijalankan oleh pengembang secara lokal, yang juga menerjemahkan perintah ke dalam panggilan API ke WS (karenanya juga "didukung oleh" WS)

Salah satu rintangan pertama yang saya coba lewati adalah sehubungan dengan otentikasi dan otorisasi.

Mari kita berpura-pura bahwa WS menggunakan layanan direktori LDAP (seperti AD atau mungkin Apache DS) sebagai ranah otentikasi. Berarti, ketika panggilan API masuk atas kawat (katakanlah, HTTPS GETuntuk beberapa sumber daya), BasicAuthkredensial diambil dari permintaan, dan diteruskan ke layanan LDAP untuk menentukan apakah ini adalah pengguna yang valid atau tidak. Jika mereka diautentikasi, maka katakanlah bahwa ranah otorisasi yang terpisah, mungkin basis data, digunakan untuk menentukan apakah pengguna yang diidentifikasi dapat melakukan apa yang mereka coba dalam permintaan HTTPS. Sejauh ini bagus.

Dalam hal alat CLI, pengguna harus mengautentikasi sebelum menjalankan perintah apa pun, dan model ini berfungsi dengan baik, karena satu pengguna hanya akan mengoperasikan instance CLI yang sama pada waktu tertentu.

Masalahnya muncul ketika kami mencoba mengintegrasikan aplikasi web (UI) dengan WS, karena banyak orang dapat masuk ke aplikasi pada saat yang sama, semua dengan izin berbeda yang menentukan panggilan API yang mendasari yang mereka boleh buat.

Sejauh yang saya lihat, sepertinya saya hanya memiliki 4 pilihan di sini:

  • Kredensial Tembolok : Setelah masuk ke aplikasi, kredensial entah bagaimana, di suatu tempat di- cache (sedemikian rupa sehingga aplikasi memiliki akses ke sana), dan aplikasi itu tidak memberlakukan segala jenis kebijakan otorisasi itu sendiri. Saat pengguna mencoba melakukan hal-hal yang menghasilkan panggilan API di bawah tenda, kredensial mereka akan dicari dari cache, dan diteruskan dengan panggilan API. Jika WS menentukan bahwa mereka tidak diotorisasi, WS mengirim kembali kesalahan.
  • Akun Tingkat Layanan : Aplikasi dan WS keduanya menggunakan bidang otentikasi / otorisasi yang sama, kecuali UI web sekarang memberlakukan otorisasi pada apa yang sebenarnya dapat dilihat dan dilakukan pengguna di dalam aplikasi. Jika mereka diizinkan untuk melakukan sesuatu yang menghasilkan panggilan API yang mendasarinya, aplikasi mengirimkan kredensial akun layanan (misalnya myapp-admin-user) dengan setiap panggilan API atas nama pengguna.
  • OAuthv2 : Saya tidak tahu apa itu OAuth atau apakah ini berlaku untuk skenario ini, tetapi saya rasa itu bisa menjadi solusi di sini entah bagaimana.
  • Server Token : Gunakan server token seperti CAS atau mungkin Kerberos untuk menjamin pengguna, dengan cara yang sama seperti berperilaku opsi Akun Tingkat Layanan. Di sini, ketika pengguna berhasil masuk ke aplikasi, server token mengirim kembali aplikasi ke UUID sesi, dan juga mendaftarkan UUID itu ke WS. Setiap kali aplikasi menghasilkan panggilan API, ia akan mengaktifkan UUID sesuai permintaan, yang kemudian divalidasi di sisi WS.

Opsi " Cached Credentials " hanya terasa seperti penyimpangan dari segala sesuatu yang baik dan sehat di tanah keamanan. Rasanya salah untuk cache kredensial di mana saja, pernah.

Opsi " Token Server " tampaknya valid untuk pengaturan jenis SSO, tetapi tidak dalam kasus khusus ini dan terasa aneh bagi saya. Saya juga berpikir tidak ada cara yang baik untuk menggunakan konsep dan BasicAuth / HTTPS sesi sesi pada saat yang sama.

Jadi ini meninggalkan OAuthv2, yang tidak saya ketahui, dan " Service-Level Account (SLA) * " sebagai satu-satunya pilihan yang tersisa. Opsi SLA tampaknya OK, tetapi memiliki beberapa kelemahan berikut:

  • Ini membutuhkan akun layanan untuk dasarnya memiliki "hak istimewa dewa" atas WS. Dengan kata lain, setelah aplikasi menganggap pengguna diizinkan untuk mengklik tombol atau melakukan sesuatu di UI, yang diterjemahkan menjadi panggilan API tanpa syarat oleh akun layanan yang digunakan oleh UI. Ini terasa buruk, mkay?
  • Terjadi pada saya bahwa mempertahankan dua set izin (set izin untuk setiap pengguna aplikasi, dan kemudian set izin untuk akun layanan yang digunakan oleh aplikasi terhadap WS) dapat mengakibatkan izin keluar dari selaras satu sama lain entah bagaimana

Jadi sepertinya saya tidak punya pilihan bagus di sini. Tentunya saya tidak bisa menjadi pengembang pertama yang mengalami hal ini, tetapi meminta Google Dewa tidak banyak membantu saya di sini. Ada ide?

smeeb
sumber

Jawaban:

6

Ada banyak alasan untuk tidak menggunakan skema otentikasi dasar untuk melindungi layanan Web API.

Untuk menggunakan layanan ini, klien perlu menyimpan kata sandi di suatu tempat dalam teks yang jelas untuk mengirimkannya bersama dengan setiap permintaan.

Verifikasi kata sandi harus sangat lambat (untuk melawan serangan brute force), yang akan menghambat skalabilitas layanan Anda. Di sisi lain, validasi token keamanan bisa cepat (verifikasi tanda tangan digital).

OAuth2 memang menawarkan solusi untuk setiap kasus penggunaan Anda. Aplikasi web Anda dapat menggunakan kode hibah , yang memberinya token akses yang dapat digunakan untuk berbicara dengan API Anda.

Aplikasi web Anda akan mengarahkan kembali browser pengguna ke server otorisasi. Ini akan meminta pengguna untuk kredensial (atau kartu pintar, atau kode auth dua faktor) dan mengembalikan kode ke browser, yang dapat digunakan klien (aplikasi web Anda) untuk mendapatkan token akses dari server otorisasi.

Aplikasi Anda juga akan mendapatkan kembali token penyegaran yang dengannya ia dapat memperoleh token akses baru jika token saat ini kedaluwarsa.

Aplikasi CLI Anda dapat menggunakan hibah kredensial pemilik sumber daya . Anda akan meminta kredensial pengguna dan mengirimkannya ke server otorisasi untuk mendapatkan akses dan menyegarkan token. Setelah aplikasi CLI Anda memiliki token, Anda dapat membuang kata sandi pengguna dalam memori.

Kedua klien (aplikasi web dan klien baris perintah) harus terdaftar di muka dengan server otorisasi.

Server otorisasi Anda mungkin berbicara dengan layanan direktori LDAP (penyedia identitas atau IdP) untuk melakukan otentikasi yang sebenarnya.

Layanan API web Anda hanya perlu memverifikasi token JWT yang masuk dan menetapkan apa yang boleh dilakukan oleh pengguna (otorisasi).

Jika Anda adalah korban dari serangan man-in-the-middle dan Anda kehilangan token akses Anda, penyerang hanya memiliki waktu terbatas (token seumur hidup) untuk menggunakannya. Kata sandi biasanya berlaku lebih lama. Segarkan token dapat dicabut jika hilang.

MvdD
sumber
Terima kasih atas input solid @ user18044 (+1). Bagaimana dengan klien HTTP lain ke layanan web? Ini adalah layanan web yang tenang, sehingga siapa pun dapat membangun klien untuk itu. Opsi OAuthv2 apa yang akan digunakan untuk mengotentikasi setiap permintaan? Sama seperti aplikasi web (pemberian kode)? Terima kasih lagi!
smeeb
Juga @ user18044 dapatkah Anda mengonfirmasi bahwa OAuthv2 hanya menangani aspek otentikasi dan bukan otorisasi? Jika demikian, bagaimana saya bisa memetakan setiap permintaan (berhasil) terotentikasi ke serangkaian peran / izin yang tersedia untuk klien?
smeeb
1
Bergantung pada bagaimana Anda mempercayai klien ini, mereka diautentikasi secara berbeda. Katakan misalnya bahwa Anda membangun aplikasi seluler untuk API Anda sendiri, Anda dapat menggunakan hibah kredensial pemilik sumber daya. Tetapi jika klien seluler dibuat oleh pihak ke-3 (beberapa aplikasi dari toko aplikasi), Anda akan menggunakan hibah implisit.
MvdD
1
@smeeb OAuth mendefinisikan cakupan untuk menunjukkan apa yang dapat dilakukan klien. Ada sejumlah ruang lingkup yang telah ditentukan, tetapi Anda dapat menetapkan sendiri (misalnya untuk memanggil API tertentu (lihat tools.ietf.org/html/rfc6749#section-3.3 )
MvdD
1
Jangan khawatir, sama-sama. Lingkup benar-benar suatu mekanisme untuk menentukan apa yang bisa dilakukan oleh pihak ketiga di API Anda. Misalnya aplikasi keuangan yang hanya bisa membaca saldo akun Anda di situs bank Anda. Tetapi karena token JWT berisi nama pengguna dan bahkan peran opsional, Anda bisa mencari di database apa yang bisa dilakukan oleh pengguna atau pengguna dalam suatu peran. Itu juga bagaimana perusahaan saya melakukannya.
MvdD
2

Saya sedang mengerjakan sistem yang agak mirip sekarang, sebenarnya; Saya akan berbohong jika saya mengatakan bahwa saya tahu cara "benar" untuk membuat ini berhasil karena saya masih bereksperimen tetapi mungkin meneliti apa yang saya temukan untuk bekerja mungkin bisa membantu. Pengaturan ini cukup banyak terinspirasi oleh OAuth2 meskipun ada kekurangannya , beberapa di antaranya akan saya bahas.

PENOLAKAN: Saya bukan petugas keamanan karena perdagangan, dan apa yang saya bangun saya bangun dengan bantuan Google dan banyak contoh yang bisa saya temukan.

Ketika saya pertama kali mulai meneliti bagaimana saya akan membangun API web yang akan mendukung aplikasi klien, saya memutuskan bahwa saya ingin mencoba dan membuat API sebagai stateless mungkin. Sebagian dari saya tergoda untuk meraih HTTP basic auth dan membuat pengguna mengautentikasi pada setiap permintaan, tetapi dua masalah muncul yang membuat solusi itu tidak tampak berjalan:

  1. Pencarian untuk memvalidasi kredensial adalah biaya waktu non-sepele, karena akan melibatkan setidaknya panggilan basis data dengan setiap permintaan
  2. Sistem ini adalah sistem multi-tenant; mengidentifikasi penyewa mana yang menjadi milik pengguna akan memerlukan parameter ketiga dan yang tidak didukung oleh HTTP auth basic (1)

Kompleksitas yang terlibat dalam otentikasi membuat saya memilih sistem token, di mana pengguna akan membuat permintaan otentikasi ke titik akhir yang akan mengeluarkan kembali token pengenal dan kemudian menyimpan bahwa di suatu tempat server kemudian dapat menggunakannya untuk memvalidasi permintaan dan menghubungkannya dengan beberapa data pengguna yang diperlukan. Ini bukan stateless sempurna, dan saya telah melihat token web JSON sebagai pendekatan alternatif, tetapi pencarian token dapat dibuat sangat cepat. (2)

Klien kemudian bertahan pada token itu sampai server tidak lagi menerima token. Klien kemudian mencoba mengautentikasi ulang dengan server dan mengambil token baru untuk mengautentikasi permintaan di masa mendatang. Inilah yang menjadi referensi posting Anda sebagai strategi kredensial yang di-cache, dan kami memilih untuk menggunakannya karena memungkinkan kami mempertahankan kontrol lebih besar atas akses ke aplikasi. Asalkan klien dapat dipercaya untuk memegang informasi otorisasi sendiri dan hanya menghubungkan melalui koneksi yang aman (kami memaksakan akses HTTPS hanya untuk alasan itu) itu tidak selalu merupakan cara yang buruk untuk menangani sesuatu, jika hanya dari perspektif UX. Untuk layanan web, kami memegang token di penyimpanan lokal browser; karena ini hanya identifikasi sementara dan bukan kombinasi nama pengguna / kata sandi pengguna yang sebenarnya maka kami menganggap ini "

Token kemudian dikirim ke API web sebagai bagian dari header Otorisasi, atau sebagai parameter GET untuk klien di mana tajuk HTTP khusus tidak tersedia. Ini penting karena memungkinkan fleksibilitas yang lebih besar dalam cara kami mengakses API dari berbagai aplikasi klien potensial, seperti halnya Anda perlu mendukung CLI dan aplikasi web. Token pembawa adalah hal yang cukup umum tetapi tidak sepenuhnya sempurna . Masalah keamanan aplikasi kami tidak cukup penting untuk mencurahkan waktu tambahan untuk meningkatkan ini.

Setelah token divalidasi, otorisasi mulai berlaku. Apa yang diperlukan bisa sangat bervariasi, tetapi pada saat itu dalam aplikasi identitas pengguna diketahui dan dengan demikian layanan otorisasi semacam itu hanya perlu diberikan bahwa identitas pengguna dan objek / tindakan untuk diperiksa.

Paling tidak, jika Anda ingin menggunakan strategi semacam ini, ada banyak perpustakaan yang dirancang untuk mengimplementasikan OAuth dan OAuth2 di luar sana; kecuali jika Anda seperti kami dan memiliki beberapa persyaratan yang sangat terbatas, saya sangat merekomendasikan menggunakan perpustakaan keamanan pihak ketiga yang tepercaya karena Anda kemungkinan besar tidak akan memperbaiki keadaan saat pertama kali Anda mencoba. Saya masih mencari-cari alternatif pihak ketiga untuk menggantikan sistem otentikasi kami saat ini karena saya tahu itu penuh dengan lubang dan tepi kasus saya bahkan tidak bisa mulai membayangkan.


Catatan kaki

  1. Ini tidak perlu jika sistem kami dibuat secara berbeda, katakanlah dengan menggunakan titik masuk yang berbeda untuk setiap klien; atau saya juga dianggap pintar dan mengawali nama pengguna dengan pengenal penyewa
  2. Saya sudah memiliki beberapa ide tentang bagaimana membuat token string mudah divalidasi murni komputasi daripada harus melakukan pencarian I / O sebagai target jangka panjang untuk perbaikan; paling tidak token berisi versi byte yang akan memungkinkan untuk upgrade di telepon jika / ketika proses decoding untuk itu berubah
moberemk
sumber