该方法还有一个缺点是难以保证 token 本身的安全。特别是在一些论坛之类支持用户自己发表内容的网站,黑客可以在上面发布自己个人网站的地址。由于系统也会在这个地址后面加上 token,黑客可以在自己的网站上得到这个 token,并马上可以发动 CSRF 攻击。为了避免这一点,系统可以在添加 token 的时候增加一个判断,如果这个链接是链到自己本站的,在后面添加 token,如果是通向外网则不加。不过,即使这个 csrftoken 不以参数的形式附加在请求之中,黑客的网站也同样可以通过 Referer 来得到这个 token 值以发动 CSRF 攻击。这也是一些用户喜欢手动关闭浏览器 Referer 功能的原因。
  在 HTTP 头中自定义属性并验证
  这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
  然而这种方法的局限性非常大。XMLHttpRequest 请求通常用于 Ajax 方法中对于页面局部的异步刷新,并非所有的请求都适合用这个类来发起,而且通过该类请求得到的页面不能被浏览器所记录下,从而进行前进,后退,刷新,收藏等操作,给用户带来不便。另外,对于没有进行 CSRF 防护的遗留系统来说,要采用这种方法来进行防护,要把所有请求都改为 XMLHttpRequest 请求,这样几乎是要重写整个网站,这代价无疑是不能接受的。
  CSRF的防御
  我总结了一下看到的资料,CSRF的防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。这里给大家介绍一个开源项目,具体的内容可以参考作者的博客《Protecting ASP.NET Applications Against CSRF Attacks》。
  1、通过Nuget 安装ARMOR Web Framework
  PM> Install-Package Daishi.Armor.WebFramework
  2、添加几个配置项
  <add key=“IsArmed” value=“true” />
  <add key=“ArmorEncryptionKey” value=“{Encryption Key}” />
  <add key=“ArmorHashKey” value=“{Hashing Key}” />
  <add key=“ArmorTimeout” value=“1200000” />
  IsArmed: 打开或者关闭ARMOR 功能开关
  ArmorEncryptionKey:ARMOR 的加密密钥,用于加密和解密Token
  ArmorHashKey:用于生成和验证ARMOR 哈希值,包含在令牌内。ARMOR 用这个实现是否token被篡改过。
  ArmorTimeout:以毫秒为单位的ARMOR 的token有效期
  可以用下面的这段代码去生成
  byte[] encryptionKey = new byte[32];
  byte[] hashingKey = new byte[32];
  using (var provider = new RNGCryptoServiceProvider()) {
  provider.GetBytes(encryptionKey);
  provider.GetBytes(hashingKey);
  3、应用程序中加入 一个ARMOR 钩子
  ARMOR主要有 Authorization Filter、 Fortification Filter 和 ARMOR UI Components,支持ASP.NET MVC和ASP.NET Web API具体的使用方法可以参照Protecting ASP.NET Applications Against CSRF Attacks。