jQuery Ajax 호출과 Html.AntiForgeryToken ()


207

내 앱에서 CSRF 공격에 대한 완화를 구현했습니다.인터넷에서 블로그 게시물에서 읽은 정보에 따라 . 특히이 게시물은 내 구현의 동인이었습니다.

기본적으로 이러한 기사와 권장 사항에 따르면 CSRF 공격을 방지하려면 다음 코드를 구현해야합니다.

1) [ValidateAntiForgeryToken]POST Http 동사를 허용하는 모든 작업을 추가하십시오 .

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}

2) <%= Html.AntiForgeryToken() %>서버에 데이터를 제출하는 양식 안에 도우미를 추가하십시오.

<div style="text-align:right; padding: 8px;">
    <%= Html.AntiForgeryToken() %>
    <input type="submit" id="btnSave" value="Save" />
</div>

어쨌든 내 응용 프로그램의 일부 부분에서는 jQuery와 함께 Ajax POST를 서버에 전혀 양식을 작성하지 않고 서버에 수행하고 있습니다. 예를 들어 사용자가 이미지를 클릭하여 특정 작업을 수행 할 수있게합니다.

활동 목록이있는 테이블이 있다고 가정하십시오. 표의 열에 "활동 완료로 표시"라는 이미지가 있으며 사용자가 해당 활동을 클릭하면 다음 샘플과 같이 Ajax POST를 수행합니다.

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {},
        success: function (response) {
            // ....
        }
    });
});

<%= Html.AntiForgeryToken() %>이 경우 어떻게 사용할 수 있습니까? Ajax 호출의 data 매개 변수 안에 도우미 호출을 포함시켜야합니까?

긴 게시물에 대해 죄송합니다. 도와 주셔서 대단히 감사합니다.

편집 :

당으로 jayrdub 대답 나는 다음과 같은 방법으로 사용했다

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {
            AddAntiForgeryToken({}),
            id: parseInt($(this).attr("title"))
        },
        success: function (response) {
            // ....
        }
    });
});

데이비드 헤이든 링크는 지금 404은, 그가 새로운 CMS에 자신의 블로그를 마이그레이션,하지만 온통 기존의 컨텐츠를 마이그레이션하지 않은 것으로 보인다.

답변:


252

나는 이와 같은 간단한 js 함수를 사용한다

AddAntiForgeryToken = function(data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
};

페이지의 모든 양식은 토큰에 대해 동일한 값을 가지므로 최상위 마스터 페이지에 이와 같은 것을 넣으십시오.

<%-- used for ajax in AddAntiForgeryToken() --%>
<form id="__AjaxAntiForgeryForm" action="#" method="post"><%= Html.AntiForgeryToken()%></form>  

그런 다음 아약스 호출에서 (두 번째 예제와 일치하도록 편집)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});

6
좋아, 나는 토큰 가져 오기의 캡슐화를 좋아한다.
jball

2
@Lorenzo, 다음 AddAntiForgeryToken과 같이 호출에 사용자 정의 데이터를 넣습니다 .data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
jball

3
위조 방지 토큰 으로 항상 기능을 보강하기 위해 사용 ajaxSend하거나 재정의 하는 것이 얼마나 나쁜 생각 입니까? 서버에 적합한 지 확인하기 위해 약간의 검사를 추가 할 수 있습니다. ajaxdataurl
ta.speot.은 (는)

1
출력 캐시를 사용하는 경우주의하십시오.
Barbaros Alp

1
@SouhaiebBesbes 유효성 검사 토큰은 모든 페이지에서 사용자에 대해 동일해야합니다 (설정되어 있고 동일하게 유지되는 쿠키와 함께 작동 함). 따라서 페이지 당 여러 개의 요청이 있는지 여부는 중요하지 않으며, 기본 페이지가 다시로드 된 경우에도 동일합니다.
JeremyWeir

29

360Airwalk에서 제공하는 솔루션이 마음에 들지만 조금 개선 될 수 있습니다.

첫 번째 문제는 $.post()빈 데이터로 만들면 jQuery가 Content-Type헤더를 추가하지 않으며이 경우 ASP.NET MVC가 토큰을 수신 및 확인하지 못한다는 것입니다. 따라서 헤더가 항상 있어야합니다.

또 다른 개선 사항은 POST, PUT, DELETE 등 컨텐츠 가 포함 된 모든 HTTP 동사 지원하는 것입니다 . 애플리케이션에서 POST 만 사용할 수 있지만 일반적인 솔루션을 사용하고 동사로 수신 한 모든 데이터에 위조 방지 기능이 있는지 확인하는 것이 좋습니다. 토큰.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content
            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
            // ensure Content-Type header is present!
            if (opt.contentType !== false || event.contentType) {
                request.setRequestHeader( "Content-Type", opt.contentType);
            }
        }
    });
});

1
+1 당신 말이 맞아요, 빈 포스트 콜 문제는 생각하지 못했습니다. 입력 주셔서 감사합니다. 귀하는 프로젝트에서 아직 삭제 / 입력을 사용하지 않는다는 것에 대해 옳았습니다.
360Airwalk

2
모든 jQuery.Ajax 호출에 기능을 추가 할 필요에서 저를 저장하기위한 한
드라고 Durlut을

2
+1 후손에 대한 메모와 .ajaxSend()마찬가지로, "jQuery 1.8부터 .ajaxSend () 메소드는 문서에만 첨부해야합니다."상태에 대한 jQuery 문서입니다 . api.jquery.com/ajaxsend
RJ Cuthbertson

1
@Bronx 어디에서 optionsif습니까? 감사.
hvaughan3

한 페이지에 여러 양식이있는 경우이를 사용하십시오. 문서 대신에보다 구체적인 선택기 호출로 beforeSend에서 값을 설정해야합니다.
Dan

22

다른 답변이 많이 있다는 것을 알고 있지만이 기사는 훌륭하고 간결하며 일부 HttpPosts를 확인하지 않아도됩니다.

http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

양식 모음을 수정하지 않고 HTTP 헤더를 사용합니다.

섬기는 사람

//make sure to add this to your global action filters
[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)
        {
            //  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);
            }
        }
    }
}

고객

var token = $('[name=__RequestVerificationToken]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;

$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: headers,
    contentType: 'application/json; charset=utf-8',
    data: { title: "This is my title", contents: "These are my contents" },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});

4
브롱크스의 응답 과 결합한 기사의 속성은 이 문제에 대한 궁극적 인 DRY 솔루션입니다.
TugboatCaptain

2
좋은 발견. 코드 스 니펫을 포함하도록 답변을 편집 했으므로 답변 자체가 그대로 유지되지만 사람들이 기사의 나머지 부분도 읽을 수 있기를 바랍니다. 이것은 매우 깨끗한 솔루션으로 보입니다.
Tim Medora

고마워 팀, 그것은 훌륭한 아이디어입니다, 링크가 죽을 때 답답하고 대답은 가치가 없어집니다. 나는 모든 새로운 대답에서 이것을 시작했습니다.
viggity

이 MVC, WebAPI 또는 .NetCore입니까? 나는 WebAPI 5에 대한 올바른 네임 스페이스를 얻을 수
Myster

20

고급 네크로맨서 인 것 같지만 4 년 후에도 MVC5에서 여전히 문제가됩니다.

Ajax 요청을 올바르게 처리하려면 Ajax 호출시 위조 방지 토큰을 서버로 전달해야합니다. 이를 포스트 데이터 및 모델에 통합하는 것은 복잡하고 불필요합니다. 토큰을 사용자 정의 헤더로 추가하는 것은 깨끗하고 재사용이 가능하며 매번 기억할 필요가 없도록 구성 할 수 있습니다.

예외가 있습니다-눈에 거슬리지 않는 아약스는 아약스 호출에 대한 특별한 치료가 필요하지 않습니다. 토큰은 일반적인 숨겨진 입력 필드에서 평소와 같이 전달됩니다. 일반 POST와 정확히 동일합니다.

_Layout.cshtml

_layout.cshtml에는이 JavaScript 블록이 있습니다. DOM에 토큰을 쓰지 않고 MVC Helper가 생성하는 숨겨진 입력 리터럴에서 jQuery를 사용하여 토큰을 추출합니다. 헤더 이름 인 Magic 문자열은 속성 클래스에서 상수로 정의됩니다.

<script type="text/javascript">
    $(document).ready(function () {
        var isAbsoluteURI = new RegExp('^(?:[a-z]+:)?//', 'i');
        //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative

        $.ajaxSetup({
            beforeSend: function (xhr) {
                if (!isAbsoluteURI.test(this.url)) {
                    //only add header to relative URLs
                    xhr.setRequestHeader(
                       '@.ValidateAntiForgeryTokenOnAllPosts.HTTP_HEADER_NAME', 
                       $('@Html.AntiForgeryToken()').val()
                    );
                }
            }
        });
    });
</script>

beforeSend 함수에서 작은 따옴표를 사용하십시오. 렌더링되는 입력 요소는 큰 따옴표를 사용하여 JavaScript 리터럴을 손상시킵니다.

클라이언트 JavaScript

이것이 실행되면 위의 beforeSend 함수가 호출되고 AntiForgeryToken이 요청 헤더에 자동으로 추가됩니다.

$.ajax({
  type: "POST",
  url: "CSRFProtectedMethod",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  success: function (data) {
    //victory
  }
});

서버 라이브러리

비표준 토큰을 처리하려면 사용자 정의 속성이 필요합니다. 이것은 @viggity의 솔루션을 기반으로하지만 눈에 띄지 않는 아약스를 올바르게 처리합니다. 이 코드는 공용 라이브러리에 넣을 수 있습니다

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public const string HTTP_HEADER_NAME = "x-RequestVerificationToken";

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {

            var headerTokenValue = request.Headers[HTTP_HEADER_NAME];

            // Ajax POSTs using jquery have a header set that defines the token.
            // However using unobtrusive ajax the token is still submitted normally in the form.
            // if the header is present then use it, else fall back to processing the form like normal
            if (headerTokenValue != null)
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

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

                AntiForgery.Validate(cookieValue, headerTokenValue);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

서버 / 컨트롤러

이제 액션에 속성을 적용하기 만하면됩니다. 또한 컨트롤러에 속성을 적용하면 모든 요청이 확인됩니다.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}

더욱 중앙 집중화 된 완벽한 솔루션. 감사합니다
David Freire

상대 URL의 헤더 만 추가하려는 이유를 더 자세히 설명 할 수 있습니까? 그것은 내 머리 위로 갔다. 훌륭한 솔루션!
MattM

relative는 ajax 설정이 jquery로 작성된 모든 요청을 다루기 때문에 헤더가 자신의 서버로 돌아가는 요청에만 설정되도록 보장합니다. 토큰은 jsonp 또는 CORS 요청으로 전송되지 않습니다. 절대 URL의 경우에도 마찬가지이지만 상대적은 동일한 도메인이어야합니다.
윌 D

1
@ WillD 나는 당신의 솔루션을 좋아했지만 조금 수정해야했습니다. $.ajaxSetup일반 beforesend이벤트 핸들러 를 정의 하도록 선택했기 때문에 이를 덮어 쓰게 될 수 있습니다. 두 번째 핸들러를 추가 할 수있는 다른 솔루션을 찾았습니다 . 잘 작동하고 구현을 중단하지 않습니다.
Viper

ASP.net 5 버전의 고객이 AntiForgery 특성을 검증 한 사람이 있습니까? 이 버전은 최신 버전으로 컴파일되지 않습니다!
Rob McCabe

19

Html.AntiForgeryToken을 사용하지 마십시오 . 대신 ASP.NET MVC 응용 프로그램에서 CSRF (Cross-Site Request Forgery) 공격 방지에 설명 된대로 웹 API에서 AntiForgery.GetTokensAntiForgery.Validate 를 사용 하십시오 .


서버 모델 유형을 게시 된 AJAX JSON에 바인딩하는 컨트롤러 조치 메소드의 경우, 올바른 모델 바인더를 사용하려면 컨텐츠 유형이 "application / json"이어야합니다. 불행히도이 방법은 [ValidateAntiForgeryToken] 속성에 필요한 양식 데이터를 사용할 수 없으므로 메서드를 사용하는 유일한 방법입니다. 내 유일한 질문은 웹 팜 또는 여러 Azure 웹 역할 인스턴스에서 여전히 작동합니까? @Edward 또는 다른 사람이 이것이 문제인지 알고 있습니까?
Richard B

@Edward Brey 왜 사용하지 말아야하는지 자세히 설명해 주시겠습니까?
Odys

4
@Odys : Html.AntiForgeryToken에는 본질적으로 잘못된 것이 없지만 단점이 있습니다. 양식이 필요하고 jQuery가 필요하며 문서화되지 않은 Html.AntiForgeryToken 구현 세부 사항이 있다고 가정합니다. 그럼에도 불구하고 많은 상황에서 괜찮습니다. "Html.AntiForgeryToken을 사용하지 마십시오"라는 문구가 너무 강하게 나타납니다. 내 의미는 더 유연한 AntiForgery.GetTokens 인 반면 웹 API와 함께 사용하기위한 것이 아닙니다.
Edward Brey

고마워! MVC5 컨트롤러에서 작동하도록 약간 변경해야했지만 이것이 해결책이었습니다
jao

3
반드시 양식이 필요하지 않습니다. 이름으로 DOM을 구문 분석하면됩니다. jquery를 사용하여 데이터 {__RequestVerificationToken : $ ( "input [name = __ RequestVerificationToken]"). val ()}을 통해 데이터 객체 내에 추가 할 수 있습니다.
Anthony Mason

16

나는 현재 프로젝트 에서이 실제 문제를 구현하고있었습니다. 인증 된 사용자가 필요한 모든 ajax-POST에 대해 수행했습니다.

먼저 jquery ajax 호출을 연결하여 너무 자주 반복하지 않기로 결정했습니다. 이 자바 스크립트 스 니펫은 모든 아약스 (포스트) 호출이 요청에 내 요청 유효성 검사 토큰을 추가하도록합니다. 참고 : __RequestVerificationToken이라는 이름은 .Net 프레임 워크에서 사용되므로 아래 표시된 것처럼 표준 Anti-CSRF 기능을 활용할 수 있습니다.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

위의 자바 스크립트에서 토큰을 사용할 수 있어야하는 뷰에서 일반적인 HTML 도우미를 사용하십시오. 기본적으로이 코드를 원하는 곳에 추가 할 수 있습니다. if (Request.IsAuthenticated) 문 내에 배치했습니다.

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

컨트롤러에서 단순히 표준 ASP.Net MVC Anti-CSRF 메커니즘을 사용하십시오. 나는 이것을 실제로했다 (실제로 소금을 사용했지만).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

Firebug 또는 이와 유사한 도구를 사용하면 POST 요청에 __RequestVerificationToken 매개 변수가 추가 된 방법을 쉽게 확인할 수 있습니다.


15

"__RequestVerificationToken"입력이 POST 요청에 포함되어 있는지 확인하기 만하면됩니다. 정보의 나머지 절반 (즉, 사용자 쿠키의 토큰)은 이미 AJAX POST 요청과 함께 자동으로 전송됩니다.

예 :

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: { 
            "__RequestVerificationToken":
            $("input[name=__RequestVerificationToken]").val() 
        },
        success: function (response) {
            // ....
        }
    });
});

1
MVC (Razor) 페이지에서 jQuery AJAX 게시를 실험하면서 여러 시간을 보낸 후에 이것은 저에게 가장 효과적인 대답이었습니다. 토큰 다음에 고유 한 데이터 필드 (또는 가정 한 viewModel)를 새 데이터 조각 (원래 데이터 개체 내)으로 포함하십시오.
Ralph Bacon

AJAX 함수가 Razor 페이지가 아닌 .html 페이지에있는 경우 어떻게 구현합니까?
Bob the Builder

귀하의 html 페이지에 서버가 제공되지 않으면 AntiForgeryToken어쨌든 모두 무례합니다. 그렇다면 (이 경우 어떻게 얻는 지 확실하지 않지만 가정한다고 가정하면) 위의 내용은 정상적으로 작동합니다. 해당 토큰을 기대하는 서버에 요청을 게시하는 간단한 웹 페이지를 만들려고 시도했지만 서버가 해당 페이지를 생성하지 않은 경우 운이 좋지 않습니다. 그것은 본질적으로 AntiForgeryToken의 요점입니다 ...
jball

6

당신은 또한 이것을 할 수 있습니다 :

$("a.markAsDone").click(function (event) {
    event.preventDefault();

    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: $('<form>@Html.AntiForgeryToken()</form>').serialize(),
        success: function (response) {
        // ....
        }
    });
});

이것은을 사용 Razor하고 있지만 WebForms구문을 사용하는 경우 <%= %>태그를 사용할 수 있습니다


4

길을 따라 나를 도왔던 @JBall의 답변에 대한 나의 의견에 더하여, 이것은 나를 위해 일하는 최종 답변입니다. MVC와 Razor를 사용하고 있으며 jQuery AJAX를 사용하여 양식을 제출하여 일부 새로운 결과로 부분보기를 업데이트 할 수 있으며 완전한 포스트 백 (및 페이지 깜박임)을 원하지 않습니다.

@Html.AntiForgeryToken()평소와 같이 양식 내부를 추가하십시오 .

내 AJAX 제출 버튼 코드 (예 : onclick 이벤트)는 다음과 같습니다.

//User clicks the SUBMIT button
$("#btnSubmit").click(function (event) {

//prevent this button submitting the form as we will do that via AJAX
event.preventDefault();

//Validate the form first
if (!$('#searchForm').validate().form()) {
    alert("Please correct the errors");
    return false;
}

//Get the entire form's data - including the antiforgerytoken
var allFormData = $("#searchForm").serialize();

// The actual POST can now take place with a validated form
$.ajax({
    type: "POST",
    async: false,
    url: "/Home/SearchAjax",
    data: allFormData,
    dataType: "html",
    success: function (data) {
        $('#gridView').html(data);
        $('#TestGrid').jqGrid('setGridParam', { url: '@Url.Action("GetDetails", "Home", Model)', datatype: "json", page: 1 }).trigger('reloadGrid');
    }
});

MvcJqGrid를 포함하는 부분 뷰를 업데이트하는 방법과 새로 고치는 방법을 보여주기 때문에 "성공"작업을 남겼습니다 (매우 강력한 jqGrid 그리드 및이 기능은 훌륭한 MVC 래퍼입니다).

내 컨트롤러 방법은 다음과 같습니다.

    //Ajax SUBMIT method
    [ValidateAntiForgeryToken]
    public ActionResult SearchAjax(EstateOutlet_D model) 
    {
        return View("_Grid", model);
    }

전체 양식의 데이터를 모델로 POST하는 팬이 아니라는 것을 인정해야하지만 필요한 경우이 방법이 효과적입니다. MVC는 16 개의 개별 값 (또는 약한 형식의 FormCollection)을 제출하는 대신 데이터 바인딩을 너무 쉽게 만듭니다. 더 잘 알고 있다면 강력한 MVC C # 코드를 만들고 싶습니다.


4

모든 $ .ajax 호출에 대해 https://gist.github.com/scottrippey/3428114 에서이 매우 영리한 아이디어를 발견 하여 요청을 수정하고 토큰을 추가했습니다.

// Setup CSRF safety for AJAX:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:
        if (options.contentType.indexOf('application/json') === 0) {
            // Add the token to the URL, because we can't add it to the JSON data:
            options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();
        } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {
            // Append to the data string:
            options.data += (options.data ? "&" : "") + token.serialize();
        }
    }
});

위의 다른 대안 중 몇 가지를 시도했지만 이것이 나를 위해 해결 한 것입니다.
HostMyBus

그러나 if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {컨텐츠 유형을 지정하지 않은 Ajax 호출을 잡기 위해 추가해야했습니다
HostMyBus

3

1. 서버에서 토큰을 얻는 기능 정의

@function
{

        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
}

2. 서버로 보내기 전에 토큰을 가져오고 헤더를 설정하십시오.

var token = '@TokenHeaderValue()';    

       $http({
           method: "POST",
           url: './MainBackend/MessageDelete',
           data: dataSend,
           headers: {
               'RequestVerificationToken': token
           }
       }).success(function (data) {
           alert(data)
       });

3. Post / get을 처리하는 메소드의 HttpRequestBase에 대한 서버상의 유효성 검사

        string cookieToken = "";
        string formToken = "";
        string[] tokens = Request.Headers["RequestVerificationToken"].Split(':');
            if (tokens.Length == 2)
            {
                cookieToken = tokens[0].Trim();
                formToken = tokens[1].Trim();
            }
        AntiForgery.Validate(cookieToken, formToken);

1

이 질문이 게시 된 지 얼마되지 않았지만 AntiForgeryToken의 사용법을 설명하고 사용하기가 덜 유용한 유용한 리소스를 발견했습니다. 또한 AJAX 호출에 위조 방지 토큰을 쉽게 포함시킬 수있는 jquery 플러그인을 제공합니다.

ASP.NET MVC 및 AJAX에 대한 위조 방지 요청 레시피

나는별로 기여하지 않지만 누군가가 유용하다고 생각할 것입니다.


그 게시물은 1 마일 정도입니다! 나는 그것이 훌륭하지만 tl; dr 확신합니다
BritishDeveloper

1
주제를 잘 다루기 때문에 너무 나쁩니다. 이 기능을 사용하는 방법을 알려줄뿐만 아니라 어떤 문제를 해결하고 기능을 올바르게 사용하는지 이해할 수있는 컨텍스트를 제공합니다. 보안에 관해서는 깊이있는 이해가 중요하다고 생각합니다.
slawek

2
그것이 중요하다면 사람들이 그것을 읽을 수 있도록 격려하는 방식으로 작성되어야합니다.)
BritishDeveloper at

1

먼저 HTML에서 @ Html.AntiForgeryToken ()을 사용하십시오.

 $.ajax({
        url: "@Url.Action("SomeMethod", "SomeController")",
        type: 'POST',
        data: JSON.stringify(jsonObject),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: false,
        beforeSend: function (request) {
            request.setRequestHeader("RequestVerificationToken", $("[name='__RequestVerificationToken']").val());
        },
        success: function (msg) {
            alert(msg);
        }

1

내가 본 가장 쉬운 방법은 다음과 같습니다. 참고 :보기에 "@ Html.AntiForgeryToken ()"이 있는지 확인하십시오.

  $("a.markAsDone").click(function (event) {
        event.preventDefault();
        var sToken = document.getElementsByName("__RequestVerificationToken")[0].value;
        $.ajax({
            url: $(this).attr("rel"),
            type: "POST",
            contentType: "application/x-www-form-urlencoded",
            data: { '__RequestVerificationToken': sToken, 'id': parseInt($(this).attr("title")) }
        })
        .done(function (data) {
            //Process MVC Data here
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            //Process Failure here
        });
    });

0

360Airwalk 솔루션을 약간 개선했습니다. 이것은 자바 스크립트 함수 내에 안티 위변조 토큰을 포함하므로 @ Html.AntiForgeryToken ()을 더 이상 모든 뷰에 포함시킬 필요는 없습니다.

$(document).ready(function () {
    var securityToken = $('@Html.AntiForgeryToken()').attr('value');
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

0
function DeletePersonel(id) {

    var data = new FormData();
    data.append("__RequestVerificationToken", "@HtmlHelper.GetAntiForgeryToken()");

    $.ajax({
        type: 'POST',
        url: '/Personel/Delete/' + id,
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function (result) {
        }
    });
}

public static class HtmlHelper {
    public static string GetAntiForgeryToken() {
        System.Text.RegularExpressions.Match value = 
                System.Text.RegularExpressions.Regex.Match(System.Web.Helpers.AntiForgery.GetHtml().ToString(), 
                        "(?:value=\")(.*)(?:\")");
        if (value.Success) {
            return value.Groups[1].Value;
        }
        return "";
    }
}

0

ajax 게시물을 사용하여 삭제 메소드를 실행하고 있습니다 (visjs 타임 라인에서 발생하지만 관련이 없습니다). 이것이 내가 누군지입니다.

이것은 내 Index.cshtml입니다

@Scripts.Render("~/bundles/schedule")
@Styles.Render("~/bundles/visjs")
@Html.AntiForgeryToken()

<!-- div to attach schedule to -->
<div id='schedule'></div>

<!-- div to attach popups to -->
<div id='dialog-popup'></div>

내가 여기에 추가 한 것은 @Html.AntiForgeryToken() 페이지에 토큰을 표시하는 것입니다.

그런 다음 내 아약스 게시물에서 다음을 사용했습니다.

$.ajax(
    {
        type: 'POST',
        url: '/ScheduleWorks/Delete/' + item.id,
        data: {
            '__RequestVerificationToken': 
            $("input[name='__RequestVerificationToken']").val()
              }
     }
);

페이지에서 스크랩 된 토큰 값을 게시 된 필드에 추가합니다.

이 전에 헤더에 값을 넣으려고했지만 동일한 오류가 발생했습니다.

개선 사항을 게시하십시오. 이것은 확실히 내가 이해할 수있는 간단한 접근법 인 것 같습니다.


0

여기에 많은 게시물이 있지만 그중 어느 것도 Google의 며칠 동안 나에게 도움이되지 않았으며 더 이상 전체 앱을 처음부터 작성하는 시점에 도달하지 못했습니다. 그런 다음 Web.confg 에서이 작은 덩어리를 발견했습니다.

 <httpCookies requireSSL="false" domain="*.localLookup.net"/>

이제 왜 내가 추가했는지 알지 못하지만 이후에 알았습니다. 디버그 모드에서는 무시되고 프로덕션 모드에서는 무시됩니다 (IE는 IIS 어딘가에 설치됨)

나를 위해 솔루션은 두 가지 옵션 중 하나였습니다. 왜 내가 추가했는지 기억이 안 나기 때문에 다른 것들이 그것에 의존하지 않을 것이라고 확신 할 수 없으며 두 번째로 도메인 이름은 모두 소문자이어야하며 TLD는 필자가 수행하지 않아야합니다 * .localLookup.net에서

어쩌면 도움이되지 않을 수도 있습니다. 누군가에게 도움이되기를 바랍니다.


0

내가 찾은 해결책은 ASPX가 아니라 Razor를위한 것이지만 상당히 문제가있는 문제입니다.

AntiForgery를 요청에 추가하여 문제를 해결했습니다. HTML 도우미는 호출로 HTML ID를 만들지 않습니다.

@Html.AntiForgeryToken()

postrequest에 토큰을 추가하기 위해 jQuery를 사용하여 숨겨진 필드에 AntiForgery ID를 추가했습니다.

$("input[name*='__RequestVerificationToken']").attr('id', '__AjaxAntiForgeryForm');

이로 인해 컨트롤러는 [ValidateAntiForgeryToken] 속성으로 요청을 수락했습니다.


-3

AntiforgeryToken은 여전히 ​​고통 스럽지만 위의 예 중 어느 것도 나를 위해 한마디로 효과가 없었습니다. 너무 많습니다. 그래서 나는 그것들을 모두 결합했습니다. iirc 주위에 매달려있는 형태의 @ Html.AntiforgeryToken이 필요합니다.

다음과 같이 해결되었습니다.

function Forgizzle(eggs) {
    eggs.__RequestVerificationToken =  $($("input[name=__RequestVerificationToken]")[0]).val();
    return eggs;
}

$.ajax({
            url: url,
            type: 'post',
            data: Forgizzle({ id: id, sweets: milkway }),
});

의심스러운 경우 $ 표시를 더 추가하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.