公开会话的CSRF保护令牌是否安全?
Django随附CSRF保护中间件,该中间件生成用于表单的唯一的每次会话令牌。它扫描所有传入的" POST"请求以获取正确的令牌,如果令牌丢失或者无效,则拒绝该请求。
我想对某些POST请求使用AJAX,但表示请求没有CSRF令牌。这些页面没有可插入的<form>元素,我宁可不要弄混将标记作为隐藏值插入的标记。我认为实现此目的的一种好方法是公开/ get-csrf-token /
之类的vew以返回用户的令牌,这依赖于浏览器的跨站点脚本编写规则来防止恶意站点请求它。
这是一个好主意吗?在允许AJAX请求的同时,有没有更好的方法来抵御CSRF攻击?
解决方案
如果我们知道将需要CSRF令牌来进行AJAX请求,则可以始终将其嵌入到HTML中。那么我们可以遍历DOM并通过Javascript找到它。这样,我们仍然可以访问令牌,但不会通过API公开令牌。
换句话说,请通过Django的模板进行操作-而不是通过URL调度程序进行操作。这样更安全。
取消那个,我错了。 (请参阅注释。)我们可以通过确保JSON遵循规范来防止漏洞利用:始终确保将对象文字作为顶级对象返回。 (我不能保证不会再有其他利用。想象一下,一个浏览器提供了对其window.onerror事件中失败代码的访问!)
我们不能依赖跨站点脚本编写规则来使AJAX响应不公开。例如,如果我们将CSRF令牌作为JSON返回,则恶意站点可能会重新定义String或者Array构造函数并请求资源。
bigmattyh是正确的:我们需要将令牌嵌入标记中的某个位置。或者,我们可以拒绝引荐来源不匹配的所有POST。这样,只有拥有过多软件防火墙的人才容易受到CSRF的攻击。
更新:以下是正确的,如果所有浏览器和插件都正确实现,则应该正确。不幸的是,我们现在知道它们并非如此,并且浏览器插件和重定向的某些组合可以使攻击者可以在跨域请求中提供任意标头。不幸的是,这意味着即使带有" X-Requested-With:XMLHttpRequest"标头的AJAX请求现在也必须受CSRF保护。结果,Django不再从CSRF保护中免除Ajax请求。
原始答案
值得一提的是,无需保护CSRF的AJAX请求,因为浏览器不允许跨站点的AJAX请求。实际上,Django CSRF中间件现在可以自动从CSRF令牌扫描中免除AJAX请求。
仅当我们实际上在服务器端X-Requested-With标头中检查" XMLHttpRequest"值(Django这样做)并且仅从CSRF扫描中排除真实的AJAX请求时,此方法才有效。