
尽管在上次发布的OWASP 2017年Top 10 CSRF攻击漏洞列表中将其分类为“已删除,但未被遗忘”,但我们认为,再次依靠这些方法来再次防御CSRF攻击是不必要的OWASP提供的相同规则。
使用CSRF令牌使用令牌(无状态和有状态全两种方法)是最主要的保护方法。 对于每个用户会话,令牌必须是唯一的,由加密鲁棒的伪随机数生成器生成。 OWASP还建议在使用HMAC时使用AES256-GCM和SHA256 / 512算法进行加密。
有多种使用令牌的方法:同步令牌,基于加密的令牌模式,基于HMAC的令牌
同步器令牌使用Synchronizer Token方法(statefull方法),意味着在每个请求上发送一个令牌,这意味着服务器端会进行一些更改。 如果令牌无效,则服务器拒绝该请求。
向服务器发送请求时,建议将令牌添加到请求参数而不是标头。 但是,如果仍将令牌插入请求标头中,请确保未将其登录在服务器上。 接收到的令牌可以存储
在客户端的隐藏字段中:<form action="/post.php" method="post"> <input type="hidden" name="CSRFToken" value="l5824xNMAYFesBxing975yR8HPJlHZ"> ... </form>
在标题中: POST /page HTTP/1.1 Accept: application/json, application/xml, text/json, text/x-json, text/javascript, text/xml User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36 Content-Type: application/json Host: example.com X-CSRF-TOKEN: l5824xNMAYFesBxing975yR8HPJlHZ
或在cookie中 POST /page HTTP/1.1 Host: example.com Set-Cookie: CSRFToken=l5824xNMAYFesBxing975yR8HPJlHZ; Content-Type: application/x-www-form-urlencoded
OWASP建议将令牌存储在标头中,并解释说,即使令牌已打开或过期,由于浏览器的缘故,攻击者仍然无法伪造该请求。
另外,为了提高所提出方法的安全性,建议为每个请求生成随机令牌参数名称和/或令牌本身。 通过这种方法,攻击者可以使用被盗令牌的时间极短。 但是,这可能会导致可用性问题。 例如,单击“返回”按钮可能会导致向服务器发送无效令牌,该令牌包含在上一页中。
不建议使用GET请求发送令牌,因为使用这种方法可以显示令牌:在浏览器历史记录,日志文件,引荐来源标头中。
基于加密的令牌这种方法是无状态的,因为它使用加密/解密来验证令牌,因此不需要在服务器端存储令牌。
服务器生成由会话标识符和时间戳组成的令牌(以防止重放攻击)。 对于加密,建议在GSM / GSM-SIV块加密模式下使用AES256加密算法。 不建议使用ECB模式。 由服务器加密的令牌以与隐藏表单字段或响应头/参数中“同步令牌”相同的方式返回给客户端。 收到令牌后,服务器必须将其解密,然后检查会话标识符,并检查带有当前时间的时间戳,并确保它不超过设置的令牌生存期。
如果会话标识符的验证成功,但时间映射不成功,则可以认为该请求有效。 在所有其他情况下,建议拒绝请求并注册它,以进一步了解如何响应此类请求。
基于HMAC的令牌
它还不需要令牌存储,其操作原理类似于基于加密的令牌,除了使用HMAC(基于哈希的消息身份验证代码)功能而不是对令牌进行加密(生成令牌(建议使用SHA256或更强大的算法))之外。 在这种情况下,令牌是用户会话标识符+时间戳的HMAC函数的结果。
代币自动化抵抗CSRF攻击的主要问题是,开发人员常常只是忘记添加功能来使用令牌。 为避免此类问题,值得使此过程自动化:
•编写一个包装器,该包装器可以通过form标记或使用ajax自动向请求添加令牌。 例如,每次使用<form:form>标记时,Spring Security都会采用类似的方法。
•编写一个钩子,以拦截流量并将令牌添加到所有易受攻击的资源。 由于分析状态更改正在执行的请求非常困难,需要令牌,因此建议在所有POST响应中包括令牌,但是值得考虑性能成本
•呈现页面时自动添加令牌。 CSRF Guard使用此方法:将令牌添加到所有href和src属性,隐藏字段以及所有形式
在尝试编写自己的自动令牌生成系统之前,建议先弄清所使用的框架是否默认情况下具有针对CSRF攻击的保护功能。 例如,相同的Django框架实现了针对CSRF的保护。
登录CSRF攻击者可以使用登录表单中的CSRF进行登录,
伪装成受害者。 PayPal和Google等巨头都面临着这种漏洞。
您可以通过创建在用户进行身份验证之前创建的会话,并在登录表单中包含令牌来处理登录表单中的CSRF。
Samesite CookieSameSite Cookie是RFC6265bis中描述的属性,其目的是抵抗CSRF攻击。 它的工作原理如下。 保护的一种方法是检查源标头和引用标头,通过它们您可以了解请求的来源,但是这种方法需要实现验证机制。 使用SameSite属性,我们限制来自外部资源的请求发送cookie。 此属性有几个可能的值:Strict,Lax和None。
使用严格值意味着浏览器将不会从与当前资源的域名不匹配的任何来源发送cookie。
值lax使得不阻止来自外部资源的cookie成为可能(使用HTTPS协议以安全的方式进行了转换)。 松懈在可用性和安全性之间取得了平衡。
设置属性非常简单:
Set-Cookie: JSESSIONID=xxxxx; SameSite=Strict Set-Cookie: JSESSIONID=xxxxx; SameSite=Lax
在撰写本文时,浏览器对属性的支持如下所示:

重要的是要记住,该属性应该用作保护的附加措施,而不是不使用CSRF令牌的一种方式。
检查标题如上所述,一种保护方法是检查请求标头的引用者和原始值。
此检查的实质是检查服务器端标头的值。 如果它们与资源匹配,则该请求被视为正确,否则将被拒绝。 如果缺少Origin标头,则需要确保Referrer值与当前资源匹配。 OWASP建议拒绝不包含Origin或Referrer标头的请求。 您也可以记录所有此类请求,以便以后进行分析并决定如何处理它们。
但是,如果您的应用程序位于代理服务器后面,则事情会变得复杂,因为标头中的URL将有所不同。 在这种情况下,有几种选择:
•配置应用程序,以便您始终知道请求的来源。 如果您的应用程序部署在多个环境(例如,开发,质量保证,生产)中,则此方法的问题是设置正确的值,这会导致支持问题
•使用主机头。 无论环境如何,都可以使用此标头确定请求的来源。
•使用X-Forwarded-Host标头,其目的是存储代理服务器收到的原始标头
所有描述的方法仅在存在原始标头和引用标头时才起作用。 但是在某些情况下,这些标头会丢失。 在某些情况下,这些标头不包含在请求中:
•IE 11不包括受信任站点的Origin标头。 它仍然仅依赖于Referer标头。
•在重定向的情况下,请求中不包含Origin,因为它被认为可能包含不应发送给其他来源的机密信息
•为所有跨站点请求启用了Origin标头,但是大多数浏览器仅针对POST / DELETE / PUT请求添加标头
通常,少量流量属于所描述的类别,但是通常您甚至不想丢掉一小部分用户,因此,以原始值/引荐来源网址为空值或与受信任域列表相对应的值进行请求被视为有效。
两次提交Cookie
这种方法非常容易实现,不需要在服务器端存储令牌(无状态)。 该方法的本质是由用户在request参数和cookie中发送令牌。 每个需要状态更改的请求,我们都会验证Cookie和请求中令牌的值。 如果会话标识符的验证成功,但是时间图不成功,则可以认为该请求有效