RESTful şifre sıfırlama


107

Parolayı sıfırlamak için bir RESTful kaynağı yapılandırmanın doğru yolu nedir?

Bu kaynak, şifresini kaybeden veya unutan biri için bir şifre sıfırlayıcıdır. Eski şifrelerini geçersiz kılar ve onlara bir şifre e-posta ile gönderir.

Sahip olduğum iki seçenek:

POST /reset_password/{user_name}

veya...

POST /reset_password
   -Username passed through request body

İsteğin bir POST olması gerektiğinden oldukça eminim. Uygun bir isim seçtiğimden daha az eminim. Ve user_name'nin URL'den mi yoksa istek gövdesinden mi geçmesi gerektiğinden emin değilim.

Yanıtlar:


54

GÜNCELLEME: (aşağıda yorum yapmak için daha fazla)

Böyle bir şeye giderdim:

POST /users/:user_id/reset_password

Tek kullanıcının {user_name}. İle belirtildiği bir kullanıcı koleksiyonunuz var . Daha sonra üzerinde işlem yapılacak eylemi belirtirsiniz, bu durumda budur reset_password. "( POST) İçin yeni bir reset_passwordeylem oluştur" demek gibidir {user_name}.


Önceki cevap:

Böyle bir şeye giderdim:

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

Her kullanıcı için iki koleksiyonunuz, bir kullanıcı koleksiyonunuz ve bir öznitelik koleksiyonunuz olur. Kullanıcı ile belirtilir :user_idve öznitelik ile belirtilir password. İşlem PUT, koleksiyonun adresli üyesini günceller.


10
Güncellenmiş (POST) çözümünüze katılıyorum. PUT istekleri idempotent olmalıdır (yani tekrarlanan istekler sonucu etkilememelidir). POST isteklerinde durum böyle değildir.
Ross McFarlane

16
Reset_password'ü password_reset olarak değiştirirdim
Richard Knop

9
Adamları bekleyin ... bu aslında KİMSEYİN birinin şifresini sıfırlamasına izin vermez mi? Sanki bu, geçerli parolayı unutan biri içinse, etkilenen kullanıcının geçerli parolayla kimliği doğrulanamaz. Yani aslında bu, bu API'nin herhangi bir şifreyi kabul edemeyeceği anlamına gelir - böylece herhangi birinin birisinin şifresini sıfırlamasını sağlar ve API bunu döndürürse, bilinen herhangi bir kullanıcının şifresini bile ele geçirir ??? Yoksa bir şey mi kaçırıyorum
transient_loop

39
/ User / {id} / password ve benzerleriyle ilgili sorun, kullanıcının "kimliğini" bilmiyor olmanız olabilir. Onların "kullanıcı adını" veya "e-postasını" veya "telefonunu" bilirsiniz, ancak "kimliği" bilemezsiniz.
coolaj86

17
Bu yaklaşımın temel kusuru, kullanıcı kimliğini zaten bildiğinizi varsaymasıdır. Bu bazı durumlarda doğru olacaktır, ancak kullanıcı yalnızca sıfırlama için bir e-posta belirtmesi gerekiyorsa kullanıcı adı veya kullanıcı kimliği bilinmediğinde bunu nasıl yaparsınız.
Alappin

95

Kimliği doğrulanmamış kullanıcılar

PUTBir api/v1/account/passworduç noktada bir istek yapıyoruz ve kullanıcının parolasını sıfırlamak (güncellemek) istediği hesabı tanımlamak için ilgili hesap e-postasıyla birlikte bir parametreye ihtiyacımız var:

PUT : /api/v1/account/password?email={email@example.com}

Not: As @DougDomeny url sorgu dizesi olarak email geçen yorumunda belirtilen bir güvenlik riski oluşturuyor. GET parametreleri kullanılırken açığa çıkmaz https(ve bu httpstür istekler için her zaman uygun bir bağlantı kullanmalısınız ) ancak ilgili başka güvenlik riskleri vardır. Bu blog yazısında bu konu hakkında daha fazla bilgi edinebilirsiniz .

E-postayı istek gövdesinden geçirmek, onu bir GET parametresi olarak geçirmek yerine daha güvenli bir alternatif olacaktır:

PUT : /api/v1/account/password

Gövde isteği:

{
    "email": "email@example.com"
}

Yanıtın 202kabul edilen bir yanıtı vardır :

İstek işlenmek üzere kabul edildi, ancak işlem tamamlanmadı. İşleme fiilen gerçekleştiğinde izin verilmeyebileceğinden, talep sonunda yerine getirilebilir veya uygulanmayabilir. Bunun gibi bir zaman uyumsuz işlemden bir durum kodunu yeniden gönderme olanağı yoktur.

Kullanıcı, adresine bir e-posta alacak email@example.comve güncelleme isteğinin işlenmesi, e-postadaki bağlantıyla gerçekleştirilen işlemlere bağlı olarak değişecektir.

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

Bağlantının bu e-postadan açılması, bağlantıdan şifre sıfırlama jetonunu gizli bir giriş alanı için giriş olarak kullanan ön uç uygulamasında bir şifre sıfırlama formuna yönlendirecektir (jeton, bağlantının bir sorgu dizesi olarak bir parçasıdır). Başka bir giriş alanı, kullanıcının yeni bir şifre belirlemesine izin verir. Yeni parolayı onaylamak için ikinci bir giriş, ön uçta doğrulama için kullanılacaktır (yazım hatalarını önlemek için).

Not: E-postada, kullanıcının herhangi bir şifre sıfırlama işlemini başlatmaması durumunda, e-postayı göz ardı edip mevcut şifresiyle uygulamayı normal şekilde kullanmaya devam edebileceğini de belirtebiliriz.

Form yeni şifre ve giriş olarak belirteç ile birlikte gönderildiğinde, şifre sıfırlama işlemi gerçekleşir. Form verileri PUTtekrar bir istekle gönderilecek, ancak bu sefer jeton dahil olacak ve kaynak şifresini yeni bir değerle değiştireceğiz:

PUT : /api/v1/account/password

Gövde isteği:

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

Yanıtı olacak 204hiçbir içerik yanıtı

Sunucu isteği yerine getirdi, ancak bir varlık gövdesi döndürmesi gerekmiyor ve güncellenmiş meta bilgileri döndürmek isteyebilir. Yanıt, mevcutsa istenen varyantla ilişkilendirilmesi GEREKEN, varlık başlıkları biçiminde yeni veya güncellenmiş meta bilgileri İÇEREBİLİR.

Kimliği doğrulanmış kullanıcılar

Parolalarını değiştirmek isteyen kimliği doğrulanmış kullanıcılar için, PUTistek e-posta olmadan hemen gerçekleştirilebilir (parolasını güncellediğimiz hesap sunucu tarafından bilinir). Böyle bir durumda form iki alan gönderecektir:

PUT : /api/v1/account/password

Gövde isteği:

{
    "old":"password",
    "new":"password"
}

İlk paragrafınızda PUT diyorsunuz ancak aşağıdaki örnek DELETE diyor. Hangisi doğru?
jpierson

Bu, bir JSON verisinin daha güvenli olacağı URL'deki e-posta adresini ortaya çıkarır.
Doug Domeny

@DougDomeny Evet, e-postayı json verisi olarak göndermek muhtemelen daha iyi olacaktır. Bunu yanıta alternatif daha güvenli bir seçenek olarak ekledim, aksi takdirde çözüm aynı olabilir.
Wilt

@Wilt: Bu bir PATCH işlemi olmaz mı? PUT, kaynağın tamamını göndermeyi gerektirir
j10

1
@jitenshah İyi nokta. Bunu yazarken PUT'un daha iyi olacağını düşündüm ama tam olarak nedenini hatırlamıyorum. Bu yamanın bu dava için daha uygun olabileceği gerekçenize katılıyorum.
Wilt

18

Bir saniyeliğine uber-RESTful alalım. Sıfırlamayı tetiklemek için parolanın SİL eylemini neden kullanmıyorsunuz? Mantıklı, değil mi? Sonuçta, mevcut şifreyi başka bir şifre lehine etkili bir şekilde atıyorsunuz.

Bu, yapacağınız anlamına gelir:

DELETE /users/{user_name}/password

Şimdi, iki büyük uyarı:

  1. HTTP DELETE'in idempotent olduğu varsayılır ("birden çok kez yaparsanız önemli değil" demek için süslü bir kelime). Bir "Şifre Sıfırlama" e-postası göndermek gibi standart şeyler yapıyorsanız, o zaman sorunlarla karşılaşacaksınız. Kullanıcıyı / parolayı bir boolean "Is Reset" bayrağıyla etiketleyerek bu sorunu çözebilirsiniz. Her silme işleminde bu bayrağı kontrol edersiniz; o set değilse o zaman şifreyi sıfırlamak ve e-posta gönderebilirsiniz. (Bu bayrağa sahip olmanın başka kullanımları da olabileceğini unutmayın.)

  2. HTTP DELETE'i bir form aracılığıyla kullanamazsınız , bu nedenle bir AJAX çağrısı yapmanız ve / veya DELETE'i POST aracılığıyla tünellemeniz gerekir.


9
İlginç fikir. Ancak DELETEburaya pek uymadığını görüyorum . Parolayı rastgele oluşturulmuş bir parola ile değiştiriyor olacaksınız, sanırım DELETEyanıltıcı olabilir. Create (POST) new reset_password actionÜzerinde hareket edeceğiniz ismin (kaynak) "reset_password işlemi" olmasını tercih ederim . Bu, e-posta göndermek için de uygundur, çünkü eylem tüm bu alt düzey ayrıntıları kapsamaktadır. POSTidempotent değildir.
Daniel Vassallo

Teklifi beğendim. Sorun 1, koşullu istekler, yani ETag + DELETE ve If-Match başlığı gönderen HEAD kullanılarak çözülebilir. Birisi artık aktif olmayan bir şifreyi silmeye çalışırsa, 412 alır.
whiskeysierra

1
DELETE'den kaçınırdım. Aynı varlık / kavram yeni bir değer alacağı için güncelleme yapıyorsunuz. Ama aslında, genellikle şu anda bile olmuyor, ancak yeni parolayı daha sonra farklı bir istekte gönderdikten sonra (parola sıfırlama postasından sonra) - Günümüzde kimse postayla yeni bir parola göndermiyor, ancak yeni bir istekte parolayı sıfırlamak için bir simge göndermiyor. belirli bir belirteç, değil mi?
antonio.fornie

11
Ya kullanıcı sıfırlama talebinde bulunduktan hemen sonra şifresini hatırlarsa? Rastgele hesapları sıfırlamaya çalışan bir bot ne olacak? Böyle bir durumda kullanıcının sıfırlama e-postasını görmezden gelmesine izin verilmelidir (e-posta öyle demelidir), yani sisteminizin şifreleri kendi başına silmemesi veya güncellememesi gerekir.
Maxime Laval

3
@MaximeLaval Bu çok iyi bir nokta. Gerçekten, bir POST olan "Sıfırlama İsteği Oluşturuyorsunuz".
Craig Walker

12

E-postaya erişimi olmayan bir kullanıcı tarafından (istemeden veya kasıtlı olarak) tetiklenmiş olabileceğinden, genellikle ilk istekte kullanıcının mevcut şifresini silmek veya yok etmek istemezsiniz. Bunun yerine, kullanıcı kaydındaki sıfırlama şifresini güncelleyin ve bunu bir e-postada bulunan bir bağlantıya gönderin. Bağlantıya tıklamak, kullanıcının jetonu aldığını onaylar ve şifresini güncellemek ister. İdeal olarak, bu da zamana duyarlı olacaktır.

Bu durumda RESTful eylemi bir POST olacaktır: PasswordResets denetleyicisinde oluşturma eylemini tetikleme. İşlemin kendisi jetonu günceller ve bir e-posta gönderir.


9

Aslında bir cevap arıyorum, bir cevap vermek anlamına gelmiyor - ama "reset_password" REST bağlamında bana yanlış geliyor çünkü bu bir isim değil bir fiil. Bu gerekçeyi kullanarak bir "sıfırlama eylemi" yaptığınızı söyleseniz bile, tüm fiiller isimdir.

Ayrıca, aynı cevabı arayan birinin, güvenlik bağlamı aracılığıyla kullanıcı adını alabilmeniz ve onu url veya vücut yoluyla göndermeniz gerekmemesi aklına gelmemiş olabilir, bu da beni endişelendiriyor.


4
Belki reset-passwordbir fiil gibi gelebilir, ancak password-resetonu bir isim yapmak için kolayca tersine çevirebilirsiniz ( ). Ve eğer uygulamanızı Event Sourcing kullanarak modellediyseniz veya herhangi bir denetiminiz olsa bile, bu isimde gerçek bir varlığa sahip olduğunuz ve hatta kullanıcıların veya yöneticilerin üzerinde GET'lere izin verebileceği mantıklıdır. geçmiş (açıkça şifre metnini maskeliyor). Beni hiç endişelendirmiyor. Ve kullanıcı adını sunucu tarafında otomatik olarak almaya gelince - yapabilirsiniz, ama sonra yönetim / kimliğe bürünme gibi şeyleri nasıl halledersiniz?
Aaronaught

1
REST'te fiil kullanımında yanlış bir şey yoktur. Sadece uygun yerlerde kullanıldığı sürece. Bunun bir kaynaktan çok bir denetleyici olduğunu ve reset-passwordetkilerini iyi tanımlamayı başardığını düşünüyorum.
Anders Östman

6

Bence daha iyi bir fikir:

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)

Verilerin sağlanmasıyla ilgili olarak:

  • Mevcut şifreyi sıfırlamak için

    • e-posta vücutta verilmelidir.
  • Yeni şifre oluşturmak için (sıfırladıktan sonra)

    • yeni şifre, aktivasyon kodu ve e-posta kimliği gövde içerisinde verilmelidir.
  • Parolayı güncellemek için (giriş yapmış kullanıcılar için)

    • eski şifre, yeni şifre gövde kısmında belirtilmelidir.
    • Parametrelerde UserId.
    • Başlıklarda Auth Token.

2
Diğer yanıtlarda da belirtildiği gibi, "SİL / api / v1 / hesap / parola" kötü bir fikirdir çünkü herhangi biri herhangi birinin parolasını sıfırlayabilir.
maximedupre

Parolayı sıfırlamak için kayıtlı bir e-posta kimliğine ihtiyacımız var. Facebook gibi bir site çalıştırmadığımız ve herhangi bir yolla toplanan tonlarca e-posta kimliğine sahip olmadığımız sürece, bilinmeyen kullanıcının e-posta kimliğini bilme şansı çok zordur. Ardından güvenlik politikaları buna göre tanımlanacaktır. Birinin şifresini sıfırlama öneriniz nedir?
codesnooker

5

Göz önünde bulundurulması gereken birkaç nokta vardır:

Parola sıfırlamaları idempotent değildir

Parola değişikliği, bunu gerçekleştirmek için kimlik bilgileri olarak kullanılan verileri etkiler; bu da, saklanan kimlik bilgileri değişirken istek basitçe aynen tekrarlanırsa gelecekteki girişimleri geçersiz kılabilir. Örneğin, parolanın unutulması durumunda alışılageldiği üzere değişikliğe izin vermek için geçici bir sıfırlama belirteci kullanılırsa, bu belirtecin başarılı bir parola değişikliğinden sonra sona ermesi gerekir, bu da isteği çoğaltma girişimlerini yine geçersiz kılar. Böylece bir şifre değişikliği bir sığınakta yaklaşım daha iyi için uygun bir iş gibi görünüyor POSTdaha PUT.

Veri yükünde kimlik veya e-posta muhtemelen gereksizdir

Bu REST'e aykırı olmasa ve bazı özel amaçları olsa da, şifre sıfırlama için bir kimlik veya e-posta adresi belirtmek çoğu zaman gereksizdir. Bir düşünün, neden bir şekilde kimlik doğrulamasından geçmesi gereken bir talebe verilerin bir parçası olarak e-posta adresini veriyorsunuz? Kullanıcı sadece şifresini değiştiriyorsa, bunu yapmak için kimlik doğrulaması gerekir (kullanıcı adı: şifre, e-posta: şifre veya başlıklar aracılığıyla sağlanan erişim belirteci aracılığıyla). Dolayısıyla, bu adımdan hesaplarına erişebiliriz. Parolalarını unutmuşlarsa, değişikliği gerçekleştirmek için özel olarak kimlik bilgileri olarak kullanabilecekleri geçici bir sıfırlama belirteci (e-posta yoluyla) verilmiş olacaktı. Ve bu durumda jetonla kimlik doğrulama, hesaplarını tanımlamak için yeterli olmalıdır.

Yukarıdakilerin hepsini göz önünde bulundurarak, RESTful şifre değişikliği için uygun plan olduğuna inanıyorum:

Method: POST
url: /v1/account/password
Access Token (via headers): pwd_rst_token_b3xSw4hR8nKWE1d4iE2s7JawT8bCMsT1EvUQ94aI
data load: {"password": "This 1s My very New Passw0rd"}

Bir yer tutucunun bant dışı bilgi gerektirdiğine dair bir ifade tamamen doğru değildir. Özel bir ortam türü, bir isteğin veya yanıtın belirli öğelerinin sözdizimini ve anlambilimini tanımlayabilir. Bu nedenle, bir ortam türünün, belirli bir alanda bulunan bir URI'nin belirli veriler için yer tutucuyu tanımlayabileceğini tanımlaması mümkündür ve anlambilim ayrıca, kodlanmış bir kullanıcı e-postasını veya yer tutucu yerine neyin dahil edilmemesi gerektiğini tanımlar. Bu ortam türüne saygı duyan istemciler ve sunucular, RESTful mimari ilkelerine hala uyumlu olacaktır.
Roman Vottner

1
İlgili POSTvs PUT 7231 RFC kısmi güncelleme iki kaynakların örtüşen veriler yoluyla elde edilebilir ancak böyle bir şey eğer şüpheli olduğunu belirtir /v1/account/passwordgerçekten aslında iyi bir kaynak için makyaj yok. POSTDiğer yöntemlerden hiçbirinin uygun olmaması durumunda kullanılabilen Web'in swiss-ordusu gibi , PATCHyeni şifreyi belirlemek için de bir seçenek olabilir.
Roma Vottner

şifrelerini bilmedikleri zaman şifre sıfırlama isteğinde bulunacak URL ne olacak?
dan carter

2

/ Users / {id} / password yöntemini kullanmaya karar verirseniz ve isteğin kendi başına bir kaynak olduğu fikrinize bağlı kalırsanız, şifreyi değiştiren ve onlara yeni bir tane gönderen bir şeyim olmayacak. yani / kullanıcı-parola-isteği / kaynaktır ve PUT kullanılıyorsa, kullanıcı bilgileri gövdede olmalıdır. Yine de şifreyi değiştirmezdim, Id kullanıcıya, POST / user / {id} / password /? Request_guid = isteği ile birlikte iletilebilen bir request_guid içeren bir sayfaya bağlantı içeren bir e-posta gönderir. xxxxx

Bu şifreyi değiştirir ve birisinin şifre değişikliği talep ederek bir kullanıcıyı hortumlamasına izin vermez.

Ayrıca, bekleyen bir istek varsa ilk PUT başarısız olabilir.


0

Kayıtlı kullanıcı Şifresini Güncelliyoruz PUT / v1 / users / password - AccessToken kullanarak kullanıcı kimliğini tanımlayın.

Kullanıcı kimliğini değiştirmek güvenli değildir. Restful API, HTTP başlığında alınan AccessToken'ı kullanarak kullanıcıyı tanımlamalıdır.

Yaylı önyüklemede örnek

@putMapping(value="/v1/users/password")
public ResponseEntity<String> updatePassword(@RequestHeader(value="Authorization") String token){
/* find User Using token */
/* Update Password*?
/* Return 200 */
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.