1
Fish opened the God website and browsed a variety of contents on it. At this time, the result of the forged request is as follows (to demonstrate the effect, hide is removed ):
Because the Fish did not log on to the system, the forged request cannot be executed and the system jumps back to the logon page.
Then Fish remembered that he was going to log on to the Online Bank to query the content, so he logged on to the Online Bank.
At this time, the result of the forged request is as follows (to demonstrate the effect, hide is removed ):
Fish transfers RMB 100 to God every 10 seconds.
Prevent CSRF
CSRF is successful because the same browser shares Cookies. That is to say, permission authentication and verification cannot prevent CSRF. So how should we prevent CSRF? In fact, the method to prevent CSRF is very simple, as long as you make sure that the request is sent by your site. So how can we ensure that the request is from our own site? ASP. NET uses tokens to determine the request.
We need to generate a Token on our page and carry the Token when sending the request. Cookies and tokens must be verified during request processing.
At this time, the result of the forged request is as follows (to demonstrate the effect, hide is removed ):
$. Ajax
What if my request is submitted through Ajax instead of Form? The result is that the verification fails.
Why? Let's look back at the page and request changes after @ Html. AntiForgeryToken () is added.
1. The page has a hidden domain named _ RequestVerificationToken.
2. The request also has a field _ RequestVerificationToken.
If you want to add such a field, I can add one!
Ah! Why is it still not possible... force me to zoom in and study the source code!
Oh! The original token should be taken from the Form. However, in ajax, there is nothing in Form. What about token? I put the token in the bowl. No, it is in the header.
Js Code:
1 $(function () { 2 var token = $('@Html.AntiForgeryToken()').val(); 3 4 $('#btnSubmit').click(function () { 5 var targetUser = $('#TargetUser').val(); 6 var amount = $('#Amount').val(); 7 var data = { 'targetUser': targetUser, 'amount': amount }; 8 return $.ajax({ 9 url: '@Url.Action("Transfer2", "Home")',10 type: 'POST',11 data: JSON.stringify(data),12 contentType: 'application/json',13 dataType: 'json',14 traditional: 'true',15 beforeSend: function (xhr) {16 xhr.setRequestHeader('__RequestVerificationToken', token);17 },18 success:function() {19 window.location = '@Url.Action("Index", "Home")';20 }21 });22 });23 });
On the server side, refer to ValidateAntiForgeryTokenAttribute to compile an AjaxValidateAntiForgeryTokenAttribute:
1 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 2 public class AjaxValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter 3 { 4 public void OnAuthorization(AuthorizationContext filterContext) 5 { 6 if (filterContext == null) 7 { 8 throw new ArgumentNullException("filterContext"); 9 }10 11 var request = filterContext.HttpContext.Request;12 13 var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];14 var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;15 var formToken = request.Headers["__RequestVerificationToken"];16 AntiForgery.Validate(cookieValue, formToken);17 }18 }
Then, replace ValidateAntiForgeryToken with AjaxValidateAntiForgeryToken.
Success! A sense of accomplishment!
Global Processing
If a ValidateAntiForgeryToken or AjaxValidateAntiForgeryToken is required for all operation requests, isn't it troublesome? Can it be processed in a unified manner somewhere? The answer is yes.
ValidateAntiForgeryTokenAttribute inherits the IAuthorizationFilter, so perform unified processing in AuthorizeAttribute.
ExtendedAuthorizeAttribute:
1 public class ExtendedAuthorizeAttribute : AuthorizeAttribute 2 { 3 public override void OnAuthorization(AuthorizationContext filterContext) 4 { 5 PreventCsrf(filterContext); 6 base.OnAuthorization(filterContext); 7 GenerateUserContext(filterContext); 8 } 9 10 /// <summary>11 /// http://www.asp.net/mvc/overview/security/xsrfcsrf-prevention-in-aspnet-mvc-and-web-pages12 /// </summary>13 private static void PreventCsrf(AuthorizationContext filterContext)14 {15 var request = filterContext.HttpContext.Request;16 17 if (request.HttpMethod.ToUpper() != "POST")18 {19 return;20 }21 22 var allowAnonymous = HasAttribute(filterContext, typeof(AllowAnonymousAttribute));23 24 if (allowAnonymous)25 {26 return;27 }28 29 var bypass = HasAttribute(filterContext, typeof(BypassCsrfValidationAttribute));30 31 if (bypass)32 {33 return;34 }35 36 if (filterContext.HttpContext.Request.IsAjaxRequest())37 {38 var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];39 var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;40 var formToken = request.Headers["__RequestVerificationToken"];41 AntiForgery.Validate(cookieValue, formToken);42 }43 else44 {45 AntiForgery.Validate();46 }47 }48 49 private static bool HasAttribute(AuthorizationContext filterContext, Type attributeType)50 {51 return filterContext.ActionDescriptor.IsDefined(attributeType, true) ||52 filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(attributeType, true);53 }54 55 private static void GenerateUserContext(AuthorizationContext filterContext)56 {57 var formsIdentity = filterContext.HttpContext.User.Identity as FormsIdentity;58 59 if (formsIdentity == null || string.IsNullOrWhiteSpace(formsIdentity.Name))60 {61 UserContext.Current = null;62 return;63 }64 65 UserContext.Current = new WebUserContext(formsIdentity.Name);66 }67 }
Register in FilterConfig.
FAQ:
1. What is BypassCsrfValidationAttribute? Isn't there an AllowAnonymousAttribute?
If you do not need to perform CSRF operations, such as attachment upload, you can add BypassCsrfValidationAttribute to the corresponding Controller or Action.
AllowAnonymousAttribute not only bypasses CSRF processing, but also bypasses authentication and verification. BypassCsrfValidationAttribute bypasses CSRF but does not bypass authentication and verification,
That is, BypassCsrfValidationAttribute acts on the login or authorized actions.
2. Why only POST requests are processed?
I developed a principle that GET is used for queries and POST is used for operations. However, CSRF is not necessary for queries. You can arrange as needed!
3. If I perform global processing and add ValidateAntiForgeryToken or AjaxValidateAntiForgeryToken to the Controller or Action, will it conflict?
There is no conflict, but the verification will be performed twice.
Source code download
For ease of use, I did not use any database, but used a file to store data. After the code is downloaded, it can be run directly without configuration.
: Https://github.com/ErikXu/CSRF
Article Reprinted from: http://www.cnblogs.com/Erik_Xu/p/5481441.html