재우니의 블로그

 

ASP.NET MVC 구현할 때, POST 로 전송시, anti-forgery token 을 함께 전송하는 방법을 찾아봤습니다. jQuery  버전은 3.5.1 버전이며, ajax 통신을 통해 전송하였습니다.

 

 

form 태그 안에 token 값을 생성합니다.

@Html.Partial("_AntiForgeryTokens")

 

jQuery 를 이용하여 token 값을 header 에 __RequestVerificationToken 를 키로 하여 토큰 값과 함께 전송합니다. 

var token = $('input[name="__RequestVerificationToken"]', $('#frm')).val();

if (window.confirm("1:1문의 요청하시겠습니까?")) {

    $.ajax({
        url: '@Url.Action("WriteSend", "QNA")',
        headers: { '__RequestVerificationToken': token },
        type: 'post',
        dataType: 'json', //json으로 응답받을 때
        contentType: 'application/json; charset=utf-8',
        data: '{ p: "' + GetJsonToEncParam(requJson) + '", contents: "' + contents + '" }',
        success: function (result) {

            if (result.success) {

                $('html').scrollTop(0);

                $("form").each(function () {
                    if (this.id == "frm") this.reset();
                });
                $(".qnafrm").hide();
                $(".qnaConfirm").show();
            }
            else {
                alert(result.msg);
            }
        },
        error: function (xhr, status, error) {
            console.log(xhr, status, error);
            console.log("error");
        }
    });
}

 

보통은 [ValidateAntiForgeryToken] 를 사용하여 토큰 값이 존재하는지 또는 검증을 확인해 줍니다. 하지만, 이상하게도 전송은 하였지만 받아지지 않고 오류가 발생됩니다.

[HttpPost]
[ValidateInput(false)]
[ValidateAntiForgeryToken]
public ActionResult WriteSend(string p, string contents)
{
	//구문 기술...
}

 

이를 해결하기 위해서 [ValidateAntiForgeryToken] 를 사용하지 않고 별도로 어트리뷰트를 만듭니다.

어트리뷰트 이름은 [ValidateHeaderAntiForgeryToken] 으로 하였습니다. 

 

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public sealed class ValidateHeaderAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            var httpContext = filterContext.HttpContext;
            var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
            AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
        }
    }

 

직접 커스텀한 어트리뷰트를 컨트롤러에 적용해 봤습니다.

[HttpPost]
[ValidateInput(false)]
//[ValidateAntiForgeryToken]
[ValidateHeaderAntiForgeryToken]
public ActionResult WriteSend(string p, string contents)
{
	//구문 기술...
}

 

테스트 검증 한 결과 문제 없이 통과 되어 오류 없이 처리가 되었습니다.

 

도움 받은 stackoverflow 사이트는 아래 제공해 드립니다.

 

참고 사이트

 

https://stackoverflow.com/a/46468504

 

__RequestVerificationToken is not present with Ajax POST

I'm using jQuery DataTales to request a POST URL from MVC5 and trying to add an anti-forgery token. I've added it to both the headers and also the request body, but still get a 500 error: "The requ...

stackoverflow.com

 

https://stackoverflow.com/questions/33306859/the-required-anti-forgery-cookie-requestverificationtoken-is-not-present?rq=1 

 

The required anti-forgery cookie "__RequestVerificationToken" is not present

My website is raising this exception around 20 times a day, usually the form works fine but there are instances where this issue occur and I don't know why is so random. This is logged exception by

stackoverflow.com

 


 

jQuery 로 post submit 전송 할 경우

form 의 post submit 전송시에는 [ValidateAntiForgeryToken] 이슈없이 작동 잘됩니다.

다시 말하면, jQuery 가 아닌 일반적인 form 의 post submit 전송시에는 이슈없이 ValidateAntiForgeryToken 작동이 잘됩니다.

@using (Html.BeginForm("RegisterSave", Controllers, FormMethod.Post, new { id = "form1", name = "form1" }))
{
    @Html.Partial("_AntiForgeryTokens")
    @Html.Hidden("p", "")
    
    <a id="btnSave" href="jvascript:void(0);" class="cmn-ev-form-applybtn chlg-apply-btn gfw500 fs26 orange">이벤트 응모하기</a>
}    

 

$("#btnSave").click(function (e) {
	e.preventDefault();
    
    if (window.confirm("are you send?")) {
    	$("#form1").submit();
    }
}

$('form').submit(function (e) {
  var formJson = $(this).serializeFormJSON();
  $("#p").val(GetJsonToEncParam(formJson));
});

 

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult RegisterSave(string p)
{
	return Content(@"<script>alert(' 참여해 주셔서 감사합니다.');location.href='/';</script>");
}    

 


 

그리고 ValidateAntiForgeryToken 를 사용하기 위해서는 HTTPS 즉 SSL 형태이어야 하며, HTTPS 로 접속하여 확인하셔야 합니다. http 접속 경로인데 아래와 같이 requiredSSL 을 true 로 할 경우 위와 같이 문제가 발생될 수 도 있으니 http 환경에서는 false 로 셋팅이 되어 있어야 겠습니다.

 

- web.config 파일 내부

<httpCookies requireSSL="true"/>