1. 相关概念

1.1 session

多数Web框架都有某种形式的Session管理: 为特定于某个客户端浏览会话的数据提供一个持久化的服务器端存储机制
Rails session存储方法提供了如下特性:

  • 机密性(Confidentiality): 除了服务器无人能读取在session中的数据
  • 完整性(Integrity): 服务器端之外无人能修改存储在session中的数据,除非抛弃旧的session再获取一个新的

Rails可以将所有session数据存储在服务器端,或者是基于cookies的session存储方案

2.2 csrf

跨站请求伪造(Cross-Sire Reuqest Forgery)攻击的步骤如下:

  • 通过被攻破的服务器或者攻击者在第三方Web站点上的script/img标签(很可能是通过XSS放置的),客户端可以从攻击者处接收代码。代码引用了目标应用程序上执行某个action的URI
  • 客户端请求来自目标应用程序的URI,发送认证cookies(因为客户端已经通过了目标站点的认证)。目标站点会执行客户端要的action,即使最终用户没有授权该action

用图表示:
csrf

2. 问题

redirect_to 到 某页面认证,之后post数据回来, session为null. 具体过程是用户访问A站点, A站点会验证用户的session, 若空session, 则跳转到B站点登录, 在B站点登录成功后, B站点后端会post登录用户的信息到A站点的一个api, 同时B站点再跳转回A, A站点通过B Post过来的数据进行用户验证, 保存Session, 于是用户愉快地登录了。然而我的问题是 B站点跳转回A的时候发现Session仍然是null, 于是陷入了无限跳转过程中。

3. 解决

假设B Post数据到A 的api是 http://hostofa:port/user, 而A在UserController的create方法中处理该事件, 则

class SafeController < ApplicationController
layout false
def create
// code to dispose data from B, then save session
end

以上为原代码, 无法生成session, 调试发现根本无法进入cretae方法
修改后的代码为:

class SafeController < ApplicationController
protect_from_forgery :except => :create
layout false
def create
// code to dispose data from B, then save session
end

问题得以解决。其实原因就是由于ApplicationController中会默认启用protect_from_forgery, 由于csrf的机制, A站点无法处理B站点Post过来的数据, 所以只要针对性的开放某api即可