18

Django 带有CSRF 保护中间件,它生成一个唯一的每个会话令牌以在表单中使用。它扫描所有传入POST请求以获取正确的令牌,如果令牌丢失或无效,则拒绝请求。

我想对一些 POST 请求使用 AJAX,但是说请求没有可用的 CSRF 令牌。这些页面没有<form>可以挂钩的元素,我宁愿不要混淆将标记作为隐藏值插入的标记。我认为这样做的一个好方法是公开一个 vew 喜欢/get-csrf-token/返回用户的令牌,依靠浏览器的跨站点脚本规则来防止敌对站点请求它。

这是一个好主意吗?是否有更好的方法来防止 CSRF 攻击,同时仍然允许 AJAX 请求?

4

3 回答 3

16

更新:以下是正确的,如果所有浏览器和插件都正确实施,则应该是正确的。不幸的是,我们现在知道它们不是,并且浏览器插件和重定向的某些组合可以允许攻击者在跨域请求中提供任意标头。不幸的是,这意味着即使是带有“X-Requested-With: XMLHttpRequest”标头的 AJAX 请求现在也必须受 CSRF 保护。因此,Django不再免除 Ajax 请求的 CSRF 保护

原始答案

值得一提的是,保护 AJAX 请求免受 CSRF 影响是不必要的,因为浏览器不允许跨站点 AJAX 请求。事实上,Django CSRF 中间件现在自动免除 AJAX 请求的 CSRF 令牌扫描

这仅在您实际检查 X-Requested-With 标头服务器端的“XMLHttpRequest”值(Django 所做的)并且仅从 CSRF 扫描中免除真正的 AJAX 请求时才有效。

于 2009-02-10T17:55:11.613 回答
14

如果您知道 AJAX 请求需要 CSRF 令牌,您可以随时将其嵌入到 HTML 中的某处;然后你可以通过 Javascript 通过遍历 DOM 找到它。这样,您仍然可以访问令牌,但不会通过 API 公开它。

换句话说:通过 Django 的模板来实现——而不是通过 URL 调度程序。这种方式更安全。

于 2008-09-28T01:36:36.050 回答
1

取消那个,我错了。(见评论。)您可以通过确保您的 JSON 遵循规范来防止利用:始终确保您返回一个对象字面量作为顶级对象。(我不能保证不会有进一步的漏洞利用。想象一下浏览器在其 window.onerror 事件中提供对失败代码的访问!)

您不能依赖跨站点脚本规则来保持 AJAX 响应的私密性。例如,如果您将 CSRF 令牌作为 JSON 返回,则恶意站点可能会重新定义 String 或 Array 构造函数并请求资源。

bigmattyh 是正确的:您需要将标记嵌入到标记中的某个位置。或者,您可以拒绝任何具有匹配的引用者的POST 。这样,只有拥有过分使用软件防火墙的人才会容易受到 CSRF 的攻击。

于 2008-09-28T17:58:09.217 回答