【问题标题】:Doorkeeper::AuthorizationsController#create Can't verify CSRF token authenticityDoorkeeper::AuthorizationsController#create 无法验证 CSRF 令牌的真实性
【发布时间】:2015-07-03 20:08:25
【问题描述】:

我通过测试 API 关注了页面 https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Resource-Owner-Password-Credentials-flow

curl -F grant_type=password \
-F username=foo@bar.com \
-F password=mypass \
-X POST http://localhost:3000/oauth/token

我得到了回应:

{ “ACCESS_TOKEN”: “6d4398b75d94835631a453af770161a6f58618b101b58ccf62a5a8492bce3440”, “token_type”: “承载”, “expires_in”:600, “refresh_token”: “c1445d0a27a8278268c1187c2e3da7163525f1fac8093890430edd328f51c3de”, “created_at”:1429931390} P>

但是当我调用 /oauth/authorize 时:

curl -F response_type=6d4398b75d94835631a453af770161a6f58618b101b58ccf62a5a8492bce3440 \ -F client_id=9c291dc4aa87bfafd6c6a4cf6930d225c106f8fe88e1d0769832047f1ee011c4 \ -F client_secret=decba5aca425095978d33653ef03d654f0b74427bcec0596bdde518016708c35 \ -F redirect_uri=urn:ietf:wg:oauth:2.0:oob \ -F username=foo@bar.com \ -X POST http://localhost:3000/oauth/authorize

但我得到了:

在 2015 年 4 月 25 日 00:30:05 -0300 为 127.0.0.1 开始 POST "/oauth/authorize" Doorkeeper::AuthorizationsController#create as / 处理 参数:{ “RESPONSE_TYPE”=> “6d4398b75d94835631a453af770161a6f58618b101b58ccf62a5a8492bce3440”, “CLIENT_ID”=> “9c291dc4aa87bfafd6c6a4cf6930d225c106f8fe88e1d0769832047f1ee011c4”, “client_secret”=> “[FILTERED]”, “REDIRECT_URI”=> “瓮:IETF:WG:OAuth的:2.0:OOB” , "用户名"=>"foo@bar.com"} 无法验证 CSRF 令牌的真实性 在 1 毫秒内完成 422 个不可处理的实体 ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): ...

什么,我做错了吗?

【问题讨论】:

  • 这是预期行为。授权表单在提供程序应用程序中呈现为 HTML,幸运的是,Rails 默认检查它在表单中呈现的 CSRF 令牌是否与表单提交匹配。因此,没有该令牌的 curl 命令会引发“CSRF 验证失败”。
  • 这个我知道,但是我正在尝试使用doorskeep oauth2 来写一个API,并且API 没有呈现HTML。
  • 如果您了解风险,您可能希望为该控制器操作禁用 Rails 伪造保护。 Doorkeeper 没有为此提供选项,您需要重新打开该控制器。
  • 最好配置门卫 gem 以支持资源所有者密码凭证流 (github.com/doorkeeper-gem/doorkeeper/wiki/…),以防您希望允许 API 客户端询问用户名和密码。您使用的流程旨在将用户重定向到您的 Web 服务以安全登录,并且绝不会将您的用户凭据暴露给 3rd 方应用程序。
  • @MarcosSousa 你解决了这个问题吗?

标签: ruby-on-rails-4 doorkeeper


【解决方案1】:

如果您只使用 API,我猜您可以通过添加以下行在环境文件 (test/developpement/production.rb) 中简单地将其关闭:

config.action_controller.allow_forgery_protection = false'

干杯!

【讨论】:

  • 这是一个非常糟糕的主意,CSRF 保护是有原因的。在这种情况下,它保护了用户使用浏览器进行的部分 oauth 流程。
  • 这就是为什么我首先详细介绍了 API。如果没有任何浏览器访问,CSRF 保护并没有真正的用处。
【解决方案2】:

看起来您在第二个请求中使用了response_type 的令牌。我认为应该是authorization_code

但是,从第一个响应来看,它似乎给了您一个不记名令牌。如果是这样,那么要查看受保护的页面(有一个 before_action:doorkeeper_authorize)该命令将是

curl http://localhost:3000/protected_page -H "Authorization: Bearer 6d4398b75d94835631a453af770161a6f58618b101b58ccf62a5a8492bce3440"

OAuth2 库

你需要使用 curl 吗?我在使用 CSRF 真实性令牌时遇到了同样的失败,因为它认为这是一个表单请求,但我让它与 OAuth2 gem 一起使用。

/oauth/applications 注册一个应用程序(大概这是受保护的),转到它,单击Authorize,单击Approve,您会看到您已发布到类似http://localhost:3000/oauth/authorize?client_id=abc123&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&response_type=code 的网址 参数"utf8"=>"✓", "authenticity_token"=>"[FILTERED]", "state"=>"", "scope"=>"public" abc123 是您的一次性身份验证代码。

但是您还没有授权您的应用程序。所以,让我们获取 access_token 和 refresh_token。

client_id = "9c291dc4aa87bfafd6c6a4cf6930d225c106f8fe88e1d0769832047f1ee011c4"
client_secret = "decba5aca425095978d33653ef03d654f0b74427bcec0596bdde518016708c35"
site = "http://localhost:3000"
redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
code = "abc123" # see above
ENV['OAUTH_DEBUG'] = 'true'
client = OAuth2::Client.new(client_id, client_secret, :site => site)
token = client.auth_code.get_token(code, redirect_uri: redirect_uri)
access_token = token.token
refresh_token = token.refresh_token
# And if you want:
# if token.expired?
#   new_token = token.refresh!
#   new_token.token
#   new_token.refresh_token
# end

如果您转到http://localhost:3000/oauth/authorized_applications,您应该会看到您的应用程序现在在列表中。

现在,您可以使用curl -X GET http://localhost:3000/protected_page -H "Authorization: Bearer #{access_token}" 之类的内容查看受保护的页面

另见https://github.com/doorkeeper-gem/doorkeeper/wiki/API-endpoint-descriptions-and-examples

可能有用的信息:门卫正在寻找什么来验证验证码

redirect_uri.present?
grant = Doorkeeper::AccessGrant.by_token(authorization_code)
grant.redirect_uri == redirect_uri
application = Doorkeeper::Application.by_uid_and_secret(client_id, client_secret)
dk_client = Doorkeeper::OAuth::Client.new(application)
!!dk_client
grant.application_id == dk_client.id
grant.accessible? #  !grant.expired? && !grant.revoked?

【讨论】:

    猜你喜欢
    • 2012-05-08
    • 1970-01-01
    • 2017-07-15
    • 2015-07-24
    • 2014-06-16
    • 2015-12-29
    • 2023-03-26
    • 2016-09-17
    • 2017-07-19
    相关资源
    最近更新 更多