CSRF 和 RESTful API (symfony2, php)

Posted

技术标签:

【中文标题】CSRF 和 RESTful API (symfony2, php)【英文标题】:CSRF and RESTful API (symfony2, php) 【发布时间】:2014-02-12 16:21:55 【问题描述】:

我正在使用 php/symfony2 开发 RESTful API。

Symfony2 带有开箱即用的 CSRF 保护,并且在使用普通表单数据时工作正常(它将 CSRF 令牌传递给表单,并且在回发时它期望嵌入在表单中的相同令牌)。

但是,如果您开发 RESTful API,我的后端前端之间的通信纯粹基于 JSON,则此解决方案不适合此目的。因此我禁用了 CSRF。

我知道没有 CSRF 令牌是不安全的,所以我想知道使用 RESTful API 使用 CSRF 的最佳方式是什么。

一个想法是有特定的网址,例如/api/generate/csrf,可以被前端调用,然后将token附加到json请求中。这听起来不是最安全的方式,因为从技术上讲,任何人都可以生成令牌。

在开发 RESTful API 时解决 CSRF 问题的最佳方法是什么。

干杯, 理查德

【问题讨论】:

您现在用于 API 的客户端是什么?这是另一个 Web 服务、移动应用程序还是前端客户端(如 angular/backbone/ember)。如果您使用第一个或第二个选项,答案可能与最后一个选项完全不同。 @Jurian Sluiman 客户端(前端)目前是基于 Web 的(html5/js)。不过未来可能还需要支持其他设备,所以我不想将自己局限于网络。 【参考方案1】:

请记住,只有当您的 REST 客户端使用基于会话的身份验证时,您才需要 CSRF 保护,否则 CSRF 保护将无济于事。

如果您的请求确实使用基于会话的身份验证,我会将 CSRF 令牌作为标头包含在内。比如:

CSRF-Token: dfsa0jr3n2io20a;

【讨论】:

不幸的是,REST 客户端正在使用基于会话的身份验证(我知道它并不完美,但目前就是这样)。我知道有一些方法可以将 CSRF 令牌作为标头传递,但是我该如何获得呢?通过调用例如得到一个/api/give/me/token 一个安全的赌注? 您应该在服务器上生成 CSRF 令牌并将其放入页面中。然后,当客户端使用该令牌发出请求时,您确定该请求来自该页面。这就是想法。像 Symfony 这样的框架会自动为您执行 Forms,但您这里有一点特殊情况,所以您应该自己实现它。 所有从客户端传递过来的数据都是 json 格式。在这种情况下,后端不会为前端生成任何表单。我知道我可以创建一个特殊的电话,例如/api/token,它将返回令牌,然后我可以将其附加到 json,这将被发送到服务器。该解决方案的问题在于,潜在的攻击者还可以访问 /api/token 以生成令牌并添加到攻击者的虚假 json 请求中 您不应该通过单独的请求获取令牌,您应该在执行 API 调用的页面中包含令牌,以便 API 调用可以再次发送此令牌。 Qoop 是对的。头版不是由服务器生成的。那么,如何获取token呢?【参考方案2】:

我也在处理这个问题。这是我的original question。

到目前为止,我有一个理论上的解决方案,但我不太确定它是否会奏效。也许有人可以发表评论。

    将CSRF TOKEN添加到JS应用可读的API响应cookie中; 由 JS 应用程序将其作为 X-CSRF-TOKEN 标头值与请求一起发送; 在 API 上验证 CSRF TOKEN。

【讨论】:

以上是关于CSRF 和 RESTful API (symfony2, php)的主要内容,如果未能解决你的问题,请参考以下文章

如何将 flask.url_for() 与 flask-restful 一起使用?

Feign 接入第三方restful api 入门

如何将cas restful api 获取到用户信息后

http 的 restful api 的 put 请求,参数放在哪儿?

拥有 POST'able API 和 Django 的 CSRF 中间件

Laravel路由api没有api密钥和csrf令牌