ユーザー認証の不備がJSON Webトークンに与える脅威の分析
エグゼクティブサマリー
Akamaiの研究者は、OWASP APIセキュリティトップ10にも挙げられているJSON Webトークン(JWT)を、認証システムを侵害する攻撃の手段として分析し、JWTに関連する脅威やその動向がどのような状況で発生するのかを明らかにしました。
JWTは、ユーザーを安全に検証するためのトークン(通常はクライアントとサーバー間)を発行することにより、APIのセキュリティを確保する役割を担っています。こうしたトークンは、一般的な検証形式の1つとして広く使用されており、JSONオブジェクトの形式で共有される情報を含んでいます。
各トークンは暗号化されていませんが、エンコードされており、検証の署名が付与されています。Akamaiは、不正な実装や低エントロピーで短い秘密鍵に起因する、JWTに対する多くの脅威の一部を調査しました。
JWTユーザーと組織がAPIのトークンとしてJWTを選択する際に直面している大きな潜在リスクは、アカウントの乗っ取り、権限の昇格、データの漏えいの3つです。対称アルゴリズムは理論的に安全性が低いにもかかわらず、Akamaiのトラフィックでは、ほとんどのJWTがこのアルゴリズムを使用していることがわかりました。
この投稿では、これらのJWTの脅威に対応するためのベストプラクティスを紹介します。
はじめに
JWTは広く利用され、比較的容易に実装できるトークン方式である一方、さまざまなリスクが潜んでいます。JWTの実装とセキュリティ確保の際は、こうしたリスクを考慮する必要があります。JWTに対する最も重大なリスクの一つは、OWASP APIセキュリティトップ10にも挙げられている、ユーザー認証の不備です。
ユーザー認証の不備は、リクエストしているユーザーの認証情報とIDがAPIによって適切に検証されていない場合に発生します。残念ながら、この脆弱性はJWTに多く観測されており、攻撃者が別のユーザーのアカウントになりすましたりアクセスしたりして、権限の昇格やデータの漏えいを引き起こす恐れがあります。
パイプラインの保護
JWTは、APIおよびWebアプリケーションで一般的に使用される認証トークンです。Akamaiのトラフィックでは、Webアプリケーションによってより多くのAPIが使用され、顧客に公開されており、さまざまなAPIエンドポイントにおけるシームレスな認証の必要性が高まっていることがわかりました。
APIは組織の主要なパイプラインとして、認証および承認メカニズムの保持、データベースの照会、組織の多くの機能の公開という役割を担っています。そのため、APIの領域ではJWTの脅威の危険性が高まっています。このブログの投稿では、JWTの基本知識、JWTに対する6つの脅威、これらの脅威への対処方法について説明します。
JWTの基本知識
JWTは、Webアプリケーション、モバイルアプリケーション、およびAPIでデータを渡すために署名付きJSONデータを送信する際の形式であり、主に認証のみに使用されます。JWT構造は、ヘッダー(JOSEヘッダーとも呼ばれます)、ペイロード、署名の3つの要素で構成され、すべてドットで区切られています(図1)。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiIiLCJpYXQiOjE2NzYyMTc5NTAsImV4cCI6MTcwNzc1Mzk1MCwiYXVkIjoiYWthbWFpLWJsb2ciLCJzdWIiOiIiLCJjb21wYW55IjoiQWthbWFpIiwidXNlciI6IkFrYW1haS1yZWFkZXIiLCJhZG1pbiI6Im5vIn0.kMPz3Z7BSlBTJKijD8bcrpzTZejX7VCZ77w5oQwJO6I
図1:JWT構造を成す3つの要素の例
ヘッダーとペイロード
ヘッダーとペイロードはどちらもBase64形式でURLセーフにエンコードされており、IETFで規定されたフィールドに関する推奨事項に従っています(図2)。「エンコード」とは、人間には直接読み取ることはできないがサーバーは簡単にデコードできることを意味します。その目的は、「URLセーフ」を維持しながら、データの整合性と使いやすさを確保することです。このようにして、Webブラウザーで使用される文字との重複を回避しています。
JOSEヘッダーは、JWTとJSON Web Encryption(JWE)の両方に使用されます。JWEは、大まかに言うと、暗号化されているJWTで、一般的なJWT攻撃の大半を回避する際に効果を発揮します。選択されたトークン方式を指定するフィールドは、「typ」(typ:JWT/JWE)です。ペイロードには、実装によって、Internet Assigned Numbers Authority(IANA)に登録されたフィールドが含まれる場合もあれば、カスタムフィールドが含まれる場合もあります。
図2:エンコードされたJWT
署名
署名の目的は、トークンの検証です。つまり、トークンがサーバーによって生成されたものであり、トークン作成後にデータが変更されていないことを検証します。
署名を作成するには、主に次の2つの手順を実行します。
暗号化アルゴリズム(MACなど)を、ドットで区切られたヘッダーとペイロードに適用する(アルゴリズムは秘密鍵を使用する)
ハッシュアルゴリズム(SHA256など)を暗号化されたヘッダーとペイロードに適用する
JWTの使用時に、サーバーではトークン自体を検証するために署名が検証されます(今回の投稿では、後半で検証用のさまざまなアルゴリズムについて説明します)。
JWTは、(大規模な場合も含めて)使いやすく、実装が容易で、サーバー側で必要となる情報をクライアント側に保持できるため、Webアプリケーションでの認証に広く使用されています。ただし、JWTは署名されていても、リスクが伴います。JWTはプレーンテキストを使用しており、各実装は異なるペイロードフィールドで構成されています。そのため、アタックサーフェスが広く、エラーの余地も十分にあります。
JWTが直面している一般的かつ興味深い脅威を調査することで、脆弱性に対する意識の向上、悪性のふるまいの容易な検知、リスクの適切な緩和、必要なセキュリティ対策による潜在的な脆弱性からの保護を実現できます。
Akamaiは、ユーザーがより安全なアプローチによってJWTを使用して作業し、セキュリティ専門家や管理者にデューデリジェンスを実施するために必要なツールと推奨事項を提供することを目標としています。
JWTに対する6つの脅威
1. サーバーが検証なしでトークンを使用できてしまう
JWTは暗号化の代わりに署名を使用するため、事前に検証を行う必要があります。アプリケーションがまったく検証を行わないという最も基本的な脅威シナリオでは、攻撃者はペイロード(例:権限昇格)を書き換えたうえで署名をそのまま維持したり、署名自体を削除したりすることで、より高い権限を取得することができます。
もう1つ考えられるのは、トークンの署名に使用されたアルゴリズムを表すヘッダーの「alg」パラメータを使用する方法です。「None」は正当な値であるため(この場合、そのJWTは「Unsecured JWT」と呼ばれます)、誰でも容易に署名なしのトークンを作成できます。バックエンドでは、JWT検証の実装も可能です。
このアプローチでは、まずヘッダーの「alg」フィールドを確認します。その後、指定されたアルゴリズムを使用してトークンを検証します。「None」アルゴリズムでは、そのトークンの署名と検証は必要ありません。トークンのペイロードを編集し、ヘッダーの「alg」をnoneに変更して、「自己署名」(署名を削除)すれば、攻撃の成功です。
例
図3に、デコードされたJWTの例を示します。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ij
oxNjU5MjM5MDIyfQ.PrhAp2DUWXoL01_odyLATuzrwn5rMtY1IVsP8y4LH5E
decoded:
{
"alg": "HS256",
"typ": "JWT"
}
.{
"name": "example name",
"iat": 1659239022
}
図3:デコードされたJWTの例
APIエンドポイントでは、検証のために選択したアルゴリズムとしてペイロードの「alg」フィールドを使用するものと仮定します。
しかし、ここではJWTを編集します(図4)。このようにして、別のユーザーになりすます有効なJWTの偽造に成功しました。
eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiZXhhbXBsZSBuYW1lIiwiaWF0Ijo
xNjU5MjM5MDIyfQ.
decoded:
{
"alg": "none",
"typ": "JWT"
}
.{
"name": "other person's name",
"iat": 1659239022
}
図4:alg:noneを不正利用するために編集したJWT
ベストプラクティス:これは簡単です。トークンを使用する前に、常に、ハードコーディングされた事前定義アルゴリズムを使用して検証します。algパラメータを検証アルゴリズムのポインタとして使用しないでください。
2.異なるアプリケーションに同じ秘密鍵を使用している
アプリケーションごとに別の登録をするようにしている企業は多数あります。同じ秘密鍵を使用すると、異なるユーザーIDを持つ2つのアプリケーションの両方で有効なトークンが作成されてしまいます。この場合、1つ目のアプリケーションで発行されたアプリケーショントークンを使って2つ目のアプリケーションにリクエストを送信することで、アカウントを乗っ取ることが可能になります。ただし、乗っ取るアカウントを任意に選択できるわけではありません(図5)。
ベストプラクティス:簡単な経験則が効果的です。ユーザーIDを切り離す際、別の秘密鍵を使用してください。
3.弱い署名アルゴリズムを使用している
アルゴリズムには、主に対称(HSXXX)と非対称(RSXXX、ESXXX、PSXXX)という2種類のファミリーがあります。対称アルゴリズムでは、共有の秘密鍵が1つ必要です。非対称アルゴリズムでは、秘密鍵と公開鍵が必要です(表1)。
対称 | |||
|---|---|---|---|
HSXXX | HMAC + SHA | 安全性が比較的低いアルゴリズム | 共有の秘密鍵を使用 |
非対称 | |||
RSXXX | RSA + SHA | より安全なアルゴリズム | 秘密鍵と公開鍵を使用 |
ESXXX | ECDSA + SHA | 3種類のアルゴリズムの中で最も安全性が高い | 秘密鍵と公開鍵を使用 |
表1:アルゴリズムの2つの主要なファミリー
攻撃者の視点からは、対称アルゴリズムの方が総当たりが容易で、公開鍵を収集する必要はなく、計算効率も非常に高くなります。Akamaiのトラフィックでは、非対称アルゴリズムよりも対称アルゴリズムの方が広く使用されています (図6)。
理論的に考えると、対称アルゴリズムは計算が少なくて済むため、大規模なケースでは非対称アルゴリズムよりもパフォーマンスが上回る場合があります。
ベストプラクティス:非対称アルゴリズムを使用する。現在、暗号学的に最も安全な選択肢であるECDSAアルゴリズムを使用することをお勧めします。秘密鍵が高いエントロピーで十分な長さを持っている場合は、適切に保護されている対称キーを使用しても構いません。
4.短く、低エントロピーの秘密鍵を使用している
短く、低エントロピーの秘密鍵は、迅速かつ低コストな総当たり攻撃の標的になる可能性があります。世の中には、グラフィックス・プロセシング・ユニット(GPU)を搭載した高性能クラウド環境にインストール可能な使いやすいクラッキングソフトウェアが存在します。GPUの性能は急速に向上しており、クラッキング能力にもその影響が及んでいます。今日のハイエンド・グラフィックス・カードは、3年前に比べて約2.5倍のスピードで解読可能です。
8文字の秘密鍵の解読に必要な日数(エントロピーは無関係とする)を3年前と現在で比較した結果を表2に示します。
ハイエンド・グラフィックス・カード | 解読に要した日数 |
|---|---|
3年前 | 10.5日 |
現在 | 4.5日 |
表2:8文字の秘密鍵を解読するのにかかる日数
数年前には約24時間かかったとされる7文字の秘密鍵も、今では90分未満で解読できます。この攻撃のユニークな点は、オフラインで実行するところです。組織側からは防御するどころか、そのような攻撃を受けていることすら知る方法もありません。
国家支援型の攻撃者として、そのような攻撃のために大規模に連携されたシステムを構築している様子を想像してみてください。JWTの秘密鍵を保持すれば、攻撃者は署名付きトークンを偽造し、そのユーザーIDを知っているだけで他のユーザーになりすますことができるのです。
ベストプラクティス:10文字以上の長い、高エントロピーの秘密鍵を使用する。秘密鍵の生成にRSAを使用することをお勧めします。
5.機密データをJWTのペイロードに保存している
JWTはBase64 URLエンコードされているため、ペイロードは暗号化されません。DB名、連番ID(すべての種類)、またはサーバーの内部フィールドとデータを格納すると、過度のデータ漏洩が発生し、他の攻撃ベクトル(たとえば、オブジェクトレベルの認可の不備など)における攻撃を助長する恐れがあります。
ベストプラクティス:機微な情報をJWTに保存しない。機微な情報を保存する必要がある場合は、JWEを使用してください。
6.鍵の混同
非対称アルゴリズムでは、JWT(署名部分)を作成するために秘密鍵が使用され、JWTを検証するために公開鍵が使用されます。攻撃者は、ヘッダーで指定されたアルゴリズムを対称的なアルゴリズム(HS256など)に変更し、サーバーによる検証に使用されている正当な公開鍵を悪用して署名を作成します。
その場合、適切に実装されていないバックエンドは公開鍵を使用して、ヘッダーで攻撃者が指定した対称アルゴリズムを実行し、攻撃者によって偽造されたJWTを正当なものとして検証してしまいます。
例
図7は、サーバーが新しいJWTを偽造するプロセスを示しています。図8は、サーバーのJWT検証プロセスを示しています。
検証の最後に行われる比較でエラーが発生する理由は、次の2つのいずれか(または両方)です。
ヘッダーとペイロードは編集されたが、署名は編集されなかった
正しいアルゴリズムまたは正しい鍵の設定に誤りがある
図9は、鍵の混同攻撃を示しています。
最終ステップ:サーバーは、図8に示すプロセスでトークンを検証します。このプロセスでは、サーバーはalgフィールドを信頼します。公開鍵を秘密としてHS256アルゴリズムを実行してトークンを検証します。まさに攻撃者の思いどおりです。
ベストプラクティス:検証プロセスで事前定義されたアルゴリズムを使用し、ユーザー入力を信頼しない。
結論
JWTは最も広く使われている認証トークンです。何度もサインインし直すことなく、多くのWebアプリケーションやAPIを認証済みの状態で利用できます。その一方で、JWTは暗号化されておらず、セキュリティを考慮して実装されていないため、多くの脅威が存在します。
コンピューターの能力は急速に進化しているため、脆弱な秘密鍵はリスクがあり、数年どころか数日で解読される可能性があります。JWTの場合、この種の攻撃は、組織が攻撃を認識していなくてもオフラインで実行される可能性があります。
対称アルゴリズムは最も広く使われており、それだけに攻撃者にとって作業が容易になります。
認証攻撃のような複雑な脅威も存在しますが、攻撃者が認証攻撃を自動化するのは困難です。しかし、単純なJWT攻撃ベクトルは、自動化され、大規模に悪用される恐れがあります。
こうした理由(およびその他の多くの理由)から、ユーザーはJWTの脆弱性とセキュリティのベストプラクティスを把握した上で潜在的な攻撃から保護することが重要です。OWASP APIセキュリティトップ10の脅威として挙げられている「ユーザー認証の不備」からJWTを保護する有用なガイドとして、この分析結果がお役に立てれば幸いです。