web-dev-qa-db-ja.com

JWTでAPIキーを生成し、必要に応じて同じキーを再生成します

最近、自分のアプリケーション用のパブリックAPIを開発する必要があることに気付きました。 node.jsMongoDBを使用してアプリケーションを開発しました。調査の結果、jwtを使用してユーザーと認証用のAPIキーを生成することにしました。 jwtトークンを認証する場合、正確に生成されたトークンを知らなくてもデコードおよび検証できるため、トークンをデータベースに保存する必要がないという利点があります。

しかし、多くのアプリケーションがアプリケーションダッシュボードにユーザーのAPIキーを表示しているので、後でユーザーに表示するためにトークンを保存する必要があります。トークンを保存することは悪い考えであり、データベースが侵害された場合、ハッカーがAPIキーを使用して他人になりすます可能性があります。

要するに、私は正確なトークンを保存しない方法を見つけようとしていますが、データベースにペイロードのみを保存し、ユーザーがAPIキーを要求するたびに、[〜#〜] secret [〜#〜]として、それらに渡します。現在、署名トークンステップで毎回同じiat(発行元)で同じペイロードを渡すと、生成されるトークンは毎回同じになることがわかりました。したがって、iatをペイロードデータと共にデータベースに保存することで、毎回正確なトークンを生成できます。


今私の質問は:

  • このアプローチは良いですか、これを達成するためのより良い方法はありますか?
  • APIキーを保存せずに生成するための良い方法はありますか?
  • これはさらに必要ですか(データベースビーチがあったとしても、すべてのデータがすでに盗まれています)。
  • これを達成するためにjwtを使用する以外の方法はありますか?
5
Sinandro

tl/dr:JWTは、サーバー間APIトークン/キーの正しいソリューションではありません。ユーザーが(理由を問わず)変更する必要がある場合、APIキーは取り消し可能である必要があり、JWTはその性質上、取り消すことができません。サーバー間認証には完全に異なるソリューションが必要です。

私はフレームチャレンジで答えます。

実際には、2つの異なる目的を持つ2つの完全に異なるkind認証トークンについて話している。とにかくJWTはユーザーダッシュボードに必要なものではないため、JWTを再生成してユーザーダッシュボードに表示する方法を理解する必要はありません。

JWTとその使用例を理解する

JWTには、これから説明する他の種類のアクセストークンと区別する2つのプロパティがあります。それらは取り消すことができず、通常は有効期間が短いです(これは、取り消しできないために必要な結果です)。

それらを取り消すことができないという事実は、データベースをチェックせずにそれらを検証できるという事実の当然の帰結です。 JWTをチェックするために必要なものはすべてJWTに組み込まれており、それらを取り消すことができる唯一の方法は、JWTを検証するたびにデータベースでそれらをマークし、データベースをチェックすることです(これは目的を無効にします)。したがって、これらは事実上取り消すことができないため、攻撃者が盗んだ場合に発生する被害を最小限に抑えるために、ライフタイムを短くすることをお勧めします。その結果、JWTには通常、より長寿命で、ユーザーが最初のJWTが期限切れになったときに新しいJWTを生成するために使用できる更新トークンも付属しています。

このプロパティの組み合わせにより、JWTに特定のユースケースが与えられます。最初にユーザー名とパスワードでログインするユーザーを認証します。ユーザーがアプリケーションにログインすると、JWTと更新トークンが与えられ、アプリは、ユーザーが必要な間ユーザーのログインを維持するために使用します(電話アプリまたはWebサイトは更新トークンを使用して自動的に取得します)必要に応じて新しいJWTを作成し、すべてのリクエストとともに最新のJWTを送信します)。

JWTの有効期間が短いか、有効期限が切れていない場合は、システムに重大なセキュリティの脆弱性が残されていることに注意してください。パスワードがリセットされます。 JWTは実際のクライアント(モバイルアプリまたはWebアプリケーション)に送信されるため、外部のアクターによる盗難に対してはるかに脆弱であり、そのため短いライフタイムが必要です。

APIアクセストークン

もちろん、APIのアクセストークンを管理するにはさまざまな方法がありますが、ダッシュボードにAPIトークンを表示するシステムについて説明しました。これらには通常、異なるプロパティセットがあります。特に、それらは長命であり、取り消し可能です。それらはサーバー間の通信に使用されるため、長寿命です。これは、構成ファイル(または類似のファイル)に常駐していることが多いため、正当な理由なしにエンドユーザーに更新プロセスの管理やトークンの更新を強制したくない場合です。

結果として、取り消し可能性は非常に重要です。ユーザーが(何らかの理由で)新しいアクセストークンが必要だと判断した場合は、新しいアクセストークンを簡単に生成する方法が必要です。より高度なシステムでは、独自の特権システムも備えており、管理者は必要な数のアクセストークンを生成して特権を割り当てることができます。これにより、ユーザーは自分のアカウントのセキュリティを管理するために必要なツールを利用できます。

すべてをまとめる

要約すると、これらは2つのまったく異なる理由により、2つの異なる種類のアクセスコードです。 JWTは、盗用されるリスクが高いエンドクライアントに到達するため、存続期間の短いアクセスコードです。ユーザーがログインするたびに新しいものが割り当てられ、その後すぐに期限切れになり、クライアントによって自動的に更新されます。

サーバー間APIトークンは存続期間が長く、お客様によって明示的に取り消された場合にのみ機能を停止します。サーバーの構成情報にコピーして、必要な場合にのみ変更できます。期限切れになることはなく、更新する必要もありません。

これらは2つの完全に異なる認証ニーズです。2つの通信チャネルには異なるセキュリティニーズがあるため、フロントエンドクライアントを認証する方法は、サーバー間通信を認証する方法とは異なります。 1つの「種類の」認証で両方のニーズを満たそうとしていますが、実際には、サーバー間認証でも機能するようにJWTを調整しようとするのは悪い考えです。ユーザーが2つの異なる方法でシステムと対話する必要がある場合は、2種類の認証を提供する必要があります。特に、JWTトークンの有効期限を(サーバー間認証に使用できるように)許可することを計画していないようですが、これはvery悪い考えです。

ソリューション

それでは、ユーザーのAPIキーをどのように生成する必要がありますか?それはあなたのニーズに依存しますが、私はそれらが何であるかわからないので、私はいくつかのケースではやり過ぎかもしれないが、すべてのケースでは十分であるかもしれない提案をあなたに与えます。

最も安全なソリューションは、エンドユーザーが複数のキーを持つことを許可することです。彼らが新しいキーを要求すると、公開/秘密キーのペアを生成し、ユーザーに秘密キーをダウンロードさせ、サーバー側に秘密キーを破棄しますそれ以降、必要に応じて使用/保存/コピーするのはユーザーの責任です。サーバーは公開鍵を保持し、要求は標準の非対称暗号方式を使用して署名および検証されます。これにより、ユーザーは必要に応じて、場合によってはアクセスレベルが異なる複数のキーを生成できます。

もちろん、もっと簡単な方法もありますが、「最適な」認証方法を選択しようとするのは少し範囲外です。誰もがさまざまなニーズを抱えており、セキュリティ/使いやすさ/コストのバランスをとる必要があります。

1
Conor Mancone

このアプローチは良いですか、これを達成するためのより良い方法はありますか?

もっと良い方法があると思います。ユーザーがAPIキーにサインアップするとき、GUIを介して一度表示し、コピーしてもらいます。次に、それをデータベースに一方向ハッシュします。その時点でそれを取得する唯一の方法は、新しいものを作成することです。保管中のデータを保護するために何をする必要があるか考えてください。

明らかに、ユーザーは自分の側でクレームを作成し、それをbase64でエンコードする必要があります。 APIエンドポイントは、転送中のデータのセキュリティを処理するSSLを使用する必要があります。データベースにクレームを保存しないでください。 iat(Issued At)が毎回同じである場合、APIへのアクセスをどのように追跡する予定ですか?

セキュリティのために、エンドポイントによって生成されたすべてのトークンに有効期限を使用することをお勧めします。

私は実際に別のリンクを盗むつもりですSO HMACとAPIキーとシークレットキーの両方を使用した安全なストレージオプションを説明するかなり良い仕事をする答え: https://stackoverflow.com/a/37953361/9199874

APIキーを保存せずに生成するための良い方法はありますか?

わからない

これは必要でもありますか(データベースビーチがあったとしても、すべてのデータがすでに盗まれています)?

これが発生した場合、1番への私の答えはリスクを減らすことができます。リスクを完全に排除することは不可能です。

これを達成するためにjwtを使用する以外の方法はありますか?

私はJWTをAPI開発者として使用しており、気に入っています。 API呼び出し内にさまざまなスコープを含める場合は、カスタムクレームでいくつかの値を見つけることもできます。

0
Justin

短い答え:トークンをローカルでデコードします。これはおそらく、あなたが言及している他のアプリケーション/ダッシュボードが行っていることです。

トークンをユーザーに表示する理由を尋ねてください。セッションが期限切れになるとき、および/または最後に認証されたとき(トークンのexpおよびiatフィールド)を表示するだけかもしれません

トークンを暗号化する必要がある場合を除き、使用しないでください。署名し、「ダッシュボード」にデコードさせて、ユーザーにペイロードを表示します。

何かを保存したい場合は、署名なしでペイロードを保存してください。

これを保存することがセキュリティリスクかどうかは、トークンに何が含まれているかによって異なります。しかし、その情報はおそらくデータベースですでに利用可能です。トークンをオーバーロードしないという一般的な方法が頭に浮かぶはずです。ユーザーID(サブフィールド)を保存しますが、ログインに必要なパスワードやユーザー名は保存しないでください。

次に、JWTを保存すること自体は悪い習慣ではありません。ただし、パスワードを保存する場合と同じリスク軽減策を適用する必要があります。トークンの保存には大きな落とし穴が伴います。これは、JWTを使用することの多くの利点を無効にします。最大の利点の1つは、トークンを保存する必要がないことです。

注:ユーザー/アプリケーションは「古い」トークンをリクエストしないでください。また、トークンが発行されたときにシステムが嘘をついてはなりません。 iatは「今」である必要があり、新たに要求された場合、トークンは新しいはずです。したがって、ユーザーが認証(またはセッショントークンを更新)するたびに、新しいiatexpを使用して新しいトークンを発行します。

認証サーバー-トークンを発行するエンティティが、トークンを使用するサービスまたはシステムとは別である場合は、公開鍵/秘密鍵スキームを使用して鍵に署名し、1つのシステムから秘密鍵をコピーまたは転送しないでください別に。

機密情報(ユーザーのパスワードなど)が含まれている場合にのみトークンを暗号化しますが、それを行う理由を真剣に質問します。安全なトランスポート層よりも基本認証スキームを使用した方がよいでしょう。

トークンはクライアントによって復号化されなくても使用できることに注意してください。トークンを暗号化しても、悪意のあるサードパーティがトークンを使用できないというわけではありません。トークンを手に入れることができれば、トークンを使用できます。

トークンを無駄にしないでください。

0
Johan