ASP.NET Core でオープン リダイレクト攻撃を防止する

クエリ文字列やフォーム データなどの要求によって指定される URL へのリダイレクトを行う Web アプリは、ユーザーを外部の悪意ある URL にリダイレクトするために改ざんされる可能性があります。 この改ざんは、オープン リダイレクト攻撃と呼ばれています。

アプリケーション ロジックによって、指定された URL へのリダイレクトが行われるたびに、リダイレクト URL が改ざんされていないことを検証する必要があります。 ASP.NET Core には、オープン リダイレクト攻撃からアプリを保護する助けとなる組み込み機能が備わっています。

オープン リダイレクト攻撃とは

ユーザーは、認証を必要とするリソースにアクセスするときに、Web アプリケーションによって頻繁にログイン ページにリダイレクトされます。 このリダイレクトには通常、ユーザーが当初要求した URL に、正しくログインした後に戻ることができるように、returnUrl クエリ文字列パラメーターが含まれています。 ユーザーは認証後に、当初要求した URL にリダイレクトされます。

宛先 URL は要求のクエリ文字列内に指定されているため、悪意のあるユーザーがクエリ文字列を改ざんする可能性があります。 改ざんされたクエリ文字列により、サイトではユーザーを外部の悪意のあるサイトにリダイレクトできる場合があります。 この手法は、オープン リダイレクト攻撃と呼ばれます。

攻撃の例

悪意のあるユーザーは、自分がユーザーの資格情報や機密情報にアクセスできるようにすることを意図した攻撃を開始できます。 攻撃を開始するため、悪意のあるユーザーは、ユーザーがサイトのログイン ページへのリンクをクリックするよう仕向けます。このページの URL には returnUrl クエリ文字列値が追加されています。 たとえば、http://contoso.com/Account/LogOn?returnUrl=/Home/About にログイン ページが含まれている、contoso.com にあるアプリについて考えてみます。 攻撃は以下の手順をたどります。

  1. ユーザーが、悪意のある http://contoso.com/Account/LogOn?returnUrl=http://contoso1.com/Account/LogOn へのリンクをクリックします (2 番目の URL は "contoso.com" ではなく "contoso1.com" です)。
  2. ユーザーは正常にログインします。
  3. ユーザーは (サイトによって) http://contoso1.com/Account/LogOn (本物のサイトとまったく同じように見える悪意のあるサイト) にリダイレクトされます。
  4. ユーザーは、もう一度ログインして (自分の資格情報を悪意のあるサイトに提供し)、本物のサイトにリダイレクトされます。

ユーザーはおそらく、最初のログイン試行が失敗し、2 回目の試行が成功したと考えます。 自分の資格情報が侵害されたことに気付かないままでいるユーザーが大半です。

Open Redirection Attack Process

ログイン ページに加えて、一部のサイトでは、リダイレクト ページやエンドポイントが提供されます。 アプリに、オープン リダイレクト /Home/Redirect が含まれるページがあると考えてください。 攻撃者は、たとえばメール内に、[yoursite]/Home/Redirect?url=http://phishingsite.com/Home/Login に移動するリンクを作成できます。 一般的なユーザーは、URL を見て、それがサイト名で始まっていることを確認します。 それを信頼して、リンクをクリックすることになります。 次にユーザーは、オープン リダイレクトによって、実際のサイトと同じに見えるフィッシング サイトに送られます。ユーザーはおそらく、いつものサイトであると信じてログインすることになります。

オープン リダイレクト攻撃からの保護

Web アプリケーションの開発時には、ユーザーが指定したデータはすべて、信頼できないものとして扱います。 アプリケーションに、URL の内容に基づいてユーザーをリダイレクトする機能がある場合は、そのようなリダイレクトが、ローカルに、アプリ内でのみ (または、クエリ文字列で指定されている可能性がある URL ではなく、既知の URL に対してのみ) 実行されるようにします。

LocalRedirect

基本クラス ControllerLocalRedirect ヘルパー メソッドを使用します。

public IActionResult SomeAction(string redirectUrl)
{
    return LocalRedirect(redirectUrl);
}

ローカルでない URL が指定されている場合は、LocalRedirect によって例外がスローされます。 その他の場合の動作は、Redirect メソッドとまったく同じです。

IsLocalUrl

リダイレクトの前に URL をテストするには、IsLocalUrl メソッドを使用します。

次の例は、リダイレクトの前に URL がローカルかどうかを確認する方法を示しています。

private IActionResult RedirectToLocal(string returnUrl)
{
    if (Url.IsLocalUrl(returnUrl))
    {
        return Redirect(returnUrl);
    }
    else
    {
        return RedirectToAction(nameof(HomeController.Index), "Home");
    }
}

IsLocalUrl メソッドは、ユーザーが誤って悪意のあるサイトにリダイレクトされることを防止します。 ローカル URL が予期される状況で、ローカルでない URL が指定された場合に、指定された URL の詳細をログに記録できます。 リダイレクト URL をログに記録すると、リダイレクト攻撃の診断時に役立つ場合があります。