Django附带CSRF protection middleware,它生成一个唯一的每会话令牌,用于表单。它会扫描所有传入的POST
请求以获取正确的令牌,并在令牌丢失或无效时拒绝该请求。
我想在某些POST请求中使用AJAX,但是说请求没有CSRF令牌可用。这些页面没有<form>
元素可以挂钩,我宁愿不把标记作为隐藏值插入标记。我认为这样做的一个好方法是公开像/get-csrf-token/
这样的vew来返回用户的令牌,依靠浏览器的跨站点脚本规则来防止恶意站点请求它。
这是个好主意吗?是否有更好的方法来防止CSRF攻击,同时仍然允许AJAX请求?
答案 0 :(得分:16)
更新:以下情况属实,如果所有浏览器和插件都已正确实施,则应为true。不幸的是,我们现在知道它们不是,并且浏览器插件和重定向的某些组合可以允许攻击者在跨域请求上提供任意标头。不幸的是,这意味着即使带有“X-Requested-With:XMLHttpRequest”标头的AJAX请求现在也必须受CSRF保护。结果,Django no longer exempts Ajax requests from CSRF protection。
原始答案
值得一提的是,保护来自CSRF的AJAX请求是不必要的,因为浏览器不允许跨站点AJAX请求。事实上,Django CSRF中间件现在automatically exempts AJAX requests from CSRF token scanning。
这仅在您实际检查X-Requested-With标头服务器端的“XMLHttpRequest”值(Django所做的)时才有效,并且只从CSRF扫描中免除真实的AJAX请求。
答案 1 :(得分:12)
如果你知道你需要为AJAX请求提供CSRF令牌,你可以随时将它嵌入HTML中;然后你可以通过遍历DOM找到它。这样,您仍然可以访问令牌,但您不会通过API公开它。
换句话说:通过Django的模板 - 而不是通过URL调度程序。这种方式更加安全。
答案 2 :(得分:1)
取消,我错了。 (请参阅注释。)您可以通过确保JSON遵循规范来阻止漏洞利用:始终确保将对象文字作为顶级对象返回。 (我无法保证不会有进一步的漏洞利用。想象一下,浏览器在其window.onerror事件中提供对失败代码的访问!)
您不能依赖跨站点脚本规则来保持AJAX响应的私密性。例如,如果您将CSRF令牌作为JSON返回,则恶意站点可以redefine the String or Array constructor并请求该资源。
bigmattyh是正确的:您需要将标记嵌入标记中的某个位置。或者,您可以拒绝执行具有不匹配的引用者的任何POST。这样,只有拥有过度热心的软件防火墙的人才容易受到CSRF的攻击。</ p>