ASP.NET-漏洞处理-验证HTTP_Referer字段修复CSRF

CSRF:

Cross Site Request Forgery,跨站请求伪造,也被称成为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用,跨站请求伪造是指攻击者可以在第三方站点制造HTTP请求并以用户在目标站点的登录态发送到目标站点,而目标站点未校验请求来源使第三方成功伪造请求


原因和步骤:
  1. 用户打开浏览器,访问系统网站A,输入用户名和密码请求登录网站A
    2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A
  2. 用户未退出网站A,在同一浏览器同一个会话中,打开一个TAB页访问网站B
  3. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A
  4. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户的Cookie信息以用户的权限处理该请求,导致来自网站B的恶意代码被执行

JS控制浏览器发送请求的时候,浏览器是根据目标站点,而不是来源站点,来发送cookie的,如果当前会话中有目标站点的cookie,就发送出去。核心问题是浏览器的会话机制,是跨站请求伪造漏洞的根源


解决方法:

一般情况下有两种半,像第三方检测公司给的一般也是前两种

  1. 使用token,在重要请求中的每一个URL和所有的表单中添加CSRF token
  2. 限制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"):
  1. 直接用<a href="">
  2. 用Submit或<input type=" ">提交的表单(POST或GET)
  3. 使用JavaScript提交的表单(POST或GET)
Request.ServerVariables("HTTP_REFERER")不能正常取值的情况:
  1. 从收藏夹链接
  2. 单击主页或自定义的地址
  3. 在浏览器中直接输地址
  4. 使用JavaScript的Location.href或者是Location.replace()
  5. <%Response.Redirect%>
  6. <%Response.AddHeader%>或者是<mete http-equiv="refresh">转向
  7. 用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:后续建议,上面的代码最好加入白名单进行控制,因为涉及接口或者发布外网的话会出现误报情况。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容