安全 Rails 安全性小探

alsotang · 2013年04月29日 · 最后由 vivijie 回复于 2013年12月12日 · 7590 次阅读
本帖已被管理员设置为精华贴

原文在:http://fxck.it/post/49101760571/rails

背景:用户的电脑并未被植入任何木马,但当出了用户电脑的网卡后,面临着一个不安全的网络世界。下面提到的某些技术的基础知识就不涉及了,只涉及跟 Rails 相关的。


玩嗅探:

如果你是通过 HTTP 来访问一个已经登陆了的网站,那么只能说,这种方式的访问的安全性是永远无法保障的。随便一个人截取了你的 cookie 就可以冒充你登陆该网站。


玩逻辑:

CookieStore。

今天看资料的时候看到 ActionDispatch::Session::CookieStore 这个东西,它会把 session 存储中的相关信息存在用户的浏览器端然后加个指纹上去。而与加密有关的 secret 保存在 config/initializers/secret_token.rb 这个文件中。

这么说来,这个 secret_token.rb 肯定就不能给其他人看到咯,否则就存在被攻击者伪造任意 session 的可能。在部署开源的 Rails 相关项目时,除了 database.yml 这个文件需要隐藏外,有必要时,也需要隐藏 secret_token.rb 这个文件。

Rails 出箱(out of box)即附带了 session 的功能,所以不用进行任何设置就可以对针对某一用户的 session 进行操作。识别用户是通过 session_id 来的,session_id 可以认为是不可破解或猜测的,只能嗅探得到。

--

我还原了一下 ruby-china 在我浏览器上设置的 session(抹掉了信息,只保留了格式)

{"session_id"=>"06fd9f57exxxxxxxxxxxxxxxxxxxx0dd", "_csrf_token"=>"eddCzjiFBIeGrrxxWxxxxxxxxxxxxxxxxxxxxps+Hxc=", "warden.user.user.key"=>["User", [1848], "$2a$10xxxxxxxxxxxxxxxKDX.YIpO"]} 首先 session_id 这关的伪造肯定过不了。

_csrf_token 貌似在我们的话题中不是很必要。

warden.user.user.key 虽然表露出:我在 User 表中,且 id 是 1848(我是 ruby-china 的 1848 号会员),但是 warden 在后面加了个 digest,所以也无法伪造。这个 digest 应该是存在于 User 表中的某个字段里。

--

很多时候,如果我们并没有 devise 或者 warden 这样的库的时候,我们会简单地保存 user_id 这个值在 session 中(用的时候,会在服务端取出 session[:user_id] 来得到 current_user)。在这样的情况下,如果不小心暴露了自己的 config/initializers/secret_token.rb 文件,那么,攻击者就可以简单地把 user_id 修改为其他用户的,并通过适当的算法得到 CookieStore 生成的那个 digest,然后 do evil。

这点需要好好注意。

--

以上提到的『适当的算法』在此:https://github.com/joernchen/evil_stuff/blob/master/ruby/sign-cookie.rb

ruby-china 的 secret_token.rb 在此:https://github.com/ruby-china/ruby-china/blob/master/config/initializers/secret_token.rb

--

这么说来,独立开发者的 Web 开发学习成本真的很高啊....不仅前端后端,还要注意各种安全性问题。


玩 CSRF:

在 Rails 中,默认的 CSRF 机制貌似已经挡掉这个攻击方式了。

CSRF 虽然是个危害不小的技术,但是当网站在应用了某个 CSRF 的中间件时(Rails provide it out of box),就已经能成功阻挡这类攻击了。除非....


玩 XSS:

...除非玩 XSS。其实 CSRF 跟 XSS 这两类攻击还是分得蛮开的,记得 cnodejs 有一次被大家玩 XSS 玩疯了,我当时也中了招。如果你的网站可以被人插入 JS 代码进行 XSS 攻击的话,HTTPS 和 CSRF 之类的东西就都无法保住用户的安全了,用户只能被随意宰割。


防护:

关于 Rails 的安全性,这篇 guides 还挺好看的:

http://guides.rubyonrails.org/security.html

XSS 和 CSRF 的话,也推荐两篇我收藏的文章:

  1. http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html

  2. http://snoopyxdy.blog.163.com/blog/static/60117440201284103022779/ (正是此牛人带头玩起了 cnodejs 的 XSS 游戏)

还是 rails 好啊,这些问题可以在用户不知情的情况下就解决掉了

逻辑攻击那块可以成功吗?如果可以成功有点危险的。

#1 楼 @jasl 好东西,收了!

#3 楼 @jjym 对的,Rails 毕竟『重』嘛~

#4 楼 @zlx_star 是可以成功的。因为 CookieStore 之所以效率高正是因为 session 的相关信息都存在了用户的浏览器这里,服务器那边因此就不必通过任何 database 就可以取到特定 session 的 data 了。

可是存在用户浏览器这里的 data(以 marshal 之后 的 hash 形式存在,并用 base64 编码)是没有加密的,于是用户可以随意改动。为了保持数据的完整性,Rails 就会在用户浏览器的 Cookie 中再保存一段 digest,到时候如果用户更改了 session data,那么 digest 就会不一致导致验证无法通过,从而确保完整性。

而这个 Cookie 中的 digest 是怎么算出来的呢?可以认为是通过一个函数,这个函数接受 session_data_hash 和 secret_token 两个参数。

当 session_data_hash 可以被改动,而 secret_token 又被泄漏时,那么只要按照上述的生成过程再次生成一下 Cookie 中的 digest,服务器就会相信浏览器这边改动后的新 session 了。毕竟服务器是没有保存任何相关信息的。

可以把 session_store 设置为 redis 存储,这样能不能避免 session 用 cookie 存储带来的问题?具体原理不是很懂

#7 楼 @KoALa 这样就不能通过 cookie 知道 session 的内容了。

#7 楼 @KoALa #8 楼 @zgm 如果改用 redis 来存储的话,那么本地只会保存一个 session_id,其他的内容都会保存在 redis 里面,也就不存在暴露数据的问题了。不过我的看法是,用 Rails 原生的这个 CookieStore 都好了。理由如下:

  1. 只要你没有暴露自己的 secret_token.rb,攻击者也是无法伪造的。
  2. 速度快。
  3. ruby-china 已经算是一个五脏俱全的站点了,它的 CookieStore 里面也只是保存了每个用户对应的 user_id 而已。如果你用了 devise 或者 warden 的话,那么这个 user_id 也是带指纹的,这么一来即使暴露了 secret_token.rb 也同样无法篡改这个 user_id。

不知我文中还有什么解释不清楚的地方,可以留言交流交流,我也是正在学习当中。:)

#9 楼 @alsotang CookieStore 是 Rails 的默认模式,它的优点肯定不需要怀疑,除了你说的上面几点,还有一个最大的优势就是简单,初级使用者即使没有相关的知识,也很能轻松的使用 Rails 提供的 session,但是 Rails 同时也提供不同的解决方案,也是有它的道理的,即使不考虑安全性,cookie stroe 也有他的局限性,比如长度的限制。

你说的都蛮不错的。

路过。。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号