수색…


소개

위조 방지 토큰은 사이트 간 요청 위조로부터 응용 프로그램을 보호하는 데 사용할 수 있습니다. 이 기능을 사용하려면 양식에서 AntiForgeryToken 메서드를 호출하고 보호 할 작업 메서드에 ValidateAntiForgeryTokenAttribute 특성을 추가합니다.

양식을 제출할 때 유효성을 검사하는 숨겨진 양식 필드 (위조 토큰)를 생성합니다.

통사론

  • @ Html.AntiForgeryToken ()

비고

CSRF 토큰 ( __RequestVerificationToken )을 사용하여 ajax 요청을 제출할 때 콘텐츠 유형이 application/json 설정되어 있지 않은지 확인하십시오. jQuery를 사용하는 경우 자동으로 컨텐츠 유형을 application/x-www-form-urlencoded 합니다. 그러면 ASP.NET MVC에서이를 인식합니다.

주의

이 값을 설정할 때는주의하십시오. 부적절하게 사용하면 응용 프로그램의 보안 취약점을 열 수 있습니다.

기본 사용법

@Html.AntiForgeryToken() 도우미 메서드는 사이트 간 요청 위조 (또는 CSRF) 공격으로부터 보호합니다.

기존 폼 중 하나에서 Html.AntiForgeryToken() 도우미를 사용하고 [ValidateAntiForgeryToken] 특성을 사용하여 해당 컨트롤러 액션을 Html.AntiForgeryToken() 사용할 수 있습니다.

면도기 (YourView.cshtml)

@using (Html.BeginForm("Manage", "Account")) {
    @Html.AntiForgeryToken()  
    <!-- ... -->
}

또는

<form>
    @Html.AntiForgeryToken()
    <!-- ... -->
</form>

컨트롤러 (YourController.cs)

목표 동작 방법 :

[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult ActionMethod(ModelObject model)
{
    // ...
}

ID 휴리스틱 검사 비활성화

종종 예외가 표시됩니다.

Anti forgery token is meant for user "" but the current user is "username"

이는 위조 토큰이 현재 로그인 한 사용자와 연결되어 있기 때문입니다. 이 오류는 사용자가 로그인했지만 토큰이 사이트의 익명 사용자로 계속 링크되어있을 때 나타납니다.

이 동작을 해결할 수있는 몇 가지 방법이 있지만 사용자의 로그인 상태에 CSRF 토큰을 연결하지 않으려면이 기능을 비활성화해야합니다.

Global.asax 파일 또는 이와 유사한 응용 프로그램 시작 논리에이 행을 입력하십시오.

AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;

모든 게시물의 유효성 검사

CSRF에 의해 야기 된 취약점으로 인해 일반적으로 모든 HttpPosts에 대해 AntiForgeryToken을 확인하는 것이 좋은 방법으로 간주됩니다 (게시물에 기술적 인 문제가 있거나 다른 인증 메커니즘 및 / 또는 게시물은 db 또는 파일에 저장하는 것과 같이 상태를 변경하지 않습니다.) 잊지 않도록 특별한 "ignore"속성으로 동작을 장식하지 않는 한 모든 HttpPost를 자동으로 확인하는 특수 GlobalActionFilter를 추가 할 수 있습니다.

[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            bool skipCheck = filterContext.ActionDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true)
                || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(DontCheckForAntiForgeryTokenAttribute), true);

            if (skipCheck)
                return;


            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

/// <summary>
/// this should ONLY be used on POSTS that DO NOT MUTATE STATE
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class DontCheckForAntiForgeryTokenAttribute : Attribute { }

모든 요청에 ​​대해 확인되도록하려면 글로벌 액션 필터에 추가하십시오.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //...
        filters.Add(new ValidateAntiForgeryTokenOnAllPosts());
        //...
    }
}

사전 사용 : 모든 POST에 대해 기본 Antiforgery 필터 적용

POST 요청에 Antiforgery attribute 을 적용하는 것을 Antiforgery attribute 기본적으로 만들어야합니다. 이 샘플은 Antiforgery filter 가 항상 모든 POST 요청에 적용되는지 확인 POST .

먼저 새로운 AntiForgeryTokenFilter 필터를 만듭니다.

//This will add ValidateAntiForgeryToken Attribute to all HttpPost action methods
public class AntiForgeryTokenFilter : IFilterProvider
{
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        List<Filter> result = new List<Filter>();

        string incomingVerb = controllerContext.HttpContext.Request.HttpMethod;

        if (String.Equals(incomingVerb, "POST", StringComparison.OrdinalIgnoreCase))
        {
            result.Add(new Filter(new ValidateAntiForgeryTokenAttribute(), FilterScope.Global, null));
        }

        return result;
    }
}

그런 다음이 사용자 정의 필터를 MVC, Application_Start에 등록하십시오.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {    
        //Cactch generic error
        filters.Add(new HandleErrorAttribute());

        //Anti forgery token hack for every post request
        FilterProviders.Providers.Add(new AntiForgeryTokenFilter());            
    }
}  



public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

이제 모든 POST 요청은 Antiforgery 속성을 사용하여 기본적으로 보호되므로 각 POST 메소드에 [ValidateAntiForgeryToken] 속성이 더 이상 필요하지 않습니다.

Jquery Ajax 요청과 함께 AntiForgeryToken 사용하기

먼저 양식을 만듭니다.

@using (Html.BeginForm())
{
  @Html.AntiForgeryToken()
}

액션 메소드

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Test(FormViewModel formData)
{
    // ...
}

스크립트

<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
var formData = new FormData($('form')[0]);
$.ajax({
    method: "POST",
    url: "/demo/test",
    data: formData ,
    success: function (data) {
  console.log(data);
    },
    error: function (jqXHR, textStatus, errorThrown) {
        console.log(errorThrown);
    }
})
</script>

contentType이 application/x-www-form-urlencoded 이외의 항목으로 설정되지 않았는지 확인하십시오. 지정된 Jquery의 기본값이 application/x-www-form-urlencoded



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow