RESTfulパスワードリセット


107

パスワードをリセットするためのRESTfulリソースを構築する適切な方法は何ですか?

このリソースは、パスワードを紛失したり忘れたりした場合のパスワード再設定者になることを目的としています。古いパスワードを無効にし、パスワードを電子メールで送信します。

私の2つのオプションは次のとおりです。

POST /reset_password/{user_name}

または...

POST /reset_password
   -Username passed through request body

私はリクエストがPOSTであるべきだと確信しています。適切な名前を選択したことに自信が持てません。また、user_nameをURLとリクエスト本文のどちらを介して渡す必要があるかはわかりません。

回答:


54

更新:(以下でさらにコメントします)

私はこのようなものに行きます:

POST /users/:user_id/reset_password

ユーザーのコレクションがあり、単一のユーザーがによって指定されてい{user_name}ます。次に、操作するアクション(この場合は)を指定しますreset_password。「POSTの新しいreset_passwordアクションを作成()」と言うようなもの{user_name}です。


以前の答え:

私はこのようなものに行きます:

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

ユーザーコレクションと、各ユーザーの属性コレクションの2つのコレクションがあります。ユーザーはで指定され:user_id、属性はで指定されpasswordます。このPUT操作は、コレクションのアドレス指定されたメンバーを更新します。


10
更新された(POST)ソリューションに同意します。PUT要求はべき等である必要があります(つまり、繰り返し要求が結果に影響を与えることはありません)。これは、POST要求の場合には当てはまりません。
ロスマクファーレン

16
私はreset_passwordをpassword_resetに変更します
Richard

9
誰かにハングアップする...これは本質的に誰でも誰かのパスワードをリセットすることを許可しないのですか?これが現在のパスワードを忘れた人のためのものである場合、影響を受けるユーザーは現在のパスワードで認証できません。つまり、本質的に、これはこのAPIがパスワードをまったく受け入れることができなかったことを意味します。つまり、だれでも誰かのパスワードをリセットできるようになり、APIがそれを返した場合、既知のユーザーのパスワードを取得することさえできますか?それとも私が何かをしないのです
transient_loop

39
/ user / {id} / passwordなどの問題は、ユーザーの「id」がわからない場合があることです。あなたは彼らの「ユーザー名」、「メール」、「電話」を知っているでしょうが、「ID」は知りません。
coolaj86 2014年

17
このアプローチの根本的な欠陥は、ユーザーIDがすでにわかっていることを前提としていることです。これは一部の状況では当てはまりますが、ユーザーがリセット用の電子メールを指定するだけでよい場合に、ユーザー名またはユーザーIDがわからない場合はどうすればよいでしょうか。
アラピン2015年

93

認証されていないユーザー

エンドポイントでPUTリクエストを実行しapi/v1/account/password、ユーザーがパスワードをリセット(更新)したいアカウントを識別するために、対応するアカウントの電子メールのパラメーターが必要です。

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

注: よう@DougDomenyは、 URLのクエリ文字列は、セキュリティ上のリスクがあるとして電子メールを渡す彼のコメントで述べました。GETパラメーターは使用時に公開されませんhttpshttpsそのような要求には常に適切な接続を使用する必要があります)が、他のセキュリティリスクが伴います。このトピックについて詳しくは、こちらのブログ投稿をご覧ください

リクエスト本文でメールを渡すことは、GETパラメータとして渡すより安全な方法です。

PUT : /api/v1/account/password

リクエスト本文:

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

応答には、202受け入れられた応答の意味があります。

リクエストは処理のために受け入れられましたが、処理は完了していません。処理が実際に行われるときに許可されない場合があるため、要求は最終的に処理される場合と処理されない場合があります。このような非同期操作からステータスコードを再送信する機能はありません。

ユーザーはでメールを受信しemail@example.com、更新リクエストの処理はメールからのリンクで行われたアクションによって異なります。

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

このメールからリンクを開くと、非表示の入力フィールドの入力としてリンクからのパスワードのリセットトークンを使用するフロントエンドアプリケーションのパスワードのリセットフォームが表示されます(トークンはクエリ文字列としてリンクの一部です)。別の入力フィールドでは、ユーザーが新しいパスワードを設定できます。新しいタイプのパスワードを確認するための2番目の入力は、(タイプミスを防ぐために)フロントエンドでの検証に使用されます。

注意: メールで、ユーザーがパスワードのリセットを初期化しなかった場合は、メールを無視して、現在のパスワードでアプリケーションを通常どおり使用し続けることもできます。

新しいパスワードとトークンを入力としてフォームが送信されると、パスワードのリセットプロセスが実行されます。フォームデータはPUT再度リクエストとともに送信されますが、今回はトークンを含めて、リソースパスワードを新しい値に置き換えます。

PUT : /api/v1/account/password

リクエストボディ:

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

応答は次のようになります204ノーコンテンツ応答

サーバーは要求を満たしましたが、エンティティ本体を返す必要はなく、更新されたメタ情報を返したい場合があります。応答には、エンティティヘッダーの形式で新しいまたは更新されたメタ情報を含めることができます(MAY)。存在する場合、要求されたバリアントに関連付ける必要があります(SHOULD)。

認証されたユーザー

パスワードを変更したい認証済みユーザーの場合、PUT要求は電子メールなしですぐに実行できます(パスワードを更新するアカウントはサーバーに知られています)。そのような場合、フォームは2つのフィールドを送信します。

PUT : /api/v1/account/password

リクエスト本文:

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

最初の段落ではPUTと言いますが、以下の例ではDELETEと言います。どちらが正確ですか?
jpierson 2015

これにより、URLの電子メールアドレスが公開されます。これにより、JSONデータがより安全になります。
Doug Domeny

@DougDomenyはい、jsonデータとしてメールを送信した方が良いでしょう。これを別のより安全なオプションとして回答に追加しました。それ以外の場合、ソリューションは同じです。
Wilt

@Wilt:これはPATCH操作ではないでしょうか?PUTは完全なリソースを送信する必要があります
j10

1
@jitenshah良い点。これを書いているとき、PUTの方が良いと思いましたが、その理由を正確には覚えていません。私は、パッチがこの場合により適しているかもしれないというあなたの推論に同意します。
Wilt、

18

少しの間RESTfulにしましょう。パスワードにDELETEアクションを使用してリセットをトリガーしないのはなぜですか?理にかなっていますね。結局のところ、既存のパスワードを破棄して別のパスワードを優先しているのです。

それはあなたがすることを意味します:

DELETE /users/{user_name}/password

ここで、2つの大きな警告があります。

  1. HTTP DELETEはべき等であると想定されています(「複数回実行しても大したことはない」と言うのは派手な言葉です)。「パスワードのリセット」メールの送信などの標準的なことを行っている場合は、問題が発生します。このユーザー/パスワードのタグ付けには、ブール値の「Is Reset」フラグを使用することで回避できます。削除するたびに、このフラグをチェックします。それが設定されていない場合、その後、あなたは、パスワードをリセットし、電子メールを送信することができます。(このフラグを持つことは他の用途もあるかもしれないことに注意してください。)

  2. フォームを通じてHTTP DELETEを使用することはできないため、AJAX呼び出しを行うか、POSTを通じてDELETEをトンネリングする必要があります。


9
面白いアイデア。しかし、私はDELETEここにうまく適合していないと思います。パスワードをランダムに生成されたものに置き換えていると思いますが、これDELETEは誤解を招く可能性があります。私はCreate (POST) new reset_password action、あなたが作用する名詞(リソース)が「reset_passwordアクション」であるを好む。アクションはこれらすべての下位レベルの詳細をカプセル化するため、これはメールの送信にも適しています。POSTべき等ではありません。
ダニエルヴァッサロ

私はその提案が好きです。問題1は、条件付き要求、つまりETag + DELETEおよびIf-Matchヘッダーを送信するHEADを使用することで処理できます。誰かがもはやアクティブのパスワードを削除しようとすると、彼は412を取得します
whiskeysierra

1
削除は避けます。同じエンティティ/コンセプトが新しい値を取得するため、更新しています。しかし、実際には、通常は今でも発生していませんが、後で別の要求で新しいパスワードを送信した後(パスワードのリセットメールの後)-今日では誰も新しいパスワードをメールで送信しませんが、新しい要求でパスワードをリセットするためのトークン与えられたトークンですね
antonio.fornie 2015年

11
ユーザーがリセット要求を行った直後に自分のパスワードを覚えている場合はどうなりますか?ランダムアカウントをリセットしようとするボットについてはどうですか?このような場合、ユーザーはリセットメールを無視することを許可する必要があります(メールにはそのように書かれているはずです)。つまり、システム自体がパスワードを削除または更新してはなりません。
Maxime Laval

3
@MaximeLavalそれは非常に良い点です。本当に、あなたはPOSTになる「リセット要求の作成」です。
Craig Walker

12

多くの場合、最初のリクエストでユーザーの既存のパスワードを削除または破棄したくない場合があります。これは、電子メールへのアクセス権を持たないユーザーによって(意図的または意図的ではなく)トリガーされた可能性があるためです。代わりに、ユーザーレコードのリセットパスワードトークンを更新し、それをメールに含まれるリンクで送信します。リンクをクリックすると、ユーザーがトークンを受け取り、パスワードを更新することを確認したことになります。理想的には、これも時間に敏感になるでしょう。

この場合のRESTfulアクションはPOSTです。PasswordResetsコントローラーで作成アクションをトリガーします。アクション自体がトークンを更新し、メールを送信します。


9

私は実際に答えを探しています。それを提供する意味ではありません-「reset_password」は、名詞ではなく動詞であるため、RESTコンテキストでは間違っているように見えます。「リセットアクション」という名詞を使用していると言っても、この正当化を使用すると、すべての動詞は名詞になります。

また、セキュリティコンテキストを介してユーザー名を取得できる可能性がある同じ回答を検索している人には発生していない可能性があり、URLまたは本文を介してそれを送信する必要がないため、緊張しています。


4
おそらくreset-password動詞のように聞こえますが、簡単に逆転(password-reset)して名詞にすることができます。また、イベントソーシングを使用してアプリケーションをモデル化した場合や、何らかの監査を行っている場合でも、実際にこの名前の実際のエンティティが存在し、ユーザーまたは管理者がそのGETを実行できる場合もあります。履歴(明らかにパスワードテキストをマスクします)。緊張しません。そして、サーバー側で自動的にユーザー名を取得することについては-できますが、それでは管理/偽装などをどのように処理しますか?
アーロンノート、2014年

1
RESTで動詞を使用することに問題はありません。適切な場所で使用されている限り。これはリソースというよりコントローラーのほうがいいと思いますし、そのreset-password効果をうまく表現できています。
AndersÖstman、2015

6

私はより良いアイデアになると思います:

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)

データの提供について:

  • 現在のパスワードをリセットするには

    • メールは本文で提出してください。
  • 新しいパスワードを作成するには(リセット後)

    • 新しいパスワード、アクティベーションコード、emailIDを本文に含めてください。
  • パスワードを更新するには(loginInユーザー用)

    • 古いパスワード、新しいパスワードを本文に記載する必要があります。
    • パラメータのユーザーID。
    • ヘッダーの認証トークン。

2
他の回答でコメントされているように、「DELETE / api / v1 / account / password」はだれでもパスワードをリセットできるため、お勧めできません。
maximedupre

パスワードをリセットするには、登録済みのメールIDが必要です。Facebookのようなサイトを運営していて、大量のメールIDを何らかの方法で収集していない限り、不明なユーザーのメールIDを知る可能性は非常に厳しいです。次に、それに応じてセキュリティポリシーが定義されます。誰かのパスワードをリセットするためのあなたの提案は何ですか?
コードスヌーカー

5

考慮すべきいくつかの考慮事項があります。

パスワードのリセットはべき等ではありません

パスワードの変更は、それを実行するための資格情報として使用されるデータに影響を及ぼします。その結果、保存された資格情報が変更されている間に要求が単純に繰り返し繰り返されると、将来の試行が無効になる可能性があります。たとえば、一時的なリセットトークンを使用して変更を許可する場合、これはパスワードを忘れた場合の慣例ですが、パスワードの変更が成功するとそのトークンは期限切れになり、要求の複製の試行が再び無効になります。したがって、パスワード変更へのRESTfulなアプローチは、より適切な仕事のようPOSTですPUT

データロード内のIDまたは電子メールはおそらく冗長です

これはRESTに違反するものではなく、特別な目的があるかもしれませんが、パスワードのリセットのためにIDまたは電子メールアドレスを指定する必要はないことがよくあります。考えてみて、なぜ認証が何らかの方法で行われることになっているリクエストに対して、データの一部としてメールアドレスを提供するのでしょうか?ユーザーが単にパスワードを変更するだけの場合、そのためには認証が必要です(ユーザー名:パスワード、電子メール:パスワード、またはヘッダー経由で提供されるアクセストークンを使用)。したがって、そのステップからアカウントにアクセスできます。パスワードを忘れた場合は、一時的なリセットトークンが(メールで)提供され、変更を行うための資格情報として特に使用できます。この場合、トークンによる認証でアカウントを識別できます。

上記のすべてを考慮に入れると、RESTfulパスワード変更の適切なスキームであると私は信じています。

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

プレースホルダーが帯域外の情報を必要とするという記述は完全に真実ではありません。特別なメディアタイプは、リクエストまたはレスポンスの特定の要素の構文とセマンティクスを記述できます。したがって、メディアタイプは、特定のフィールドに含まれるURIが特定のデータのプレースホルダーを定義できることを定義でき、セマンティクスは、エンコードされたユーザーの電子メールまたはプレースホルダーの代わりに何を含めないかをさらに定義します。そのメディアタイプを尊重するクライアントとサーバーは、RESTfulアーキテクチャの原則に引き続き準拠します。
Roman Vottner、2018

1
POSTPUT RFC 7231部分更新は、2つのリソースの重複したデータによって達成することができるが、のようなものがあれば、それは疑問であることを指定し/v1/account/password、本当に実際に良いリソースを補うん。POST他の方法のいずれも考慮すると、実現可能でない場合に使用できるWebのスイス・アーミー・kniffあるPATCHかもしれないが、新しいパスワードを設定するための選択です。
Roman Vottner、2018

パスワードがわからない場合にパスワードのリセットを要求するURLはどうなりますか?
ダンカーター、

2

/ users / {id} / passwordメソッドを使用し、リクエストが独自のリソースであるという考えに固執する場合、パスワードを変更して新しいパスワードを送信するものはありません。つまり、/ user-password-request /はリソースであり、PUTを使用するため、ユーザー情報を本文に含める必要があります。パスワードは変更しませんが、request_guidを含むページへのリンクを含むメールをユーザーに送信します。これは、POST / user / {id} / password /?request_guid =へのリクエストと共に渡すことができます。 xxxxx

それはパスワードを変更し、誰かがパスワードの変更を要求することによってユーザーをホースすることはできません。

さらに、未処理の要求がある場合、最初のPUTは失敗する可能性があります。


0

ログに記録されたユーザーのパスワードを更新PUT / v1 / users / password-AccessTokenを使用してユーザーIDを識別します。

ユーザーIDの交換は安全ではありません。Restful APIは、HTTPヘッダーで受信したAccessTokenを使用してユーザーを識別する必要があります。

Spring-Bootの例

@putMapping(value="/v1/users/password")
public ResponseEntity<String> updatePassword(@RequestHeader(value="Authorization") String token){
/* find User Using token */
/* Update Password*?
/* Return 200 */
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.