オープンリダイレクト

未検証のユーザー指定URLへの移動は、フィッシングや認証処理の悪用につながるおそれがあります。

説明

オープンリダイレクトは、ユーザーが送ったURLを検証せず、redirectやsendRedirectなどの移動応答に使う場合に起こります。正規ドメインで始まるリンクに見えても、実際には外部のフィッシングサイトや悪意のあるダウンロードページへ移動する可能性があります。

ログイン後の移動先、OAuthコールバック後のreturnUrl、決済完了後のページなどで発生しやすい問題です。

想定される影響

  • 信頼されるサービスのURLを使ったフィッシング
  • 未検証のリダイレクトを信頼する認証処理でのトークン漏えいやセッションの窃取
  • 悪意のあるファイルのダウンロードや脆弱な外部サイトへの誘導
  • 許可されたドメインを経由するリダイレクトによるフィルターの回避

対処方法

  • 移動先を、サーバーが管理する許可リストのパスやドメインに制限してください。
  • URL全体を受け取る代わりに、next=profileのような固定識別子をサーバーで実際のパスへ対応付けてください。
  • 外部URLが必要なら、スキーム、ホスト、ポート、正規化結果を確認し、httpsだけを許可してください。
  • startsWithやcontainsだけで信頼しないでください。https://trusted.example.com.evil.exampleのような値で回避されるおそれがあります。
  • 未許可の値は拒否するか、安全な既定パスへ移動させてください。

例

Springコントローラーの抜粋です。必要なimportとアプリケーションの内部ルート定義は省略しています。

変更前

java
@GetMapping("/login/success")
public void loginSuccess(
    @RequestParam("next") String next,
    HttpServletResponse response
) throws IOException {
    response.sendRedirect(next);
}

変更後

java
private static final Map<String, String> ALLOWED_REDIRECTS = Map.of(
    "profile", "/account/profile",
    "orders", "/account/orders"
);

@GetMapping("/login/success")
public void loginSuccess(
    @RequestParam(value = "next", defaultValue = "profile") String next,
    HttpServletResponse response
) throws IOException {
    String redirectPath = ALLOWED_REDIRECTS.getOrDefault(next, "/account/profile");
    response.sendRedirect(redirectPath);
}

説明:

  • 変更前: リクエストパラメーターのURLへそのまま移動します。正規サービスのリンクをクリックしても、外部サイトへ誘導される可能性があります。
  • 変更後: 入力をURLではなくサーバーが把握する識別子として扱います。許可リストにない値には、安全な既定パスを使います。

参考資料