CSRF防护措施
1. CSRF-Token
不同于通过在服务器上设置跨源资源共享策略(CORS )外,部分服务器例如(Dijango,ASP.NET)会在服务器随机生成一个 token 值,然后隐藏在 HTML 页面中,在提交表单时会附带上这个生成随机的 token 值。服务器在接收到请求后,会将 token 值同 session 保存的 token 进行比较,如果是一致才会进一步处理,从而防止 CSRF 攻击。(当然如 csrf token 泄露了,攻击者还是能够进行 CSRF 攻击)
Dijango
在 Django 中,csrf_token 是由服务器生成的。具体地说,Django 使用中间件来生成和验证 CSRF token,其中生成 CSRF token 的中间件是 django.middleware.csrf.CsrfViewMiddleware。当客户端发送一个 POST 请求时,这个中间件会在服务器端自动为该请求生成一个 CSRF token,并将该 token 存储在客户端的 Cookie 中。同时,在该 POST 请求的响应头中,服务器会将该 CSRF token 发送给客户端。客户端在之后的请求中,需要在请求头中携带该 CSRF token,以供服务器进行验证。下面是表单中加入 {\% csrf_token \%} 的模板标签。
<form method="post">
{\% csrf_token \%}
<label for="username">Username:</label>
<input type="text" id="username" name="username"><br><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password"><br><br>
<input type="submit" value="Submit">
</form>
在客户端,可以通过 Django 的模板引擎,使用 {\% csrf_token \%} 标签来自动生成表单中的 CSRF token 字段,或者使用 JavaScript 手动获取存储在 Cookie 中的 CSRF token 值,并将其设置为请求头中的 X-CSRFToken 字段,例如:
var csrftoken = getCookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
ASP. NET
ASP.NET 的方式同 Dijango 类似,当 ASP. NET 接收到具有 POST 请求方法的请求时,将生成一个新的防跨站请求伪造标记并将其存储在服务器端的 Session 中。服务器将这个标记存储在页面的隐藏字段中。在发送 POST 请求时,ASP. NET 会将这个标记包含在表单数据中,并在接收到请求后与服务器端存储的 Session 中的标记进行比较,以验证请求的来源。
例如,在 ASP. NET MVC 中,可以在表单中添加一个 @Html.AntiForgeryToken() 方法,如下所示:
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<input type="submit" value="Submit" />
}
而在 sqlmap 中也会处理 csrf token 这种情况。这两个正则表达式用来匹配 ASP. NET 中的 ViewState 和 EventValidation 参数,这两个参数是 ASP. NET 防止 Web 应用程序的跨站点请求伪造 (CSRF) 攻击的一种措施。ViewState 是将页面状态信息加密并作为隐藏域存储在页面上的一个机制。EventValidation 是用来验证服务器控件事件是否合法的一种机制。因此,在执行 Web 攻击的过程中,可以通过匹配这两个参数的值来确定 ASP. NET 的防护机制是否被正确实现。
sqlmap 中有两个正则用于匹配这两个数值
# Regular expression used for extracting ASP.NET view state values
VIEWSTATE_REGEX = r'(?i)(?P<name>__VIEWSTATE[^"]*)[^>]+value="(?P<result>[^"]+)'
# Regular expression used for extracting ASP.NET event validation values
EVENTVALIDATION_REGEX = r'(?i)(?P<name>__EVENTVALIDATION[^"]*)[^>]+value="(?P<result>[^"]+)'