CSRF:
Cross Site Request Forgery,跨站请求伪造,也被称成为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用,跨站请求伪造是指攻击者可以在第三方站点制造HTTP请求并以用户在目标站点的登录态发送到目标站点,而目标站点未校验请求来源使第三方成功伪造请求
原因和步骤:
- 用户打开浏览器,访问系统网站A,输入用户名和密码请求登录网站A
2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A - 用户未退出网站A,在同一浏览器同一个会话中,打开一个TAB页访问网站B
- 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A
- 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户的Cookie信息以用户的权限处理该请求,导致来自网站B的恶意代码被执行
JS控制浏览器发送请求的时候,浏览器是根据目标站点,而不是来源站点,来发送cookie的,如果当前会话中有目标站点的cookie,就发送出去。核心问题是浏览器的会话机制,是跨站请求伪造漏洞的根源
解决方法:
一般情况下有两种半,像第三方检测公司给的一般也是前两种
- 使用token,在重要请求中的每一个URL和所有的表单中添加CSRF token
- 限制refer,检测HTTP Header中的Referer字段,服务器查看Referer是否为自己的站点,如果不是,则拒绝服务
最后半种是使用验证码技术,在重要请求的页面需要进行验证码验证
本文使用的是第二种方法,根据HTTP协议,在HTTP头中有一个字段叫Referer,它记录了该HTTP请求的来源地址。
在通常情况下,访问一个安全受限页面的请求必须来自于同一个网站。
比如某银行的转账是通过用户访问银行页面完成,用户必须先登录银行首页,然后通过点击页面上的按钮来触发转账事件。当用户提交请求时,该转账请求的 Referer值就会是转账按钮所在页面的URL(本例中,通常是以银行首页域名开头的地址)。而如果攻击者要对银行网站实施CSRF攻击,他只能在自己的网站构造请求,当用户通过攻击者的网站发送请求到银行时,该请求的 Referer是指向攻击者的网站。因此,要防御CSRF攻击,银行网站只需要对于每一个转账请求验证其Referer值,如果是存在且以银行首页开头的域名,则说明该请求是来自银行网站自己的请求,是合法的。如果Referer是其他网站的话,就有可能是CSRF攻击,则拒绝该请求。
总之,HTTP Referer是header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器籍此可以获得一些信息用于处理。
正常取得Request.ServerVariables("HTTP_REFERER"):
- 直接用<a href="">
- 用Submit或<input type=" ">提交的表单(POST或GET)
- 使用JavaScript提交的表单(POST或GET)
Request.ServerVariables("HTTP_REFERER")不能正常取值的情况:
- 从收藏夹链接
- 单击主页或自定义的地址
- 在浏览器中直接输地址
- 使用JavaScript的Location.href或者是Location.replace()
- <%Response.Redirect%>
- <%Response.AddHeader%>或者是<mete http-equiv="refresh">转向
- 用XML加载地址
实例
/* ''' <summary>
''' 代码待完善,未经严格测试,谨慎使用
''' </summary>
''' <param name="Sender"></param>
''' <param name="E"></param> */
Private Sub Application_BeginRequest(ByVal Sender As Object, ByVal E As EventArgs) Handles Me.BeginRequest
If Request.ServerVariables.Count > 0 Then
If Request.ServerVariables("HTTP_REFERER") IsNot Nothing AndAlso Request.ServerVariables("HTTP_REFERER").ToString().Contains(Request.ServerVariables("HTTP_HOST").ToString()) = False Then
demo.WriteLog("User Host:" & Request.UserHostAddress & vbCrLf &
"Event Name:OtherLink" & vbCrLf &
"Url:" & Request.Url.ToString & vbCrLf &
"HTTP_REFERER:" & Request.ServerVariables("HTTP_REFERER").ToString() & vbCrLf &
"HTTP_HOST:" & Request.ServerVariables("HTTP_HOST").ToString() & vbCrLf)
If IIf(Request.RawUrl.Contains(".asmx"), True, False) Then
Response.End()
Else
Response.Redirect("Warning.htm?wtype=OtherLink", False)
End If
End If
End If
End Sub
PS:后续建议,上面的代码最好加入白名单进行控制,因为涉及接口或者发布外网的话会出现误报情况。