Memasukkan kata sandi dalam panggilan API REST

31

Misalkan saya memiliki REST API yang juga digunakan untuk mengatur / mengatur ulang kata sandi. Mari kita juga anggap ini berfungsi melalui koneksi HTTPS. Apakah ada alasan bagus untuk tidak meletakkan kata sandi itu di jalur panggilan, katakan juga saya akan menyandikannya di BASE64?

Contohnya adalah mengatur ulang kata sandi seperti ini:

http://www.example.com/user/joe/resetpassword/OLDPASSWD/NEWPASSWD

Saya mengerti BASE64 bukan enkripsi, tapi saya hanya ingin melindungi kata sandi untuk berselancar di bahu dalam kasus ini.

Bart Friederichs
sumber
61
Apakah Anda menyarankan efek samping pada GET? Itu adalah pelanggaran protokol di sana.
Esben Skov Pedersen
27
Ini sebenarnya bukan SISA karena resetpassword/OLDPASSWD/NEWPASSWDbukan sumber daya. Ini doa dari suatu proses. Anda tidak perlu memasukkan semuanya ke dalam URL.
usr
5
@Eben: siapa bilang GET? OP tidak pernah mengatakan itu.
dagnelies
3
Benar, dia tidak dalam pertanyaan itu. Tetapi komentarnya terhadap jawaban Netch mengatakan "Tebak saya harus menggunakan POST setelah semua", jadi kita dapat berasumsi bahwa dia awalnya bermaksud / bertanya tentang GET. Yang, seperti yang ditunjukkan Esben adalah A Bad Thing. DAPATKAN hanya membaca.
Mawg
4
Ini artikel wawasan menjelaskan banyak jebakan mekanisme reset password mungkin bisa membantu memahami kasus ini lebih baik.
9000

Jawaban:

76

Server yang baik mencatat semua permintaan yang dikirim ke sana, termasuk URL (sering, tanpa bagian variabel setelah '?'), IP sumber, waktu eksekusi ... Apakah Anda benar-benar ingin log ini (berpotensi dibaca oleh grup admin yang luas) mengandung info sangat kritis sebagai kata sandi? Base64 bukan penghenti mereka.

Netch
sumber
42
Ini bukan alasan terbesar untuk menggunakan POST. Itu alasan keamanan. Tapi seperti yang sudah dicatat oleh Esben di komentar, mengubah status dengan GET merupakan pelanggaran terhadap layanan Istirahat
semacam itu
2
@BartFriederichs: dan riwayat browser akan mengingat URL. Dan mencoba sekelompok kata sandi secara anonim dengan membuat halaman web yang memiliki tautan untuk semua kata sandi yang ingin Anda coba, dan membiarkan Googlebot melakukan permintaan yang sebenarnya ...
RemcoGerlich
2
"Tapi seperti yang sudah dicatat Esben di komentar, mengubah status dengan GET adalah pelanggaran terhadap layanan Istirahat seperti itu" Aku memperhatikan komentar itu juga, tapi aku tidak melihat di mana ada orang yang mengatakan bahwa ini adalah permintaan GET. Anda dapat menanamkan informasi dalam URI dan masih POST, setelah semua. Ini tidak benar-benar tenang , karena URI sebenarnya tidak menyebutkan sumber daya.
Joshua Taylor
Hai, jawaban yang bagus, tapi saya tidak setuju dengan "tanpa bagian variabel setelah '?'" ... ada banyak yang menyimpan URL lengkap !!!
dagnelies
2
"Mengubah status dengan GET adalah pelanggaran terhadap layanan Istirahat seperti itu" - Jangan terlalu terjebak dalam REST. Mengubah status dengan GET adalah pelanggaran HTTP .
Dan Ellis
69

Apa yang Anda usulkan tidak aman atau tenang.

@Netch telah menyebutkan masalah dengan log, tetapi ada juga masalah lain di mana Anda menunjukkan kata sandi dikirim oleh HTTP, membuatnya sepele untuk menangkap kata sandi dengan segala jenis sniffer kawat atau serangan manusia-di-tengah.

Saat Anda melakukan permintaan GET menggunakan REST, elemen berbeda di URL mewakili elemen berbutir halus. URL Anda berbunyi seperti Anda mengembalikan bagian NEWPASSWD dari OLDPASSWD yang merupakan bagian dari kata sandi reset. Itu tidak masuk akal semantik. GET tidak boleh digunakan untuk menyimpan data.

Anda harus melakukan sesuatu seperti ini:

POST https://www.example.com/user/joe/resetpassword/
{oldpasswd:[data], newpasswd:[data]}

POST karena Anda menulis data, dan https karena Anda tidak ingin mengendusnya.

(Ini benar-benar keamanan bar rendah. Minimum absolut yang harus Anda lakukan.)

Gort the Robot
sumber
2
Bukankah ini berarti mem-hashing kata sandi di sisi klien? Apakah ini direkomendasikan?
Rowan Freeman
1
Catatan: ini tidak akan mengizinkan persyaratan kata sandi (panjang, dll.). Itu mungkin tidak menjadi masalah dalam kasus Anda, meskipun itu adalah praktik keamanan yang sering, dan kadang-kadang diperlukan oleh beberapa entitas.
Paul Draper
8
Anda tidak membuat catatan baru tetapi memperbarui catatan yang ada (biasanya), jadi ini harus PUT daripada POST.
4
Ini tidak terlalu tenang. resetpassword bukan sumber daya apalagi sub-sumber daya. Namun, /user/joe/passwordsedikit lebih baik tetapi tidak optimal.
whirlwin
12
@CamilStaps Tidak, Anda tidak dapat menggunakan PUT, karena PUTidempoten. Tetapi ketika kata sandi telah diubah dari secretmenjadi supersecretberhasil, maka permintaan yang sama akan gagal untuk kedua kalinya, jadi POSTbenar di sini. Tentu saja, seperti yang dikatakan @whirlwin, sumber ini tidak disebutkan namanya.
Residuum
60

Skema yang diusulkan memiliki masalah di beberapa bidang.

Keamanan

Jalur URL sering dicatat; menempatkan kata sandi yang tidak diacuhkan di jalan adalah praktik yang buruk.

HTTP

Informasi otentikasi / otorisasi akan muncul di header Otorisasi. Atau berpotensi, untuk hal-hal berbasis browser, header Cookie.

BERISTIRAHAT

Kata kerja seperti resetpassworddi URL Anda umumnya merupakan tanda yang jelas dari paradigma transfer negara non-representasional. URL harus mewakili sumber daya. Apa artinya GET resetpassword? Atau HAPUS?

API

Skema ini mengharuskan selalu mengetahui kata sandi sebelumnya. Anda mungkin ingin mengizinkan lebih banyak kasus; mis. kata sandi hilang.


Anda bisa menggunakan otentikasi Dasar atau Intisari , yang merupakan skema yang dipahami dengan baik.

PUT /user/joe/password HTTP/1.0
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Content-Type: text/plain
Host: www.example.com

NEWPASSWD

Itu tidak menempatkan informasi ultra-sensitif di jalur, dan mengikuti konvensi HTTP dan REST.

Jika Anda perlu mengizinkan beberapa mode otorisasi lainnya (mis. Beberapa token yang dikirim melalui saluran terverifikasi untuk mereset kata sandi), Anda dapat menggunakan tajuk Otorisasi yang berbeda tanpa harus mengubah apa pun.

Paul Draper
sumber
4

Terlepas dari keamanan, masalah dengan ini adalah bahwa itu bukan pendekatan yang sangat tenang.

OLDPASSWDdan NEWPASSWDtidak mendukung apa pun dalam hierarki sumber daya Anda dan bahkan lebih buruk lagi, operasinya tidak idempoten.

Jadi Anda hanya dapat menggunakan POSTkata kerja Anda, dan Anda tidak harus memasukkan dua kata sandi di jalur sumber daya Anda.

biziclop
sumber
1
Anda tidak membuat catatan baru tetapi memperbarui catatan yang ada (biasanya), jadi ini harus PUT daripada POST.
2
@CamilStaps Jika hanya mengatur kata sandi, bisa jadi itu. Tetapi karena mungkin kata sandi lama perlu diverifikasi juga, itu membuat operasi menjadi non-idempoten, dan dengan demikian PUTdidiskualifikasi sebagai kata kerja. Itu bisa digabung ulang untuk bekerja dengan PUTtetapi dalam bentuk saat ini tidak.
biziclop
OLDPASSWD adalah info otentikasi dan tidak boleh ada di URL sama sekali.
Tidak harus, itu adalah praktik umum untuk secara eksplisit meminta kata sandi lama di atas otentikasi.
biziclop
3

Masalahnya adalah untuk menghindari kata sandi teks biasa dalam permintaan Anda. Ada dua opsi untuk memenuhi persyaratan layanan web yang tenang.

1. hashing sisi klien

  • Saya kira Anda menyimpan kata sandi Anda seperti misalnya hash (kata sandi + garam)
  • Anda dapat memotong kata sandi baru dengan garam di sisi klien
  • Itu berarti: Buat garam baru di sisi klien, buat hash misalnya hash (newPassword + newSalt)
  • Kirim hash baru yang dibuat plus garam ke layanan web Anda yang tenang
  • Kirim kata sandi lama juga sebagai hash (oldPassword + oldSalt)

2. Enkripsi

  • Buat "one time key" (otk) sumber daya untuk pengguna seperti / otk / john
  • Sumber daya ini mengembalikan kunci satu kali unik acak aman, misalnya kbDlJbmNmQ0Y0SmRHZC9GaWtRMW0ycVJpYzhMcVNZTWlMUXN6ZWxLdTZESFRs dan ID unik misalnya 95648915125
  • Layanan web Anda yang tenang harus menyimpan otk acak ini untuk komunikasi aman berikutnya dengan ID 95648915125
  • Enkripsi kata sandi lama dan baru Anda dengan otk mis. AES (untuk alasan keamanan Anda harus menggunakan dua otks terpisah untuk kata sandi lama dan baru)
  • Kirim kata sandi terenkripsi ke sumber daya perubahan kata sandi Anda dengan ID 95648915125
  • Satu kombinasi ID dan otk hanya diperbolehkan bekerja satu kali saja, jadi Anda harus menghapus kombinasi itu setelah memasukkan kata sandi
  • Opsi yang lebih baik: Kirim kata sandi saat ini / lama oleh Basic-Auth.

Catatan: HTTPS diperlukan untuk kedua opsi!

maz258
sumber
1
Mengapa saya harus mengenkripsi ganda (skema enkripsi Anda dengan OTK, dan HTTPS) dengan pertukaran kata sandi? Apa vektor serangan di sini yang tidak dicakup oleh HTTPS?
Bart Friederichs
1
Satu-satunya tujuan adalah untuk menghindari kemungkinan log server. Badan permintaan HTTP (misalnya dengan kata sandi baru plaintext) juga dapat dicatat meskipun HTTPS digunakan. Kemungkinan serangan lain adalah penggunaan sertifikat yang ditandatangani sendiri yang secara khusus digunakan untuk tujuan internal.
maz258
2

Apa saja fitur operasi reset kata sandi?

  1. Itu mengubah sesuatu.
  2. Ada nilai yang diatur.
  3. Hanya beberapa orang yang diizinkan melakukannya (pengguna, admin, atau salah satu, mungkin dengan aturan berbeda tentang bagaimana keduanya dapat melakukannya).

Poin 1 di sini berarti Anda tidak dapat menggunakan GET, Anda harus POST sesuatu yang mewakili operasi penggantian kata sandi ke URI yang mewakili sumber daya yang menangani perubahan kata sandi, atau PUT sesuatu yang mewakili kata sandi baru ke URI yang mewakili kata sandi atau mewakili sesuatu (misalnya pengguna) yang kata sandinya adalah fitur.

Secara umum kami akan POST, paling tidak karena itu bisa menjadi canggung. PUTting sesuatu yang tidak bisa kami dapatkan nanti dan tentu saja kami tidak bisa MENDAPATKAN kata sandi.

Oleh karena itu, poin 2 adalah data yang mewakili kata sandi baru, dalam apa yang POST.

Poin 3 berarti kita harus mengesahkan permintaan, yang berarti bahwa jika pengguna adalah pengguna saat ini, kita akan memerlukan kata sandi saat ini untuk dibuktikan kepada kita (meskipun tidak harus menerima kata sandi saat ini, jika misalnya tantangan berbasis hash digunakan untuk membuktikan pengetahuan tentang itu tanpa mengirimnya).

Karena itu URI harus seperti <http://example.net/changeCurrentUserPassword>atau <http://example.net/users/joe/changePassword>.

Kami mungkin memutuskan bahwa kami ingin menerima kata sandi saat ini dalam data POST serta dalam mekanisme otorisasi umum yang digunakan.

Jon Hanna
sumber