GitEngHar / myEnglish.server

MyEnglish.Server
0 stars 0 forks source link

GoogleとOIDC認証連携をしていこう #3

Open GitEngHar opened 1 week ago

GitEngHar commented 1 week ago

spring 6.0 でoauth https://spring.pleiades.io/spring-security/reference/servlet/oauth2/login/core.html

spring 6.0以前? の書き方 https://zenn.dev/gen_kk/articles/be05af86455666

GitEngHar commented 1 week ago

論理を固める

JWT認証について

https://developer.mamezou-tech.com/blogs/2022/12/08/jwt-auth/

ルーティング

ほげほげ

OIDCの仕組み

WebSite A で認証し、他サイトで連携して A のみの登録情報で他サイトでもログインできるようにする仕組み

  1. WebAでログイン
  2. WebBでログインしたい要求
  3. B→Aにログイン必要なIDトークンとアクセストークンを発行依頼
  4. Aで提示情報と署名が正しいか検証
  5. A → ユーザーに認証要求
  6. ユーザー IDトークンとアクセストークンの発行を認証
  7. AからBへのIDトークンとアクセストークンの発行
  8. IDトークンとアクセストークンを利用してログイン

トークンの違い

OIDCは認可の仕組みであって認証の仕組みではないので、トークン値が正しいかどうかは検証する必要があるようだ https://tech.yyh-gl.dev/blog/id_token_and_access_token/

認証情報の保持

hogehoge

SpringSecurity主要なコンポーネント(Javaのセキュリティ実装)

FilterChainProxy

フレームワーク処理の全体の流れを制御
具体的なセキュリティ対策処理は FilterChainに任せ

SecurityFilterChain

FilterChainProxyが受け取ったリクエストに対して適用する
デフォルトではDefaultSecurityFilterChainが適用 , リクエストパターンごとに SecurityFilterのリストを管理

SecurityFilter

サーブレットフィルタクラス
フレームワーク機能やセキュリティ対策機能を提供
複数のSecurityFilterと連鎖させてWebアプリのセキュリティ対策を行う仕組み

コアなクラス

HttpFirewall

HttpServletRequsetとHttpResponseに ファイアウォール機能を組み込む
デフォではDefaultHttpFirewallクラスが使われ、 ディレクトリトラバーサル攻撃や不正なリダイレクト先の指定によるHttpレスポンス分割攻撃のチェックが実装されている

GitEngHar commented 1 week ago

ディレクトリトラバーサル攻撃

アクセスを許可していないディレクトリにリンクを直指定して閲覧等をしようとすること

Httpレスポンス分割攻撃

https://securitychecklist.net/security/cyber-attack/HTTP-responce-splitting.html リクエストヘッダーの内容をユーザー入力しているシステムが攻撃対象
悪意のあるHTTPレスポンスを生成して、プロキシサーバにキャッシュさせる
Cookie盗難や、想定外のサイトへの遷移をさせられる

GitEngHar commented 15 hours ago

フロントエンドとの連携をどうしよう

GitEngHar commented 15 hours ago

今のままだと以下のような構成になるね image

GitEngHar commented 15 hours ago
GitEngHar commented 15 hours ago

ChatGPTへ壁打ち

フロントエンドで認証を行わず、すべての認証処理をバックエンドに委託する構成では、バックエンドでセキュアにGoogle OIDC認証を管理し、その結果をフロントエンドに反映させる方法が考えられます。この場合、認証情報のやり取りをセキュアに保つことが重要です。

セキュアな構成のポイント
このような構成では、以下のポイントに注意してセキュリティを強化できます。

1. バックエンドでの認証管理
すべての認証はバックエンドで行われ、フロントエンドはバックエンドから認証済みかどうかの情報を取得します。具体的には、以下の流れで構成できます。

ユーザーがバックエンドにアクセス
ユーザーがフロントエンドにアクセスし、特定の操作(ログインなど)を行うと、バックエンドがGoogle OIDCの認証をトリガーします。ユーザーはGoogleの認証ページにリダイレクトされ、Googleアカウントでのログインが行われます。

Googleからの認証レスポンスを受け取る
認証が成功すると、Googleが id_token と access_token をバックエンドに返します。バックエンドはこれを受け取り、トークンの検証(署名や有効期限、issuerの確認)を行います。

セッション管理 or JWT発行
トークンの検証が成功した後、バックエンドは認証されたセッションを開始するか、JWTを生成します。これにより、後続のリクエストにおいてユーザーを認証済みとして扱うことが可能になります。

セッションの場合:ユーザーに対応するセッションIDをサーバーサイドで管理し、HTTP-onlyクッキーを用いてフロントエンドに渡します。
JWTの場合:ユーザーに署名付きJWTを発行し、それをHTTP-onlyクッキーに保存します。
2. フロントエンドでの認証状態の管理
フロントエンドは認証処理を行いませんが、バックエンドからのレスポンスをもとにコンテンツの表示を制御します。具体的には以下の方法を使います。

バックエンドからの状態取得
フロントエンドは、バックエンドの認証APIに定期的に問い合わせるか、リダイレクト後にバックエンドから返された結果に基づいて、ユーザーが認証済みかどうかを確認します。認証が成功していない場合は、バックエンドが適切なリダイレクトを行うか、401 Unauthorizedなどのステータスコードを返します。

セッションやJWTのチェック
フロントエンドは認証情報(例えばHTTP-onlyクッキーに格納されたセッションIDやJWT)を利用して、認証済みユーザーにのみコンテンツを表示します。APIリクエストを行う際は、バックエンドで認証されているかを確認します。

3. APIリクエスト時のセキュリティ
バックエンドがユーザーの認証を管理しているため、フロントエンドからバックエンドに送られるAPIリクエストもセキュアにする必要があります。

HTTP-only Cookieでのトークン送信 認証情報(セッションIDまたはJWT)はHTTP-onlyクッキーに保存し、APIリクエスト時に自動的に送信されます。これにより、JavaScriptからトークンがアクセスされることを防ぎ、XSS攻撃のリスクを軽減します。

バックエンドでのトークン検証 各APIリクエストに対して、バックエンドは送信されたクッキー(セッションIDまたはJWT)を検証します。JWTを使用する場合、トークンの署名を確認し、有効期限や権限をチェックします。

4. 認可の実装
認証後のユーザーに対して、適切なアクセス権限を付与する必要があります。

Role-Based Access Control (RBAC) ユーザーごとに ROLE_USER や ROLE_ADMIN といったロールを付与し、APIリクエスト時にこれをチェックします。特定のエンドポイントにアクセスできるユーザーを制限し、不正アクセスを防ぎます。
5. CSRF保護
バックエンドがセッション管理を行っている場合、**CSRF(クロスサイトリクエストフォージェリ)**攻撃に対する対策も必要です。Spring Securityを利用してCSRFトークンを発行し、フロントエンドからのリクエストにこのトークンを含めるようにします。

6. 通信の暗号化
すべての通信はSSL/TLSで保護する必要があります。これにより、認証情報が第三者に盗まれるリスクを防ぎます。必ずHTTPSでの通信を使用し、TLS1.2以降の暗号化プロトコルを使うようにします。

構成フロー
フロントエンド(React)

ユーザーがページにアクセス
フロントエンドはAPIリクエストをバックエンドに送信(例えば、認証済みかどうかを確認)
バックエンド(Spring Security + Google OIDC)

ユーザーが未認証の場合、Google OIDCの認証ページにリダイレクト
Googleから id_token を受け取って検証
認証が成功したら、セッションIDまたはJWTを発行し、HTTP-onlyクッキーに保存
APIリクエスト時

フロントエンドはバックエンドにAPIリクエストを送信
クッキーに保存されたトークンを使ってバックエンドが認証を行い、アクセスを許可
このように、フロントエンドでは直接の認証処理を行わず、バックエンドでトークン管理と認証を行う構成は、セキュアかつ管理がしやすいアプローチです。

実現に必要な知識

JWTを理解してOIDCのIDtoken等を利用し、クライアントで認証情報を保てる ステートフルなWebアプリにしたい https://zenn.dev/mikakane/articles/tutorial_for_openid https://zenn.dev/mikakane/articles/tutorial_for_jwt

JWTを理解して OIDCとJWTの兼ね合いを理解する
JWTはCookieで保持しても問題ないので、クライアントで認証情報を取得し検証できる
認証できていない = Cookie に認証情報が存在しないか 認証情報がだたしくない 場合は バックエンドの認証へリダイレクトさせる