ASP.NET MVC中防止跨站请求攻击(CSRF)

时间:2023-02-13 10:48:26

转载   http://kevintsengtw.blogspot.co.nz/2013/01/aspnet-mvc-validateantiforgerytoken.html

在 ASP.NET MVC 裡為了要防止 CSRF (Cross-Site Request Forgery) 跨站偽造請求的攻擊,我們可以在 View 的表單中加入「@Html.AntiForgeryToken」然後在對應的後端 Action 方法加上「ValidateAntiForgeryToken」Attribute 來防止 CSRF 的攻擊,相關

而當網站接收到沒有 AntiForgeryToken 的 POST 請求時就會返回錯誤訊息,如果沒有指定錯誤頁的話大多會是使用預設的 Error Page,比較好的錯誤訊息顯示方式是不要透漏太多訊息,以免讓有心者可以去鑽漏洞,但如果真的想要指定錯誤頁的話,也是有方法的,這篇文章當中就跟各位來說明。

什麼是 CSRF ( Cross-Site Request Forgery ) 跨站偽造請求呢?最常看到的就是經由網站裡的表單利用 POST 來發動攻擊,一般我們做網站都是預設站內的所有 POST 需求都是經由站內的表單或是 Javascript 程式所發出的,但有心攻擊的人就會利用這一點來對網站做壞事,例如我有一個簡單的登入頁面,

ASP.NET MVC中防止跨站请求攻击(CSRF)

有心想做壞事的人是不會一直在這個頁面上去做踹站的動作,而是會自己寫個偽造的登入頁面然後跨站傳送 POST 請求到我們網站來踹,

ASP.NET MVC中防止跨站请求攻击(CSRF)

這只是一個單純的 HTML 檔案,只是在表單的 Action 是使用測試網站的網址,

ASP.NET MVC中防止跨站请求攻击(CSRF)

在這個偽造的網頁表單中輸入正確的帳號與密碼,就可以長驅直入網站當中,

ASP.NET MVC中防止跨站请求攻击(CSRF)

ASP.NET MVC中防止跨站请求攻击(CSRF)

所以不管我們在網站登入頁做的多麼嚴謹或是再多防護,都有可能因為這樣的疏忽而大開方便之門。

為了避免這樣的情況發生,我們可以在 View 頁面的表單中加入「@Html.AntiForgeryToken」,然後在對應的 Action 方法上標註「ValidateAntiForgeryToken」Attribute,如此就可以避免跨站偽造請求的攻擊,

ASP.NET MVC中防止跨站请求攻击(CSRF)

ASP.NET MVC中防止跨站请求攻击(CSRF)

在 View 頁面的表單裡加上「@Html.AntiForgeryToken」,產出頁面的原始碼會是以 Hidden 欄位放置 Token,

ASP.NET MVC中防止跨站请求攻击(CSRF)

並且也會產生 Cookie「__RequestVerificationToken」來放置 Request Verification Token,

ASP.NET MVC中防止跨站请求攻击(CSRF)

如果是經由偽造的頁面所傳送過來的 POST Request,那麼系統就會顯示錯誤,

ASP.NET MVC中防止跨站请求攻击(CSRF)

在上面未加入 AntiForgeryToken 的情況下會返回一個錯誤頁,而這個錯誤頁不應該出現在一般使用者的眼前,因為這樣的錯誤訊息內容透露了很多系統內部細節,所以我在之前的文章也強調過應該要使用專屬的錯誤訊息頁來顯示,而錯誤訊息頁的內容也不要透露太多的細節,一般的情況下,我們都會在 Web.Config 的 System.Web Section 加入 customError 的內容,如下:

ASP.NET MVC中防止跨站请求攻击(CSRF)

那麼當遇到 CSRF 傳送時就會返回系統預設的錯誤頁內容,

ASP.NET MVC中防止跨站请求攻击(CSRF)

ASP.NET MVC中防止跨站请求攻击(CSRF)

如果你想要讓 CSRF 所返回的網頁不是用預設的 Error.cshtml 的話,可以在 ~/View/Shared 目錄下建立一個新的錯誤頁,例如我另外建立一個「CSRF_Error.cshtml」

ASP.NET MVC中防止跨站请求攻击(CSRF)

在 Controller 的 Action 方法上就必須要再去標註 HandleError Attribute,並在這個 Attribute 內指定 ExceptionType 以及返回的錯誤頁名稱,

ASP.NET MVC中防止跨站请求攻击(CSRF)

後端沒有接收到前端 View 所 POST 回來的 AntiForgeryToken 時是會發生 HttpAntiForgeryException (MSDN : HttpAntiForgeryException 類別),所以在 HandleError 的要指定當發生 HttpAntiForgeryException 時所返回錯誤訊息所使用的 View 名稱,再一次重新傳送 CSRF POST 請求後,就會顯示指定的錯誤頁內容,

ASP.NET MVC中防止跨站请求攻击(CSRF)

如果有安裝 elmah 來記錄系統錯誤的話,可以在 elmah Dashboard 裡看到的 HttpAntiForgeryException 錯誤,

ASP.NET MVC中防止跨站请求攻击(CSRF)

而我在之前的文章裡曾經有介紹過在 Global.asax 的 Application_Error 事件中對系統發生錯誤時進行處理,並且依照錯誤的不同而顯示不同的錯誤頁面,

ASP.NET MVC + ELMAH 監控並記錄你的網站錯誤資訊 1

雖然 HttpAntiForgeryException 是 Http Statu Code 500 的 Internal Error,但並不會返回我們所指定的 InternalError 錯誤頁,所以我這邊的作法是自己再另外建立一個 HandleError Attribute,然後在引發 Exception 時去判斷 Exception 的類別,然後依照類別去做不同的處理,例如遇到 HttpAntiForgeryExceptoipn 這個類別的 Exception 就顯示指定的錯誤訊息頁,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http.Filters;
using System.Web.Mvc; namespace MvcApplication1.Base
{
public class CustomHandleErrorAttribute : System.Web.Mvc.FilterAttribute, System.Web.Mvc.IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (!filterContext.IsChildAction
&& (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled))
{
var innerException = filterContext.Exception;
if ((new HttpException(null, innerException).GetHttpCode() == ))
{
var controllerName = (string)filterContext.RouteData.Values["controller"];
var actionName = (string)filterContext.RouteData.Values["action"];
var viewName = "Error"; if (typeof(HttpAntiForgeryException).IsInstanceOfType(innerException))
{
controllerName = "ErrorPage";
actionName = "AntiForgeryError";
viewName = "~/Views/ErrorPage/AntiForgeryError.cshtml";
}
else
{
controllerName = "ErrorPage";
actionName = "InternalError";
viewName = "~/Views/ErrorPage/InternalError.cshtml";
} var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
var result = new ViewResult
{
ViewName = viewName,
ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
TempData = filterContext.Controller.TempData
}; filterContext.Result = result;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = ;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true; var version = Assembly.GetExecutingAssembly().GetName().Version;
filterContext.Controller.ViewData["Version"] = version.ToString();
}
}
} }
}

其中的 viewName 需要指定絕對路徑,如果不把路徑名稱寫清楚,就只會在 ~/Views/Shared 目錄裡找,找不到就會引發 InvalidOperationException 的例外。

建立好 CustomHandleErrorAttribute 後,原本標註在 Login 方法上的 HandleError Attribute 就可以拿掉,而接著要到 ~/App_Start 目錄下的「FilterConfig.config」做修改,

ASP.NET MVC中防止跨站请求攻击(CSRF)

把原本所使用的 HandleErrorAttribute 置換為我們所建立的 CustomHandleErrorAttribute, 修改如下,

using System.Web;
using System.Web.Mvc;
using MvcApplication1.Base; namespace MvcApplication1
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomHandleErrorAttribute());
//filters.Add(new HandleErrorAttribute());
}
}
}

修改完成後,重新建置方案並重新傳送 CSRF 請求,就可以看到我們所指定的錯誤內容,

ASP.NET MVC中防止跨站请求攻击(CSRF)

雖說可以讓我們自己依據不同的錯誤或是例外來執行不同的處理或是顯示不同的錯誤訊息頁,但還是不要也不宜做得太細、太多,還是要避免過多的訊息暴露在外而讓人有機可趁。

參考連結:

The Code Project - Exception Handling in ASP.NET MVC  by After2050

*  - HandleErrorAttribute not working

* - ASP.net MVC - Custom HandleError Filter - Specify View based on Exception Type

延伸閱讀:

Steven Sanderson's blog : Prevent Cross-Site Request Forgery (CSRF) using ASP.NET MVC’s AntiForgeryToken() helper

隱匿角落 : 关于CSRF攻击及mvc中的解决方案 [ValidateAntiForgeryToken]

ASP.NET MVC中防止跨站请求攻击(CSRF)的更多相关文章

  1. asp&period;net MVC中防止跨站请求攻击&lpar;CSRF&rpar;的ajax用法

    参考: Preventing Cross-Site Request Forgery (CSRF) AttacksValidating .NET MVC 4 anti forgery tokens in ...

  2. ASP&period;NET MVC 实现 AJAX 跨域请求

    ASP.NET MVC 实现AJAX跨域请求的两种方法 和大家分享下Ajax 跨域的经验,之前也找了好多资料,但是都不行,后来看到个可行的修改了并测试下 果然OK了   希望对大家有所帮助! 通常发送 ...

  3. ASP&period;NET MVC 实现AJAX跨域请求方法《1》

    ASP.NET MVC 实现AJAX跨域请求的两种方法 通常发送AJAX请求都是在本域内完成的,也就是向本域内的某个URL发送请求,完成部分页面的刷新.但有的时候需要向其它域发送AJAX请求,完成数据 ...

  4. ASP&period;NET MVC中设置跨域

    ASP.NET MVC中设置跨域 1.什么是跨域请求 js禁止向不是当前域名的网站发起一次ajax请求,即使成功respone了数据,但是你的js仍然会报错.这是JS的同源策略限制,JS控制的并不是我 ...

  5. js基础 js自执行函数、调用递归函数、圆括号运算符、函数声明的提升 js 布尔值 ASP&period;NET MVC中设置跨域

    js基础 目录 javascript基础 ESMAScript数据类型 DOM JS常用方法 回到顶部 javascript基础 常说的js包括三个部分:dom(文档document).bom(浏览器 ...

  6. ASP&period;NET Core-Docs:在 ASP&period;NET Core 中启用跨域请求(CORS)

    ylbtech-ASP.NET Core-Docs:在 ASP.NET Core 中启用跨域请求(CORS) 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部 1. ...

  7. 跨站请求伪造 CSRF &sol; XSRF&lt&semi;一:介绍&gt&semi;

    跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一 ...

  8. PHP安全编程:跨站请求伪造CSRF的防御&lpar;转&rpar;

    跨站请求伪造(CSRF)是一种允许攻击者通过受害者发送任意HTTP请求的一类攻击方法.此处所指的受害者是一个不知情的同谋,所有的伪造请求都由他发起,而不是攻击者.这样,很你就很难确定哪些请求是属于跨站 ...

  9. 跨站请求伪造&lpar;CSRF&rpar;-简述

    跨站请求伪造(CSRF)-简述 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 ...

随机推荐

  1. jmeter(九)逻辑控制器

    jmeter中逻辑控制器(Logic Controllers)的作用域只对其子节点的sampler有效,作用是控制采样器的执行顺序. jmeter提供了17种逻辑控制器,它们各个功能都不尽相同,大概可 ...

  2. 使用layer&period;open时content属性传值记录

    最近在做一个后台项目,正好碰上了要使用layer.open,就顺手记录一下,方便以后遇到了有个参考 - 2016/11/7 layer 这个是一个web弹层组件,挺好用的...然后项目框架是SSM.. ...

  3. compare

    icompareble 默认的比较器 list.sort() compareto icompare Keyvaluepair<k,p>Where k:new()

  4. c&plus;&plus; 学习笔记 c&plus;&plus; 引用C库注意点:&num;ifdef &lowbar;&lowbar;cplusplus 倒底是什么意思?

    时常在cpp的代码之中看到这样的代码: #ifdef __cplusplus extern "C" { #endif //一段代码 #ifdef __cplusplus } #en ...

  5. 设定PCB电路板形状和物理边界

    1 设定PCB电路板形状和物理边界 在Protel DXP的PCB板文件向导中,我们已经初步确定了电路板的形状和物理边界.但我们在绘制PCB板之前,也许还会对电路板的边界的细节加以调整.如果我们要对电 ...

  6. 基于visual Studio2013解决算法导论之026二叉树

     题目 二叉树实现 解决代码及点评 #include<stdio.h> #include <malloc.h> #include <stdlib.h> typ ...

  7. 优秀开源软件学习系列(一)——从零学习Spring4以及学习方法分享

    一.目的1.掌握Spring4怎样使用,以便将这个框架作为自己的一项技能.2.掌握Spring官网是怎样介绍其产品的,在心中对Spring有最官方的.最直观的了解.在Spring的相关领域,能够知道怎 ...

  8. js函数防抖、节流实现

    防抖 Debounce 函数防抖就是,延迟一段时间再执行函数,如果这段时间内又触发了该函数,则延迟重新计算: // 简单实现 function debounce(fn, wait) { let t r ...

  9. 15-5-23 下午02时22分58秒 CST&gt&semi; &lt&semi;Info&gt&semi; &lt&semi;Management&gt&semi; &lt&semi;BEA-141281&gt&semi; &lt&semi;unable to get file lock&comma; will retry &period;&period;&period;&gt&semi;

     A-141281> <unable to get file lock, will retry ...>   http://gdutlzh.blog.163.com/blog/s ...

  10. Java父类与子类方法调用顺序

    父类 FatherClass package 父类与子类方法调用顺序; /** * 父类 * @author shundong * */ public class FatherClass { priv ...