这听起来有点邪恶,不过请耐心听我说。这也不是一个专门的Rails问题,尽管这两个站点使用Rails。(提前为这两件事道歉)
想象两个都使用Ruby on Rails的网站:
-
mysite.com,我是一个开发人员,在改变代码等方面有完全的访问权限,也有一个管理员登录,所以我可以管理用户帐户。
-
theirsite.com,我有一个管理员登录,但没有开发访问。我认识管理它的人,但我宁愿不要出于政治原因向他们寻求任何帮助。
使用我的admin登录在每个网站上,我已经为同一个人做了一个用户帐户。当他们登录到mysite.com,我希望能够提供一个按钮,记录他们直接进入他们的网站。我有他们的用户名和密码为theirsite.com存储在他们的用户记录在mysite.com数据库,以方便这一点。这个按钮是一个表单的提交按钮,它复制了theirsite.com登录页面上的表单,隐藏了用户名和密码字段。
绊脚石是theirsite.com处理CSRF与一个authenticity_token
变量,这是失败的验证,当登录从mysite.com提交。
我的第一次尝试是,在mysite.com控制器中加载带有表单的页面,以抓取theirsite.com登录页面以获得真实性令牌,然后将其插入我的表单。但是这行不通。
如果我加载theirsite.com登录页面,和mysite.com页面与远程登录按钮在两个浏览器选项卡中,并手动复制authenticity_token从theirsite.com表单到mysite.com表单,然后它的工作。这是因为(我认为)的authenticity_token链接到我的会话通过一个cookie,当我做这一切在同一浏览器会话匹配,但当我得到真实性令牌从theirsite.com通过抓取(使用Nokogiri,但我可以使用curl代替)它不是相同的会话。
问题A)所以,我认为我还需要设置一个cookie,以便在浏览器和Nokogiri请求之间匹配会话。但是,这可能是不可能的,而这正是反csrf系统设计的目的。是这样吗?
问题B)假设我决定,尽管有政治因素,我需要要求theirsite.com的所有者做一个小改变,允许我在知道用户的用户名和密码的情况下登录他们的网站。我能要求他们做出的最小、最安全的改变是什么?
请随意说"滚开,你这个邪恶的黑帽子",我认为这是一个有效的回应。这个问题有点棘手。
A)不,这是不可能的,因为CSRF保护仅用于防止此类操作。所以"滚开,你这个邪恶的黑帽子"
根据问题,我假设theirsite.com正在使用Rails(v3或v4)
B)你可以要求他们做的最小的改变是为你做一个特殊的动作,这样你就可以从你的后端传递用户凭证,用户将从他们的上登录。
这个动作将像这样工作:
您将有一个特殊的代码,该代码将与凭据一起传递,以便在他们的服务器上验证请求。该代码可以是静态的预定义代码,也可以在两个站点上使用相同的算法以分钟/小时/天为基础生成。
您将要求为您创建的函数将像这样:
Rails v3和v4:
此操作将仅用于POST。
#I'm supposing 'protect_from_forgery' is already done in theirsite.com
class ApplicationController < ActionController::Base
protect_from_forgery
end
#changes to be made are here as follows
class SomeController < ApplicationController
skip_before_filter :verify_authenticity_token, only: [:login_outside] #this turns off CSRF protection on specific actions
def login_outside
if(#check special code here)
#Their login logic here
end
end
end
查看此链接了解在Rails中跳过CSRF保护的更多信息
Rails 4
这应该不难做到。
您需要发送一个ajax GET请求到他们的注册页面,用javascript复制authenticity_token,然后发送一个ajax POST到实际的登录路由,该路由使用正确的凭据和authenticity_token创建会话。
一个棘手的部分是找到他们的登录路线。试试/sessions/new
,或者他们在表单中有url,所以看看那里的html。好运!
另一个棘手的部分是知道通常如何发送参数。查看表单的html。如果所有的input
标签在它们的名字之前都有user_
,那么你需要类似地构造你的参数;即user_email
, user_password
。
获取crsf令牌并提交自己的表单是完全可能的(因为任何人都可以访问登录页面!)然而,很难知道他们安排的细节。猜测和检查并不是太糟糕的选项(再次,/sessions/new
是我如何路由我的登录;你也应该试试你的路线,看看他们是否有相似的路线。
如果这不起作用,试着看看他们的github帐户!很有可能他们没有每月支付7美元,而且它是向公众开放的。通过这种方式,您可以轻松地查看它们的路由和参数解析。
祝你好运!
这是不可能的。反csrf的工作原理是这样的:向用户发送cookie,并以隐藏字段的形式注入令牌到表单中;如果令牌与cookie相匹配,则接受表单post。现在,如果你在你的端运行form,你不能设置cookie(因为cookie只能在其源域设置)。
如果你只是想在他们的网站上执行一些特定的操作,你可以摆脱浏览器自动化。(例如,在服务器端运行浏览器,编写操作脚本并执行)。
对于B)最安全和最小的变化是矛盾的:)最小的变化是为他们的POST请求创建处理程序,你将发送用户名和密码(这个处理程序必须在https上运行),它将在他们的一侧创建验证cookie。
至于最安全-存储加密(非散列)密码的整个概念充其量是有问题的(您希望您的网站在这里列出http://plaintextoffenders.com/?)此外,如果用户更改了自己的密码,你就完蛋了。安全的解决方案是,您将只存储3pty UserID在您的一方,您将发送不对称加密的UserID与时间戳到他们的一方(您将加密它与您的私钥)。他们将解密它(他们必须有公钥),验证时间戳是否太旧,如果不是,他们将为给定的用户id创建验证cookie。也有相应的协议(如SAML)。
A)你所做的实际上是一种CSRF攻击。
跨站点请求伪造攻击背后的思想是攻击者欺骗浏览器以某个站点上的用户身份执行操作,即使用该站点的用户。用户通常由存储在cookie中的会话标识符标识,并且cookie会自动发送。这意味着如果没有保护,攻击者将能够在目标站点上执行操作。
为了防止CSRF,站点通常在页面中包含一个反CSRF令牌,该令牌与会话绑定,并在合法站点发出的请求中发送。这是因为令牌是不可预测的,攻击者无法从合法站点的页面读取令牌值。
我可以列出绕过CSRF保护的各种方法,但这些都依赖于反CSRF机制的不正确实现。如果您设法这样做,您已经在theirsite.com中发现了安全漏洞。
有关CSRF的更多背景信息,请参见https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)。
B) 他们可以做的最小的改变是禁用登录页面的CSRF保护检查。
CSRF保护依赖于请求的不可预测性,对于登录页面,秘密密码本身可以防止CSRF。没有必要通过反csrf令牌进行额外的检查。