ASP.NET Core 오픈 리디렉션 공격 방지

querystring 또는 양식 데이터와 같은 요청을 통해 지정된 URL로 리디렉션되는 웹앱은 잠재적으로 변조되어 사용자를 악의적인 외부 URL로 리디렉션할 수 있습니다. 이 변조를 오픈 리디렉션 공격이라고 합니다.

애플리케이션 논리가 지정된 URL로 리디렉션될 때마다 리디렉션 URL이 변조되지 않았는지 확인해야 합니다. ASP.NET Core에는 오픈 리디렉션 공격으로부터 앱을 보호하는 데 도움이 되는 기본 제공 기능이 있습니다.

오픈 리디렉션 공격이란?

웹 애플리케이션은 인증이 필요한 리소스에 액세스할 때 사용자를 로그인 페이지로 리디렉션하는 경우가 많습니다. 리디렉션에는 일반적으로 returnUrl querystring 매개 변수가 포함되어 있으므로 사용자가 성공적으로 로그인한 후 원래 요청된 URL로 돌아갈 수 있습니다. 사용자가 인증하면 원래 요청한 URL로 리디렉션됩니다.

대상 URL은 요청의 querystring에 지정되므로 악의적인 사용자가 querystring을 변조할 수 있습니다. 변조된 querystring을 사용하면 사이트에서 사용자를 외부 악성 사이트로 리디렉션할 수 있습니다. 이 기술을 오픈 리디렉션 공격이라고 합니다.

예제 공격

악의적인 사용자는 악의적인 사용자가 사용자의 자격 증명 또는 중요한 정보에 액세스할 수 있도록 하기 위한 공격을 개발할 수 있습니다. 공격을 시작하려면 악의적인 사용자가 URL에 추가된 returnUrl querystring 값이 있는 사이트의 로그인 페이지에 대한 링크를 클릭하도록 사용자를 유도합니다. 예를 들어 http://contoso.com/Account/LogOn?returnUrl=/Home/About의 로그인 페이지가 포함된 contoso.com의 앱을 생각해 보겠습니다. 공격은 다음 단계를 따릅니다.

  1. 사용자가 http://contoso.com/Account/LogOn?returnUrl=http://contoso1.com/Account/LogOn에 대한 악의적인 링크를 클릭합니다.(두 번째 URL은 "contoso.com"이 아니라 "contoso1.com"입니다.)
  2. 사용자가 성공적으로 로그인합니다.
  3. 사용자가 (사이트에 의해) http://contoso1.com/Account/LogOn(실제 사이트와 정확히 같은 악성 사이트)으로 리디렉션됩니다.
  4. 사용자가 다시 로그인하고(악성 사이트에 자격 증명 제공) 실제 사이트로 다시 리디렉션됩니다.

사용자는 첫 번째 로그인 시도가 실패했으며 두 번째 시도가 성공했다고 판단할 수 있습니다. 사용자는 자격 증명이 손상되었다는 사실을 인식하지 못할 가능성이 높습니다.

Open Redirection Attack Process

일부 사이트에서는 로그인 페이지 외에도 리디렉션 페이지 또는 엔드포인트를 제공합니다. 앱에 오픈 리디렉션, /Home/Redirect가 있는 페이지가 있다고 가정해 보겠습니다. 예를 들어 공격자가 [yoursite]/Home/Redirect?url=http://phishingsite.com/Home/Login으로 전송되는 이메일의 링크를 만들 수 있습니다. 일반적인 사용자는 URL을 살펴보고 사이트 이름으로 시작하는 것을 확인합니다. 신뢰하면 링크를 클릭합니다. 그러면 오픈 리디렉션이 사용자를 사용자의 사이트와 동일해 보이는 피싱 사이트로 보내고, 사용자는 사용자의 사이트라고 생각하는 것에 로그인할 가능성이 높습니다.

오픈 리디렉션 공격으로부터 보호

웹 애플리케이션을 개발할 때는 사용자가 제공한 모든 데이터를 신뢰할 수 없는 데이터로 처리합니다. 애플리케이션에 URL의 콘텐츠에 따라 사용자를 리디렉션하는 기능이 있는 경우 이러한 리디렉션은 앱 내에서 로컬로만(또는 querystring에 제공될 수 있는 URL이 아닌 알려진 URL로) 수행되는지 확인합니다.

LocalRedirect

기본 Controller 클래스의 LocalRedirect 도우미 메서드를 사용합니다.

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

LocalRedirect는 로컬이 아닌 URL이 지정된 경우 예외를 throw합니다. 그렇지 않으면 Redirect 메서드처럼 동작합니다.

IsLocalUrl

IsLocalUrl 리디렉션하기 전에 이 메서드를 사용하여 URL을 테스트합니다.

다음 예제에서는 리디렉션하기 전에 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 로깅은 리디렉션 공격을 진단하는 데 도움이 될 수 있습니다.