部署 多台机器上 Unicorn 共享 Session

6233843 · 发布于 2014年5月25日 · 最后由 jimrokliu 回复于 2014年8月11日 · 6811 次阅读
96
本帖已被设为精华帖!

Hi,各位 问一个找了几天都没有满意答案的问题,欢迎大家讨论。

Rails 默认的 Session 是 CookieStore,也就是存在 Cookie 里面,随着每次发送的 request 到服务器端,供服务器解析。

一旦我有多台机器,就会面临在A机器上登陆的用户可能下次请求被 redirect 到 B 机器而导致 Session 丢失。解决方案是使用数据库或者 Memcached 单独把 Session 存起来,这样多台机器都共同访问一个 Session 池,就不会发生上述问题了。

但我想,既然 CookieStore 是在 Cookie 里的,每次 request 里面既有 Cookie 也有 CookieSession,是不是 CookieStore 自然就能多机器共享 Session,而不用再搭建 Memcached 或者 DB 的 Session 池?

再请教大家都是怎么做的?有什么优缺点? 欢迎指教 :)

共收到 49 条回复
1

cookiestore 没有这个问题。

1

cookiestore 的限制是大小限制,cookies 不能超过大约4K大小,所以不要往 session 里面塞大的对象。

4002

ip-hash ,简单粗暴

The method ensures that requests from the same client will always be passed to the same server except when this server is unavailable.

http://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash

96

cookiestore适合不存储复杂对象的场景。如果你的应用不需要购物车这种复杂对象,你可以考虑cookiestore,后台任何一个服务器退出都不会影响用户的请求。

96

#2楼 @Rei 一般也不会往session里面塞其他东西吧

96

#3楼 @libuchao 这个太过于简单粗暴,这样一搞,负载均衡完全没用呀

96

#4楼 @jimrokliu 谢谢,我的猜测得到确认

1

#5楼 @6233843 新手常见的是:

session[:user] = current_user

推荐的是

session[:user_id] = current_user.id
202

cookie都是放在客户端,如果后台设计的差,直接篡改这个cookie就可以产生中间人攻击啦。还是用数据库来存吧。Mysql memory engine.

11871

#9楼 @xds2000 服务端session也依赖cookie, 劫持保存在客户端的session id照样能产生中间人攻击, 没区别, cookiestore保存好secret key安全性不会比传统session差。 mysql内存表坑很多, 比如不支持大字段, 就算是varchar照样按定长算,没特殊要求尽量别用这东西。

96

还是先把https搞起来吧

202

@tnt 有几点不同意你的观点:

  1. “cookiestore保存好secret key安全性不会比传统session差。” 首先,服务端session也是用secret key的。第二,session存客户端,劫持后可以直接用这个账号登录。但如果session在服务端,这个合法用户在知道劫持后是可以通过退出账号,直接让劫持的session无效的。你说说这安全性差在什么地方。
165

就像 @Rei 说的 cookiestore 不会出现你所说的 session 丢失,只是大小有限制,如果你遇到了使用 cookiestore 但是确实类似的情况,你可以检查下你不同服务器的 secret key 是不是一样,sercet key 用来验证和签名 cookie 的,如果不一样,最后表现的情况就像是 session 丢失。

2

cookie_store,或 dalli_store 轻松解决

config/initializers/session_store.rb

Rails.application.config.session_store ActionDispatch::Session::CacheStore, :expire_after => 20.minutes

Gemfile

gem 'dalli'
11871

#12楼 @xds2000

第一点不是很一致么 (1) 无论是cookie store还是传统的cookie(session id)<->server session, 就算再通过secret key加密, 劫持到cookie时已经算完了, 这方面除了ssl是没办法保障的。 (2) 不考虑劫持现象, 传统的cookie(session id)<->server session无法伪造, 但是cookie store的session在服务端secret key不泄漏的情况下, 同样无法伪造。 所以安全系数上是完全一致的。

第二点针对登出失效, 这是设计问题, 不是安全问题 cookie store的session检测用户时同样需要存在一个sign做验证(比如根据用户的密码和一个token字段), 用户登出完全可以重设生成这个sign所需要的token, 也就是说当用户登出或者修改密码时,原先保存在session里的sign已经失效了, 当然也就未登录了。

202

@tnt 首先,我要明确争论的论点是:Session存在客户端还是服务端, 我的观点是,存在客户端的session是有安全风险的,是对用户数据的不负责任的设计。

第二,对你 #15楼#10楼说的观点不赞同。 “cookie store的session检测用户时同样需要存在一个sign做验证(比如根据用户的密码和一个token字段)” 我为啥需要检测呢, 我本地已经有这个session了,我可以直接用就可以(假设session还没有过期)。

2

#12楼 @xds2000

session存客户端,劫持后可以直接用这个账号登录。但如果session在服务端,这个合法用户在知道劫持后是可以通过退出账号,直接让劫持的session无效的

劫持一样有效的,普通用户是很难知道自己是否被劫持的。

202

@huacnlee 是的,你说的是真实的情况。

@tnt 抱歉,我没有那事实和代码说话。但我看了你提到的淘宝session框架的技术。我觉的它的方案并不一定是普适的,任何技术都是有场景的。我们讨论的就是一般场景下的方案。而你提到的很多框架使用默认cookie来存session算是一个论据,我认可你这个理由。

我继续我的观点 存在客户端的session是有安全风险的,是对用户数据的不负责任的设计。,另外,我这里就是对通常情况的处理。任何观点在不同的场景下都是可以被打破的。

论点资料:

  1. Ruby on Rails Security Guide Django Security Guide 两个最流行的WEB框架对session存在cookiestore的说明,我认为如何用好cookiestore并不那么容易。

  2. Session storage and security in Rails 我看到的是有风险的存在。

  3. "Security Vulernability: Session Cookie Store" 用开源代码的key解session.

一般情况下,#14楼的方案就可以算是完美的,不赞成使用cookie_store,有安全限制,存储限制,设计限制。

8

用memcache或mysql memory engine存session就不怕重启的时候用户的session掉一地么?这就是对用户数据负责?

重放攻击和scret key泄露问题在正确使用的前提下是可以避免的,谁能保证自己的服务器不重启?

3787

用了好几年多台unicorn负载均衡的人表示从来没遇到过什么跨节点session丢失问题。cookiestore本身就是无状态的,不会绑定到任何一台web节点。

说客户端存储session有风险的,请仔细阅读相关源码,然后根据源码的实现原理制定出一个可操作的攻击方案,贴到这里一起讨论。都是搞技术的,希望不要光打嘴炮。

973

从共享的问题讨论到了安全的问题。 很多我们所谓清楚的技术都是"拿来主义",很多是没有亲自实验过的。 放进couchbase节点自动同步如何?

1286

咱们的回复 有点偏离 lz的本意了, 不过既然说到这了, 咱们就继续说说CookieStore的一个弊端:

如果使用CookieStore, 那么用户对应的session cookie就存到客户端, 这个时候 也就与服务器无关了, 也就是说你即使logout了,通过copy这个cookie 还是可以访问server的。这个文章有个演示

那么怎么让客户端cookie 失效呢

解决方法:

1、用户 主动 修改密码, 让之前的cookie 失效.(但是 试想用户主动 修改密码的 频率 实在太低) 2、修改secret_key, 是所有的cookie都失效(代价太大了, 应该直接不用这个方案)

回到 lz的 共享的session的问题:#14楼 huacnlee 给出了一个大众的方案.

2

#23楼 @meeasyhappy 用 Rails 默认的 CookieStore,靠谱的,保证 secret_key 安全就好了。

另外,纠正一下前面 #18楼 @tnt 说淘宝是 Cookie 存储 Session 的事情,我们之前内部调用过淘宝主站的 Session,原理是 Cookie 里面有个 session key,真正的 Session 数据是存储在服务端的(具体什么里面我不清楚,猜测应该是 Memcached 之类的),取信息通过 session key 调用某些接口获取

96

感谢大家的踊跃发言,这篇帖子已经成为精华帖了。。。

96

#23楼 @meeasyhappy cookie的加密不光有secret_key,还有个token,每个用户的都不一样,退出后重置这个token,cookie就失效了,不会影响到其他用户

96

cookieSession可以做到客户端共享,缺点是不安全。 如果是服务器端session,一般是两个思路: 1.多个节点本地存,然后数据同步,我不知道ruby有没有现成的方案做数据同步,优点是数据读取快,缺点是同步存在时间差,数据一致性差。 2.使用集中式的缓存服务存session,比如memcached或者redis存储。优点是数据一致性好,缺点是存在远程调用。 至于使用db做session存储的,也是一种方案,不过撑不住大的访问量。

4798

cookiestore have no problem

239

#28楼 @hmilym cookiestore has on problem

65

session存在cookie在学习项目中可以用用,但在真实应用中不推荐,缺点:安全和费流量;存数据库性能不行,建议存集中式缓存,比如memcache,14楼 @huacnlee 已经给出方案,一般解决到这也就满足系统需求了;但是如果有人说当某台cache服务器宕机了,不就存在session丢失吗?可以要看业务影响面;这个可以解决,但是要看你这系统有没有必要花精力去解决这个问题;解决cache单点问题,可以同一份数据存在多个cache服务器上,保证高可用;当然没有绝对的,如果整个cache集群所在的机房断电了呢?难道要做多机房热备?额,扯远了。觉得一般应用用集中式缓存存session就够了。

65

#18楼 @tnt 淘宝分享用加密cookie作为session方案(请搜"淘宝session框架")?淘宝不是在coookie里加密存session吧?据我了解是在服务器端用Tair(集中式高可用缓存)存储的。

96

默默爱上了redis,所以这个也许楼主愿意试试看,比db session store要轻巧一点。

https://github.com/redis-store/redis-rails

# config/initializers/session_store.rb
MyApplication::Application.config.session_store :redis_store
4499

rack代码里session下面的cookie实现,其实就是在浏览器里存储了session的key,seesion的value还是在内存的。叫cookie based session: https://github.com/rack/rack/blob/master/lib/rack/session/cookie.rb 代码里还有个memcache的session实现,就是把session的value存储在memcache里: https://github.com/rack/rack/blob/master/lib/rack/session/memcache.rb 要实现共享session,要考虑几方面: 1.安全,因此首选存在server 2.稳定,不能因server端crash而丢失session,要有持久化支持。 3.自动清除,客户端的cookie有效期是可以设置的,为避免server端session存储规模太大,也要支持expire后自动删除。 综上,使用基于redis和mongodb的session存储,都挺好: https://github.com/roidrage/redis-session-store https://github.com/yeezon/mongo_session 我在项目里,一直用mongo_session。 padrino里,指定session存储:

set :sessions, :use => Rack::Session::MongoSession, :config => {:host=>''...}
96

前几天怎好也在处理这个问题,多项目共享Session,我是通过Redis实现的,这是我整理的步骤,楼主可以参考一下:http://www.cnblogs.com/richard1234/p/3783689.html

967

@120791589 这样是要单点登陆吧,咋和楼主说的不是一个方向

134

session 数据本身肯定要存服务器的,至于是内存、memchaced、redis 还是数据库,就见仁见智了。存到客户端的就是 session key。

4906

#4楼 @jimrokliu 有复杂对象购物车也可以用cookie存储数据阿,购物车利的东西完全可以放在server端阿

96

#37楼 @wudixiaotie 主要是cookie有4k的长度限制,加上rails已经把用户的信息加密后存储在cookie中,你利用的空间不大。

4906

#38楼 @jimrokliu 完全可以只存储个用户标示,然后把相关的信息存到server端的数据库或者缓存层中,当然不能全放到cookie中了,上面有人都说过这样类似的方法了。

96

#39楼 @wudixiaotie 这种情况就不是利用cookie存储复杂对象了。

14358

这个页面在safari 7.0.3 页面搜索找不到 lee 这个词。好奇怪。

4906

#40楼 @jimrokliu 不明白为什么你要用cookie存储复杂对象,或者非要在客户端存储复杂对象,这样作能得到什么明显的有利的地方么????拿到是为了实现而实现????

96

#42楼 @wudixiaotie 我没有说过要用cookie存储复杂对象啊,我第一句话是“cookiestore适合不存储复杂对象的场景。如果你的应用不需要购物车这种复杂对象,你可以考虑cookiestore,后台任何一个服务器退出都不会影响用户的请求。”

4906

#40楼 @jimrokliu 不知道你这句话是什么意思?

96

#44楼 @wudixiaotie 是你问“不明白为什么你要用cookie存储复杂对象”呀,我说没有这回事呀。

4906

#45楼 @jimrokliu "这种情况就不是利用cookie存储复杂对象了。"这是啥意思?????

96

#46楼 @wudixiaotie 是这样的,当你cookie只是存储一个用户id,或者购物车id,真正的内容存储在database中,这样不是利用cookie存储复杂对象。我所指的用cookie存储复杂对象是利用cookie的4k大小,将一些信息序列话到cookie中。在cookie中存储有一些直接的好处,最直接的就是可以降低后端failover的复杂性,因为状态完全在cookie中,新增加服务器或者offline服务器都不会触发用户端的再登陆。当然,后端可以用redis的群集,数据库群集来实现可靠的session存储,但会增加系统整体的复杂性。

4906

#47楼 @jimrokliu 我感觉,与其花时间死扣4k的cookie的存储空间,不如把经历用在其他的地方,例如你上面自己提出的解决方案,首先你要明白一点,cookie本来就不是用来存储复杂对象的。再说,即便你想到办法把购入车的内容存到cookie里面,难道你要每个用户的购物车限制大小么???购物车东西过多,cookie溢出就告诉用户,hi 哥们,你少买点东西吧,或者你该结帐了。。。你这网站还想继续下去么????cookie设计的目的是为了保存用户的登录状态,习惯设置等等的信息,在用户关闭浏览器再次打开后不需要重新设置。你买个自行车然后在飞机论坛发帖子询问怎么让自行车飞起来,这完全是强人所难么!!!!!!!!!!

96

#48楼 @wudixiaotie 不是所有的系统都需要有个购物车的,楼主最早的问题是能不能省略掉后端的database store。所以我说“不存储复杂对象的话是可以的。”

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