Reset kata sandi yang tenang

107

Apa cara yang tepat untuk menyusun sumber daya yang tenang untuk menyetel ulang kata sandi?

Sumber daya ini dimaksudkan untuk menjadi penyetel ulang kata sandi bagi seseorang yang kehilangan atau lupa kata sandinya. Ini membatalkan kata sandi lama mereka dan mengirimi mereka kata sandi lewat email.

Dua opsi yang saya miliki adalah:

POST /reset_password/{user_name}

atau...

POST /reset_password
   -Username passed through request body

Saya cukup yakin permintaannya harus POST. Saya kurang yakin bahwa saya telah memilih nama yang sesuai. Dan saya tidak yakin apakah user_name harus diteruskan melalui URL atau badan permintaan.

Chris Dutrow
sumber

Jawaban:

54

PEMBARUAN: (lebih lanjut untuk komentar di bawah)

Saya akan memilih sesuatu seperti ini:

POST /users/:user_id/reset_password

Anda memiliki kumpulan pengguna, dengan satu pengguna ditentukan oleh {user_name}. Anda kemudian akan menentukan tindakan untuk dioperasikan, yang dalam kasus ini adalah reset_password. Ini seperti mengatakan "Buat ( POST) reset_passwordtindakan baru untuk {user_name}".


Jawaban sebelumnya:

Saya akan memilih sesuatu seperti ini:

PUT /users/:user_id/attributes/password
    -- The "current password" and the "new password" passed through the body

Anda akan memiliki dua koleksi, koleksi pengguna, dan koleksi atribut untuk setiap pengguna. Pengguna ditentukan oleh :user_iddan atribut ditentukan oleh password. The PUToperasi update anggota ditujukan koleksi.

Daniel Vassallo
sumber
10
Saya setuju dengan solusi (POST) Anda yang diperbarui. Permintaan PUT harus idempoten (yaitu permintaan berulang tidak akan mempengaruhi hasil). Ini tidak terjadi pada permintaan POST.
Ross McFarlane
16
Saya akan mengubah reset_password menjadi password_reset
Richard Knop
9
Tunggu teman-teman ... bukankah ini pada dasarnya memungkinkan SIAPA SAJA menyetel ulang sandi seseorang? Seperti, jika ini untuk seseorang yang lupa sandi saat ini, pengguna yang terpengaruh tidak dapat diautentikasi dengan sandi saat ini. Jadi pada dasarnya ini berarti API ini tidak dapat menerima kata sandi sama sekali - sehingga memungkinkan siapa pun untuk menyetel ulang kata sandi seseorang, dan jika API mengembalikannya, bahkan mendapatkan kata sandi pengguna yang dikenal ??? Atau saya melewatkan sesuatu
transient_loop
39
Masalah dengan / user / {id} / password dan sejenisnya adalah Anda mungkin tidak mengetahui "id" pengguna. Anda akan tahu "nama pengguna" atau "email" atau "telepon" mereka, tetapi bukan "id".
coolaj86
17
Kelemahan mendasar dari pendekatan ini adalah asumsi bahwa Anda sudah mengetahui id pengguna. Ini akan benar dalam beberapa keadaan tetapi bagaimana Anda melakukannya maka ketika nama pengguna atau id pengguna tidak diketahui jika pengguna hanya perlu menentukan email untuk reset.
Alappin
94

Pengguna yang tidak diautentikasi

Kami melakukan PUTpermintaan pada api/v1/account/passwordtitik akhir dan memerlukan parameter dengan email akun yang sesuai untuk mengidentifikasi akun yang ingin disetel ulang (memperbarui) sandinya oleh pengguna:

PUT : /api/v1/account/password?email={[email protected]}

Catatan: Seperti yang disebutkan @DougDomeny dalam komentarnya, meneruskan email sebagai string kueri di url adalah risiko keamanan. Parameter GET tidak terekspos saat menggunakan https(dan Anda harus selalu menggunakan httpskoneksi yang tepat untuk permintaan semacam itu) tetapi ada risiko keamanan lain yang terlibat. Anda dapat membaca lebih lanjut tentang topik ini di posting blog ini di sini .

Meneruskan email di badan permintaan akan menjadi alternatif yang lebih aman daripada meneruskannya sebagai parameter GET:

PUT : /api/v1/account/password

Badan permintaan:

{
    "email": "[email protected]"
}

Tanggapan tersebut memiliki arti tanggapan yang 202diterima :

Permintaan telah diterima untuk diproses, tetapi pemrosesan belum selesai. Permintaan tersebut mungkin pada akhirnya atau mungkin tidak akan ditindaklanjuti, karena mungkin akan tidak diizinkan saat pemrosesan benar-benar terjadi. Tidak ada fasilitas untuk mengirim ulang kode status dari operasi asinkron seperti ini.

Pengguna akan menerima email di [email protected]dan memproses permintaan pembaruan bergantung pada tindakan yang diambil dengan tautan dari email tersebut.

https://example.com/password-reset?token=1234567890

Membuka tautan dari email ini akan mengarahkan ke formulir setel ulang kata sandi pada aplikasi ujung depan yang menggunakan token setel ulang kata sandi dari tautan sebagai input untuk bidang input tersembunyi (token adalah bagian dari tautan sebagai string kueri). Bidang masukan lain memungkinkan pengguna menyetel kata sandi baru. Masukan kedua untuk mengonfirmasi kata sandi baru akan digunakan untuk validasi di front-end (untuk mencegah kesalahan ketik).

Catatan: Dalam email kami juga dapat menyebutkan bahwa jika pengguna tidak menginisialisasi pengaturan ulang kata sandi, dia dapat mengabaikan email dan tetap menggunakan aplikasi secara normal dengan kata sandinya saat ini

Ketika formulir dikirimkan dengan kata sandi baru dan token sebagai input proses reset kata sandi akan berlangsung. Data formulir akan dikirim dengan PUTpermintaan lagi tetapi kali ini termasuk token dan kami akan mengganti kata sandi sumber daya dengan nilai baru:

PUT : /api/v1/account/password

Badan permintaan:

{
    "token":"1234567890",
    "new":"password"
}

Tanggapan tersebut akan menjadi tanggapan 204tanpa konten

Server telah memenuhi permintaan tetapi tidak perlu mengembalikan badan-entitas, dan mungkin ingin mengembalikan metainformation yang diperbarui. Respons MUNGKIN menyertakan metainformation baru atau yang diperbarui dalam bentuk header entitas, yang jika ada HARUS dikaitkan dengan varian yang diminta.

Pengguna terotentikasi

Untuk pengguna terotentikasi yang ingin mengubah kata sandi mereka, PUTpermintaan dapat segera dilakukan tanpa email (akun yang kami perbarui kata sandinya diketahui server). Dalam kasus seperti itu, formulir akan mengirimkan dua bidang:

PUT : /api/v1/account/password

Badan permintaan:

{
    "old":"password",
    "new":"password"
}
Melayu
sumber
Di paragraf pertama, Anda mengucapkan PUT tetapi contoh di bawah ini mengatakan HAPUS. Mana yang akurat?
jpierson
Ini mengekspos alamat email di URL, yang akan lebih mengamankan data JSON.
Doug Domeny
@DougDomeny Ya, mengirim email sebagai data json mungkin lebih baik. Saya menambahkan ini ke jawaban sebagai alternatif opsi yang lebih aman, jika tidak solusinya bisa sama.
Wilt
@Wilt: Bukankah ini operasi PATCH? PUT harus mengirimkan sumber daya yang lengkap
j10
1
@jensa Saat menulis ini saya pikir PUT akan lebih baik, tetapi saya tidak ingat persis mengapa. Saya setuju dengan alasan Anda bahwa tambalan mungkin lebih cocok untuk kasus ini.
Layu
18

Mari kita tenang sejenak. Mengapa tidak menggunakan tindakan DELETE untuk kata sandi untuk memicu penyetelan ulang? Masuk akal, bukan? Lagi pula, Anda secara efektif membuang kata sandi yang ada demi kata sandi yang lain.

Itu artinya Anda akan melakukan:

DELETE /users/{user_name}/password

Sekarang, dua peringatan besar:

  1. HTTP DELETE seharusnya idempoten (kata mewah untuk mengatakan "bukan masalah besar jika Anda melakukannya beberapa kali"). Jika Anda melakukan hal-hal standar seperti mengirim email "Atur Ulang Kata Sandi", Anda akan mengalami masalah. Anda dapat mengatasi penandaan pengguna / kata sandi ini dengan boolean "Is Reset". Pada setiap penghapusan, Anda mencentang bendera ini; jika tidak diatur maka Anda dapat mengatur ulang kata sandi dan mengirim email Anda. (Perhatikan bahwa memiliki flag ini mungkin memiliki kegunaan lain juga.)

  2. Anda tidak dapat menggunakan HTTP DELETE melalui formulir , jadi Anda harus melakukan panggilan AJAX dan / atau menyalurkan DELETE melalui POST.

Craig Walker
sumber
9
Ide yang menarik. Namun saya tidak melihat DELETEcocok di sini. Anda akan mengganti kata sandi dengan kata sandi yang dibuat secara acak, saya kira, jadi DELETEbisa menyesatkan. Saya lebih suka Create (POST) new reset_password action, di mana kata benda (sumber daya) Anda akan bertindak adalah "tindakan reset_password". Ini juga cocok untuk mengirim email, karena tindakan tersebut merangkum semua detail tingkat bawah ini. POSTtidak idempoten.
Daniel Vassallo
Saya suka lamarannya. Masalah 1 dapat ditangani dengan menggunakan permintaan bersyarat, yaitu HEAD yang mengirimkan header ETag + DELETE dan If-Match. Jika seseorang mencoba untuk menghapus kata sandi yang tidak lagi aktif, dia akan mendapatkan 412.
whiskeysierra
1
Saya akan menghindari HAPUS. Anda memperbarui, karena entitas / konsep yang sama akan mendapatkan nilai baru. Tapi sebenarnya, biasanya itu tidak terjadi sekarang, tetapi hanya setelah mengirim kata sandi baru dalam permintaan yang berbeda nanti (setelah surat reset kata sandi) - Saat ini tidak ada yang mengirim kata sandi baru melalui surat, tetapi token untuk mengatur ulang dalam permintaan baru dengan token yang diberikan, bukan?
antonio.fornie
11
Bagaimana jika pengguna mengingat kata sandinya setelah membuat permintaan reset? Bagaimana dengan beberapa bot yang mencoba mengatur ulang akun acak? Pengguna harus diizinkan untuk mengabaikan email setel ulang dalam kasus seperti itu (email seharusnya mengatakan demikian), yang berarti sistem Anda tidak boleh menghapus atau memperbarui sandi dengan sendirinya.
Maxime Laval
3
@AximeLaval Itu poin yang sangat bagus. Sungguh, Anda "Membuat Permintaan Reset", yang akan menjadi POST.
Craig Walker
12

Seringkali Anda tidak ingin menghapus atau menghancurkan kata sandi pengguna yang ada pada permintaan awal, karena ini mungkin telah dipicu (secara tidak sengaja atau sengaja) oleh pengguna yang tidak memiliki akses ke email. Sebagai gantinya, perbarui token setel ulang sandi pada catatan pengguna dan kirimkan dalam tautan yang disertakan dalam email. Mengklik tautan akan mengonfirmasi bahwa pengguna menerima token dan ingin memperbarui kata sandi mereka. Idealnya, ini juga sensitif terhadap waktu.

Tindakan RESTful dalam kasus ini akan menjadi POST: memicu tindakan create pada pengontrol PasswordResets. Tindakan itu sendiri akan memperbarui token dan mengirim email.

Tandai Swardstrom
sumber
9

Saya sebenarnya mencari jawaban, bukan bermaksud memberikan jawaban - tetapi "reset_password" terdengar salah bagi saya dalam konteks REST karena ini adalah kata kerja, bukan kata benda. Meskipun Anda mengatakan Anda sedang melakukan kata benda "reset action" - menggunakan justifikasi ini, semua kata kerja adalah kata benda.

Selain itu, mungkin tidak terpikir oleh seseorang yang mencari jawaban yang sama bahwa Anda mungkin bisa mendapatkan nama pengguna melalui konteks keamanan, dan tidak harus mengirimkannya melalui url atau badan sama sekali, yang membuat saya gugup.

orbfish
sumber
4
Mungkin reset-passwordterdengar seperti kata kerja, tetapi Anda dapat dengan mudah membalikkannya ( password-reset) menjadi kata benda. Dan jika Anda telah membuat model aplikasi Anda menggunakan Event Sourcing atau bahkan jika Anda hanya memiliki jenis audit apa pun, masuk akal jika Anda benar-benar memiliki entitas nyata dengan nama ini dan bahkan mungkin mengizinkan GET di atasnya agar pengguna atau administrator dapat melihatnya. sejarah (jelas menutupi teks kata sandi). Tidak membuatku gugup sama sekali. Dan untuk mengambil nama pengguna secara otomatis di sisi server - Anda bisa, tetapi bagaimana Anda menangani hal-hal seperti administrasi / peniruan?
Aaronaught
1
Tidak ada yang salah dalam menggunakan kata kerja di REST. Asalkan digunakan di tempat yang sesuai. Saya pikir ini lebih merupakan pengontrol daripada resorce, dan reset-passwordberhasil menggambarkan efeknya dengan baik.
Anders Östman
6

Saya pikir ide yang lebih baik adalah:

DELETE /api/v1/account/password    - To reset the current password (in case user forget the password)
POST   /api/v1/account/password    - To create new password (if user has reset the password)
PUT    /api/v1/account/{userId}/password    - To update the password (if user knows is old password and new password)

Tentang penyediaan data:

  • Untuk mengatur ulang kata sandi saat ini

    • email harus diberikan dalam badan.
  • Untuk membuat kata sandi baru (setelah reset)

    • kata sandi baru, kode aktivasi dan emailID harus diberikan di badan.
  • Untuk memperbarui kata sandi (untuk pengguna yang masuk)

    • kata sandi lama, kata sandi baru harus disebutkan di badan.
    • UserId dalam Params.
    • Auth Token di header.
kode-kode
sumber
2
Seperti yang dikomentari di jawaban lain, "HAPUS / api / v1 / akun / sandi" adalah ide yang buruk, karena siapa pun dapat menyetel ulang sandi siapa pun.
dimaksimalkan hingga
Kami membutuhkan ID email terdaftar untuk mengatur ulang kata sandi. Peluang untuk mengetahui ID email dari pengguna yang tidak dikenal sangat suram kecuali kita menjalankan situs seperti Facebook dan memiliki banyak ID email yang dikumpulkan melalui cara apa pun. Kemudian kebijakan keamanan akan ditentukan dengan semestinya. Apa saran Anda untuk mengatur ulang kata sandi seseorang?
Codesnooker
5

Ada beberapa pertimbangan yang harus diambil:

Penyetelan ulang kata sandi tidak idempoten

Perubahan kata sandi memengaruhi data yang digunakan sebagai kredensial untuk melakukannya, yang akibatnya dapat membatalkan upaya di masa mendatang jika permintaan hanya diulangi kata demi kata sementara kredensial yang disimpan telah berubah. Misalnya, jika token reset sementara digunakan untuk mengizinkan perubahan, seperti yang biasa terjadi dalam situasi kata sandi yang terlupakan, token itu harus kedaluwarsa setelah perubahan kata sandi berhasil, yang sekali lagi membatalkan upaya lebih lanjut untuk mereplikasi permintaan. Jadi pendekatan RESTful untuk perubahan kata sandi tampaknya menjadi pekerjaan yang lebih cocok untuk POSTdaripada PUT.

ID atau e-mail dalam pemuatan data mungkin berlebihan

Meskipun itu tidak bertentangan dengan REST dan mungkin memiliki beberapa tujuan khusus, seringkali tidak perlu menentukan ID atau alamat email untuk pengaturan ulang kata sandi. Pikirkan tentang itu, mengapa Anda memberikan alamat email sebagai bagian dari data untuk permintaan yang seharusnya melalui otentikasi satu atau lain cara? Jika pengguna hanya mengubah sandi, mereka perlu mengautentikasi untuk melakukannya (melalui nama pengguna: sandi, email: sandi, atau token akses yang disediakan melalui header). Karenanya, kami memiliki akses ke akun mereka dari langkah itu. Jika mereka lupa sandi, mereka akan diberi token reset sementara (melalui email) yang dapat mereka gunakan secara khusus sebagai kredensial untuk melakukan perubahan. Dan dalam kasus ini, otentikasi melalui token seharusnya cukup untuk mengidentifikasi akun mereka.

Mempertimbangkan semua hal di atas, inilah yang saya yakini sebagai skema yang tepat untuk perubahan kata sandi yang tenang:

Method: POST
url: /v1/account/password
Access Token (via headers): pwd_rst_token_b3xSw4hR8nKWE1d4iE2s7JawT8bCMsT1EvUQ94aI
data load: {"password": "This 1s My very New Passw0rd"}
Michael Ekoka
sumber
Pernyataan bahwa placeholder memerlukan informasi out-of-band tidak sepenuhnya benar. Jenis media khusus dapat mendeskripsikan sintaks dan semantik elemen tertentu dari permintaan atau respons. Oleh karena itu, jenis media dapat menentukan bahwa URI yang terdapat dalam bidang tertentu dapat menentukan placeholder untuk data tertentu dan semantik selanjutnya menentukan bahwa email pengguna yang dienkode atau yang tidak harus disertakan sebagai ganti placeholder. Klien dan server yang menghormati jenis media tersebut akan tetap mematuhi prinsip arsitektur RESTful.
Roman Vottner
1
Mengenai POSTvs. PUT RFC 7231 menentukan bahwa pembaruan parsial dapat dicapai melalui data yang tumpang tindih dari dua sumber daya tetapi dipertanyakan jika sesuatu seperti /v1/account/passworditu benar-benar menggantikan sumber daya yang baik. Seperti POSTswiss-army-kniff dari Web yang dapat digunakan jika tidak ada metode lain yang layak, mempertimbangkan PATCHmungkin juga menjadi pilihan untuk menyetel sandi baru.
Roman Vottner
bagaimana dengan URL untuk meminta pengaturan ulang kata sandi ketika mereka tidak tahu kata sandinya?
dan carter
2

Saya tidak akan memiliki sesuatu yang mengubah sandi dan mengirim mereka yang baru jika Anda memutuskan untuk menggunakan metode / users / {id} / password, dan tetap berpegang pada gagasan Anda bahwa permintaan tersebut adalah sumber dayanya sendiri. yaitu / user-password-request / adalah sumber daya, dan menggunakan PUT, info pengguna harus ada di dalam tubuh. Saya tidak akan mengubah kata sandinya, saya akan mengirim email ke pengguna yang berisi link ke halaman yang berisi request_guid, yang dapat diteruskan bersama dengan permintaan ke POST / user / {id} / password /? Request_guid = xxxxx

Itu akan mengubah kata sandi, dan itu tidak memungkinkan seseorang untuk menyela pengguna dengan meminta perubahan kata sandi.

Ditambah PUT awal bisa gagal jika ada permintaan yang belum selesai.

sepeda
sumber
0

Kami Perbarui kata sandi pengguna yang dicatat PUT / v1 / pengguna / kata sandi - identifikasi id pengguna menggunakan AccessToken.

Tidak aman untuk menukar id pengguna. Restful API harus mengidentifikasi pengguna menggunakan AccessToken yang diterima di header HTTP.

Contoh di musim semi-boot

@putMapping(value="/v1/users/password")
public ResponseEntity<String> updatePassword(@RequestHeader(value="Authorization") String token){
/* find User Using token */
/* Update Password*?
/* Return 200 */
}
Dapper Dan
sumber