Saya merancang layanan web RESTful yang perlu diakses oleh pengguna, tetapi juga layanan dan aplikasi web lain. Semua permintaan yang masuk perlu diautentikasi. Semua komunikasi berlangsung melalui HTTPS. Otentikasi pengguna akan bekerja berdasarkan token otentikasi, yang diperoleh dengan mem-posting nama pengguna dan kata sandi (melalui koneksi SSL) ke sumber / sesi yang disediakan oleh layanan.
Dalam kasus klien layanan web, tidak ada pengguna akhir di belakang layanan klien. Permintaan dimulai oleh tugas terjadwal, acara atau beberapa operasi komputer lainnya. Daftar layanan penghubung sudah diketahui sebelumnya (jelas, saya kira). Bagaimana cara mengautentikasi permintaan ini yang berasal dari layanan (web) lain? Saya ingin proses otentikasi semudah mungkin diterapkan untuk layanan tersebut, tetapi tidak dengan mengorbankan keamanan. Apa standar dan praktik terbaik untuk skenario seperti ini?
Opsi yang dapat saya pikirkan (atau telah disarankan kepada saya):
Minta layanan klien menggunakan nama pengguna dan sandi "palsu", dan lakukan otentikasi dengan cara yang sama seperti pengguna. Saya tidak suka opsi ini - rasanya tidak benar.
Tetapkan ID aplikasi permanen untuk layanan klien, mungkin juga kunci aplikasi. Sejauh yang saya mengerti, ini sama dengan memiliki nama pengguna + kata sandi. Dengan id dan kunci ini, saya dapat mengautentikasi setiap permintaan, atau membuat token otentikasi untuk mengautentikasi permintaan lebih lanjut. Bagaimanapun, saya tidak suka opsi ini, karena siapa pun yang bisa mendapatkan id dan kunci aplikasi dapat menyamar sebagai klien.
Saya bisa menambahkan pemeriksaan alamat IP ke opsi sebelumnya. Ini akan membuat lebih sulit untuk melakukan permintaan palsu.
Sertifikat klien. Siapkan otoritas sertifikat saya sendiri, buat sertifikat dasar, dan buat sertifikat klien untuk layanan klien. Namun, ada beberapa masalah yang muncul di benak saya: a) bagaimana saya masih mengizinkan pengguna untuk mengautentikasi tanpa sertifikat dan b) seberapa rumit penerapan skenario ini dari sudut pandang layanan klien?
Sesuatu yang lain - pasti ada solusi lain di luar sana?
Layanan saya akan berjalan di Java, tetapi saya sengaja meninggalkan informasi tentang kerangka khusus apa yang akan dibangunnya, karena saya lebih tertarik pada prinsip-prinsip dasar dan tidak begitu banyak pada detail implementasi - Saya berasumsi solusi terbaik untuk ini akan dapat diterapkan terlepas dari kerangka kerja yang mendasarinya. Namun, saya sedikit tidak berpengalaman dengan subjek ini, jadi tips dan contoh konkret tentang implementasi aktual (seperti perpustakaan pihak ketiga yang bermanfaat, artikel, dll.) Akan sangat dihargai.
Jawaban:
Solusi apa pun untuk masalah ini bermuara pada rahasia bersama. Saya juga tidak suka opsi nama pengguna dan kata sandi yang di-hardcode tetapi memiliki keuntungan karena cukup sederhana. Sertifikat klien juga bagus, tetapi apakah jauh berbeda? Ada sertifikat di server dan satu di klien. Keuntungan utamanya adalah lebih sulit untuk melakukan kekerasan. Semoga Anda memiliki perlindungan lain untuk melindunginya.
Saya rasa poin A Anda untuk solusi sertifikat klien tidak sulit untuk diselesaikan. Anda hanya menggunakan cabang.
if (client side certificat) { check it } else { http basic auth }
Saya bukan ahli Java dan saya tidak pernah bekerja dengannya untuk membuat sertifikat sisi klien. Namun Google yang cepat membawa kita ke tutorial ini yang sesuai dengan keinginan Anda.Terlepas dari semua diskusi "apa yang terbaik" ini, izinkan saya menunjukkan bahwa ada filosofi lain yang mengatakan, "lebih sedikit kode, lebih sedikit kecerdasan lebih baik." (Saya pribadi memegang filosofi ini). Solusi sertifikat klien terdengar seperti banyak kode.
Saya tahu Anda mengajukan pertanyaan tentang OAuth, tetapi proposal OAuth2 menyertakan solusi untuk masalah Anda yang disebut " token pembawa " yang harus digunakan bersama dengan SSL. Saya pikir, demi kesederhanaan, saya akan memilih pengguna / pass hard-code (satu per aplikasi sehingga mereka dapat dicabut secara individual) atau token pembawa yang sangat mirip.
sumber
Setelah membaca pertanyaan Anda, saya akan katakan, buat token khusus untuk melakukan permintaan yang diperlukan. Token ini akan hidup dalam waktu tertentu (katakanlah dalam satu hari).
Berikut adalah contoh untuk menghasilkan token otentikasi:
misalnya: 3 Juni 2011
lalu gabungkan dengan kata sandi pengguna, contoh "my4wesomeP4ssword!"
Kemudian lakukan MD5 dari string itu:
Kapan Anda memanggil permintaan, selalu gunakan token ini,
Token ini selalu unik setiap hari, jadi saya rasa perlindungan semacam ini lebih dari cukup untuk selalu melindungi layanan Anda.
Semoga membantu
:)
sumber
Ada beberapa pendekatan berbeda yang dapat Anda lakukan.
Puritan RESTful akan ingin Anda menggunakan otentikasi BASIC, dan mengirim kredensial pada setiap permintaan. Alasan mereka adalah tidak ada yang menyimpan negara bagian mana pun.
Layanan klien dapat menyimpan cookie, yang mempertahankan ID sesi. Secara pribadi saya tidak menganggap ini menyinggung seperti beberapa orang puritan yang saya dengar - bisa jadi mahal untuk mengautentikasi berulang kali. Sepertinya Anda tidak terlalu menyukai ide ini.
Dari uraian Anda, sepertinya Anda benar-benar tertarik dengan OAuth2 Pengalaman saya sejauh ini, dari apa yang saya lihat, adalah agak membingungkan, dan agak berdarah. Ada implementasi di luar sana, tetapi mereka sedikit dan jarang. Di Java, saya memahami bahwa ini telah diintegrasikan ke dalam modul keamanan Spring3 . ( Tutorial mereka ditulis dengan baik.) Saya telah menunggu untuk melihat apakah akan ada perpanjangan di Restlet , tapi sejauh ini, meskipun sudah diusulkan, dan mungkin ada di inkubator, itu masih belum dimasukkan sepenuhnya.
sumber
Saya percaya pendekatannya:
cukup standar, terlepas dari bagaimana Anda menerapkan dan detail teknis spesifik lainnya.
Jika Anda benar-benar ingin mendorong amplop, mungkin Anda dapat menganggap kunci https klien dalam keadaan sementara tidak valid hingga kredensial divalidasi, membatasi informasi jika tidak pernah ada, dan memberikan akses saat divalidasi, berdasarkan lagi pada masa kedaluwarsa.
Semoga ini membantu
sumber
Sejauh pendekatan sertifikat klien berjalan, tidak akan terlalu sulit untuk diterapkan sambil tetap mengizinkan pengguna tanpa sertifikat klien masuk.
Jika Anda ternyata membuat Otoritas Sertifikasi yang ditandatangani sendiri, dan menerbitkan sertifikat klien untuk setiap layanan klien, Anda akan mendapatkan cara mudah untuk mengautentikasi layanan tersebut.
Bergantung pada server web yang Anda gunakan, harus ada metode untuk menentukan otentikasi klien yang akan menerima sertifikat klien, tetapi tidak memerlukannya. Misalnya, di Tomcat saat menentukan konektor https, Anda dapat menyetel 'clientAuth = want', bukan 'true' atau 'false'. Anda kemudian akan memastikan untuk menambahkan sertifikat CA yang ditandatangani sendiri ke truststore Anda (secara default file cacerts di JRE yang Anda gunakan, kecuali Anda menentukan file lain dalam konfigurasi server web Anda), jadi satu-satunya sertifikat tepercaya adalah yang dikeluarkan dari CA yang Anda tandatangani sendiri.
Di sisi server, Anda hanya akan mengizinkan akses ke layanan yang ingin Anda lindungi jika Anda dapat mengambil sertifikat klien dari permintaan (bukan null), dan melewati pemeriksaan DN apa pun jika Anda menginginkan keamanan tambahan. Untuk pengguna tanpa sertifikat klien, mereka masih dapat mengakses layanan Anda, tetapi tidak memiliki sertifikat yang ada dalam permintaan.
Menurut pendapat saya ini adalah cara yang paling 'aman', tetapi tentunya memiliki kurva belajar dan overhead, jadi mungkin belum tentu menjadi solusi terbaik untuk kebutuhan Anda.
sumber
5. Sesuatu yang lain - pasti ada solusi lain di luar sana?
Anda benar, ada! Dan itu disebut JWT (JSON Web Tokens).
JSON Web Token (JWT) adalah standar terbuka (RFC 7519) yang mendefinisikan cara kompak dan mandiri untuk mentransmisikan informasi dengan aman antar pihak sebagai objek JSON. Informasi ini dapat diverifikasi dan dipercaya karena ditandatangani secara digital. JWT dapat ditandatangani menggunakan rahasia (dengan algoritme HMAC) atau pasangan kunci publik / pribadi menggunakan RSA.
Saya sangat merekomendasikan melihat JWT. Mereka adalah solusi yang jauh lebih sederhana untuk masalah jika dibandingkan dengan solusi alternatif.
https://jwt.io/introduction/
sumber
Anda dapat membuat Sesi di server dan berbagi
sessionId
di antara klien dan server dengan setiap panggilan REST.Pertama permintaan ISTIRAHAT mengotentikasi:
/authenticate
. Mengembalikan tanggapan (sesuai format klien Anda) dengansessionId: ABCDXXXXXXXXXXXXXX
;Simpan ini
sessionId
diMap
dengan sesi yang sebenarnya.Map.put(sessionid, session)
atau gunakanSessionListener
untuk membuat dan menghancurkan kunci untuk Anda;Dapatkan sessionid dengan setiap panggilan REST, seperti
URL?jsessionid=ABCDXXXXXXXXXXXXXX
(atau cara lain);HttpSession
dari peta menggunakansessionId
;sumber
Saya akan menggunakan memiliki aplikasi yang mengarahkan pengguna ke situs Anda dengan parameter id aplikasi, setelah pengguna menyetujui permintaan tersebut menghasilkan token unik yang digunakan oleh aplikasi lain untuk otentikasi. Dengan cara ini aplikasi lain tidak menangani kredensial pengguna dan aplikasi lain dapat ditambahkan, dihapus, dan dikelola oleh pengguna. Foursquare dan beberapa situs lain mengotentikasi cara ini dan sangat mudah diterapkan sebagai aplikasi lain.
sumber
Selain otentikasi, saya sarankan Anda memikirkan gambaran besarnya. Pertimbangkan untuk membuat layanan RESTful backend Anda tanpa otentikasi apa pun; kemudian letakkan beberapa otentikasi yang sangat sederhana yang diperlukan layanan lapisan tengah antara pengguna akhir dan layanan backend.
sumber