Saya sedang mengembangkan REST API yang membutuhkan otentikasi. Karena otentikasi itu sendiri terjadi melalui layanan web eksternal melalui HTTP, saya beralasan bahwa kami akan mengeluarkan token untuk menghindari panggilan berulang kali ke layanan otentikasi. Yang membawa saya dengan rapi ke pertanyaan pertama saya:
Apakah ini benar-benar lebih baik daripada hanya meminta klien untuk menggunakan HTTP Basic Auth pada setiap permintaan dan panggilan cache ke sisi server layanan otentikasi?
Solusi Basic Auth memiliki keuntungan karena tidak memerlukan perjalanan bolak-balik penuh ke server sebelum permintaan konten dapat dimulai. Token berpotensi dapat lebih fleksibel dalam cakupannya (yaitu hanya memberikan hak untuk sumber daya atau tindakan tertentu), tetapi itu tampaknya lebih sesuai dengan konteks OAuth daripada kasus penggunaan saya yang lebih sederhana.
Saat ini token diperoleh seperti ini:
curl -X POST localhost/token --data "api_key=81169d80...
&verifier=2f5ae51a...
×tamp=1234567
&user=foo
&pass=bar"
Itu api_key
, timestamp
dan verifier
dibutuhkan oleh semua permintaan. The "verifier" dikembalikan oleh:
sha1(timestamp + api_key + shared_secret)
Maksud saya adalah untuk hanya mengizinkan panggilan dari pihak yang dikenal, dan untuk mencegah panggilan digunakan kembali kata demi kata.
Apakah ini cukup bagus? Underkill? Berlebihan?
Dengan token di tangan, klien dapat memperoleh sumber daya:
curl localhost/posts?api_key=81169d80...
&verifier=81169d80...
&token=9fUyas64...
×tamp=1234567
Untuk panggilan yang sesederhana mungkin, ini sepertinya sangat bertele-tele. Mempertimbangkan shared_secret
keinginan untuk menyematkan (minimal) aplikasi iOS, yang saya anggap dapat diekstraksi, apakah ini bahkan menawarkan sesuatu di luar rasa aman yang palsu?
sumber
Jawaban:
Biarkan saya memisahkan semuanya dan menyelesaikan pendekatan setiap masalah secara terpisah:
Autentikasi
Untuk otentikasi, baseauth memiliki keuntungan sebagai solusi yang matang pada tingkat protokol. Ini berarti banyak "mungkin muncul nanti" sudah terpecahkan untuk Anda. Misalnya, dengan BaseAuth, agen pengguna tahu bahwa kata sandi adalah kata sandi sehingga mereka tidak menyimpannya dalam cache.
Beban server auth
Jika Anda memberikan token kepada pengguna alih-alih meng-cache otentikasi di server Anda, Anda masih melakukan hal yang sama: Caching informasi otentikasi. Satu-satunya perbedaan adalah Anda mengalihkan tanggung jawab untuk caching kepada pengguna. Ini sepertinya pekerjaan yang tidak perlu bagi pengguna tanpa keuntungan, jadi saya sarankan untuk menangani ini secara transparan di server Anda seperti yang Anda sarankan.
Keamanan Transmisi
Jika dapat menggunakan koneksi SSL, hanya itu saja, koneksi aman *. Untuk mencegah beberapa eksekusi yang tidak disengaja, Anda dapat memfilter beberapa url atau meminta pengguna untuk menyertakan komponen acak ("nonce") di URL.
Jika itu tidak memungkinkan, dan informasi yang dikirimkan tidak rahasia, saya sarankan untuk mengamankan permintaan dengan hash, seperti yang Anda sarankan dalam pendekatan token. Karena hash memberikan keamanan, Anda dapat menginstruksikan pengguna Anda untuk memberikan hash sebagai kata sandi baseauth. Untuk meningkatkan ketahanan, saya merekomendasikan menggunakan string acak daripada timestamp sebagai "nonce" untuk mencegah serangan replay (dua permintaan yang sah dapat dibuat pada detik yang sama). Alih-alih memberikan bidang "rahasia bersama" dan "kunci api" yang terpisah, Anda cukup menggunakan kunci api sebagai rahasia bersama, lalu menggunakan garam yang tidak berubah untuk mencegah serangan tabel pelangi. Bidang nama pengguna tampaknya juga merupakan tempat yang baik untuk meletakkan nonce, karena ini adalah bagian dari autentikasi. Jadi sekarang Anda memiliki panggilan bersih seperti ini:
Memang benar ini sedikit melelahkan. Ini karena Anda tidak menggunakan solusi tingkat protokol (seperti SSL). Jadi, mungkin ide yang bagus untuk memberikan beberapa jenis SDK kepada pengguna sehingga setidaknya mereka tidak harus melakukannya sendiri. Jika Anda perlu melakukannya dengan cara ini, menurut saya tingkat keamanannya sesuai (just-right-kill).
Amankan penyimpanan rahasia
Itu tergantung siapa yang Anda coba gagalkan. Jika Anda mencegah orang yang memiliki akses ke telepon pengguna untuk menggunakan layanan REST Anda atas nama pengguna, maka akan menjadi ide yang baik untuk menemukan semacam API keyring pada OS target dan meminta SDK (atau pelaksana) menyimpan kunci di sana. Jika itu tidak memungkinkan, Anda setidaknya bisa membuatnya sedikit lebih sulit untuk mendapatkan rahasia dengan mengenkripsinya, dan menyimpan data terenkripsi dan kunci enkripsi di tempat terpisah.
Jika Anda mencoba untuk mencegah vendor perangkat lunak lain mendapatkan kunci API Anda untuk mencegah pengembangan klien alternatif, hanya pendekatan enkripsi-dan-simpan-secara terpisah yang hampir berhasil. Ini adalah crypto kotak putih, dan hingga saat ini, belum ada yang menemukan solusi yang benar-benar aman untuk masalah kelas ini. Paling tidak yang dapat Anda lakukan adalah tetap mengeluarkan satu kunci untuk setiap pengguna sehingga Anda dapat melarang kunci yang disalahgunakan.
(*) EDIT: Koneksi SSL tidak lagi dianggap aman tanpa mengambil langkah tambahan untuk memverifikasinya .
sumber
RESTful API murni harus menggunakan fitur standar protokol yang mendasarinya:
Untuk HTTP, RESTful API harus sesuai dengan header standar HTTP yang ada. Menambahkan header HTTP baru melanggar prinsip REST. Jangan menemukan kembali roda, gunakan semua fitur standar dalam standar HTTP / 1.1 - termasuk kode respons status, tajuk, dan sebagainya. Layanan web RESTFul harus memanfaatkan dan mengandalkan standar HTTP.
Layanan yang tenang HARUS NEGARA. Trik apa pun, seperti autentikasi berbasis token yang mencoba mengingat status permintaan REST sebelumnya di server melanggar prinsip REST. Sekali lagi, ini HARUS; yaitu, jika server web Anda menyimpan informasi terkait konteks permintaan / tanggapan di server dalam upaya untuk membuat sesi apa pun di server, maka layanan web Anda TIDAK Stateless. Dan jika TIDAK stateless, itu BUKAN RESTFul.
Intinya: Untuk tujuan otentikasi / otorisasi, Anda harus menggunakan header otorisasi standar HTTP. Artinya, Anda harus menambahkan header otorisasi / otentikasi HTTP di setiap permintaan berikutnya yang perlu diautentikasi. REST API harus mengikuti standar Skema Otentikasi HTTP. Hal spesifik tentang bagaimana header ini harus diformat didefinisikan dalam standar RFC 2616 HTTP 1.1 - bagian 14.8 Otorisasi RFC 2616, dan dalam RFC 2617 HTTP Authentication: Basic and Digest Access Authentication .
Saya telah mengembangkan layanan RESTful untuk aplikasi Cisco Prime Performance Manager. Cari Google untuk dokumen REST API yang saya tulis untuk aplikasi itu untuk detail lebih lanjut tentang kepatuhan RESTFul API di sini . Dalam implementasi itu, saya telah memilih untuk menggunakan skema Otorisasi "Dasar" HTTP. - periksa versi 1.5 atau lebih tinggi dari dokumen REST API tersebut, dan cari otorisasi di dokumen tersebut.
sumber
Di web, protokol stateful didasarkan pada memiliki token sementara yang dipertukarkan antara browser dan server (melalui header cookie atau penulisan ulang URI) pada setiap permintaan. Token itu biasanya dibuat di ujung server, dan merupakan bagian dari data buram yang memiliki waktu aktif tertentu, dan memiliki tujuan tunggal untuk mengidentifikasi agen pengguna web tertentu. Artinya, token bersifat sementara, dan menjadi NEGARA yang harus dipertahankan server web atas nama agen pengguna klien selama durasi percakapan itu. Oleh karena itu, komunikasi yang menggunakan token dengan cara ini TETAP. Dan jika percakapan antara klien dan server TETAP, itu tidak TENANG.
Nama pengguna / kata sandi (dikirim di header Otorisasi) biasanya disimpan di database dengan maksud untuk mengidentifikasi pengguna. Terkadang pengguna bisa memaksudkan aplikasi lain; namun, nama pengguna / kata sandi TIDAK PERNAH dimaksudkan untuk mengidentifikasi agen pengguna klien web tertentu. Percakapan antara agen web dan server berdasarkan penggunaan nama pengguna / kata sandi di header Otorisasi (mengikuti Otorisasi Dasar HTTP) TIDAK NEGATIF karena front-end server web tidak membuat atau mengelola NEGARA apa pun informasi atas nama agen pengguna klien web tertentu. Dan berdasarkan pemahaman saya tentang REST, protokol menyatakan dengan jelas bahwa percakapan antara klien dan server harus NEGARA. Oleh karena itu, jika kita ingin memiliki layanan RESTful yang sebenarnya, kita harus menggunakan nama pengguna / kata sandi (Lihat RFC yang disebutkan di posting saya sebelumnya) di header Otorisasi untuk setiap panggilan, BUKAN jenis token sension (misalnya token sesi yang dibuat di server web , Token OAuth dibuat di server otorisasi, dan sebagainya).
Saya memahami bahwa beberapa penyedia REST yang disebut menggunakan token seperti token terima OAuth1 atau OAuth2 untuk diteruskan sebagai "Otorisasi: Bearer" di header HTTP. Namun, bagi saya tampaknya menggunakan token tersebut untuk layanan RESTful akan melanggar STATELESS sebenarnya yang berarti bahwa REST mencakup; karena token tersebut adalah bagian data sementara yang dibuat / dikelola di sisi server untuk mengidentifikasi agen pengguna klien web tertentu selama durasi yang valid dari percakapan klien / server web tersebut. Oleh karena itu, layanan apa pun yang menggunakan token OAuth1 / 2 tersebut tidak boleh disebut REST jika kita ingin tetap berpegang pada arti TRUE dari protokol STATELESS.
Rubens
sumber