[asp.net-mvc] jQuery Ajax 호출과 Html.AntiForgeryToken ()
내 앱에서 CSRF 공격에 대한 완화를 구현했습니다.인터넷에서 블로그 게시물에서 읽은 정보에 따라 . 특히이 게시물은 내 구현의 동인이었습니다.
- ASP.NET MVC에 대한 모범 사례ASP.NET 및 웹 도구 개발자 콘텐츠 팀의
- 사이트 간 요청 위조 공격 분석Phil Haack 블로그
- ASP.NET MVC 프레임 워크의 AntiForgeryToken- David Hayden 블로그의 Html.AntiForgeryToken 및 ValidateAntiForgeryToken 특성
기본적으로 이러한 기사와 권장 사항에 따르면 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) {
// ....
}
});
});
답변
나는 이와 같은 간단한 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) {
// ....
}
});
답변
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);
}
}
});
});
답변
다른 답변이 많이 있다는 것을 알고 있지만이 기사는 훌륭하고 간결하며 일부 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 년 후에도 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);
}
답변
Html.AntiForgeryToken을 사용하지 마십시오 . 대신 ASP.NET MVC 응용 프로그램에서 CSRF (Cross-Site Request Forgery) 공격 방지에 설명 된대로 웹 API에서 AntiForgery.GetTokens 및 AntiForgery.Validate 를 사용 하십시오 .
답변
나는 현재 프로젝트 에서이 실제 문제를 구현하고있었습니다. 인증 된 사용자가 필요한 모든 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 매개 변수가 추가 된 방법을 쉽게 확인할 수 있습니다.
답변
“__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) {
// ....
}
});
});