V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
raincious
V2EX  ›  PHP

[求解] 这样分配Session钥匙安全么?

  •  
  •   raincious · 2013-12-08 22:27:54 +08:00 · 3960 次点击
    这是一个创建于 3790 天前的主题,其中的信息可能已经有所发展或是发生改变。
    好吧,我知道老是来这求解有点厚颜无耻,但是为了避免犯错,那么还是厚颜无耻一把好了。谢谢大家赐教。

    问题是这样的:如何保证Session是安全且不可伪造的。因为之后为了节省查询数,我想直接在数据库会话上绑定用户的数据,拿到这个Key就相当于得到了用户权限。

    [我现在的做法是,Session只作为记录客户活动状况的东西,只有createTime、updateTime和requests这几个字段,用户对应的权限使用另一套Ticket系统来实现。那套系统会给客户端颁发由用户ID和一串随机码组成的凭证来确认用户。但这就意味着多至少一次查询,而且我的架构为了速度和多数据库还不支持各种JOIN。]

    我想出的新方案是这样的:

    (1)通过将IP地址加入SessionKey的运算条件(整个要素由 IP + 两组随机数 + HTTP_USER_AGENT 组成),然后用MD5输出一段Hash作为Cookie的钥匙来实现。因为MD5快而且定长,这样数据表就好设计了。

    (2)这样输出了一段SessionKey,然后再用用户的IP + 这个SessionKey来Hash出另一段SessionVerifyKey。之后将这两个Key组合好发送给客户端(65个字符长)。

    (3)下次读出的时候,用返回的SessionKey + 用户的IP产生的Hash比对这个返回的SessionVerifyKey,如果一致就认为是合法的Session,否则就重新产生一个。

    实现的代码在这里:
    https://github.com/raincious/facula/blob/master/libraries/units/class.session.php#L231

    但问题是,MD5现在的碰撞率太高了,这样能否保证Session的钥匙无法被撞开呢?或者我最好还是守着旧方法就好了?

    而且我看了V2EX的Cookie,其中的auth应该就是Session钥匙,但貌似也只有一个Hash串呢?或者这样就足够安全了?
    21 条回复    1970-01-01 08:00:00 +08:00
    icanc
        1
    icanc  
       2013-12-08 22:51:40 +08:00   ❤️ 1
    如果没有大量用户,谈不上碰撞。如果真的有人想碰撞,楼主考虑的应该是如何应付CC攻击了。
    ejin
        2
    ejin  
       2013-12-08 23:15:37 +08:00
    什么叫md5碰撞率太高了啊 你不会把它伪装成sha1么,伪装成其他样子的么,md5是16位你就一定要坚持16位?只要别人没办法拿到你的源码,谁知道你的是什么算法,或者根本就是你自己的算法?

    明明是sha1你可以伪装成md5,md5也可以伪装成sha1,这又不是什么难的,非要告诉别人你是什么什么什么算法,通过什么什么什么来计算出这个值,你这不是自己找不自在么

    要想碰撞,那也要知道你是什么算法才行啊
    ejin
        3
    ejin  
       2013-12-08 23:17:41 +08:00   ❤️ 1
    哦哦 你是怕用户多了碰撞?那你加入几位随机码进去,要想碰撞没有个几亿年怕是不可能了哦,什么?几亿年后还有人上你……哦不是,是上你的网站?我觉得你想太多了
    dongbeta
        4
    dongbeta  
       2013-12-08 23:20:47 +08:00   ❤️ 1
    楼主想多了
    Livid
        5
    Livid  
    MOD
       2013-12-08 23:21:25 +08:00   ❤️ 1
    用户数量到几万这个量级的时候,SHA1 也是会碰撞的。
    bigcoon
        6
    bigcoon  
       2013-12-08 23:49:13 +08:00
    没有用户id么?
    txlty
        7
    txlty  
       2013-12-08 23:52:57 +08:00
    没太看明白。我在用户验证环节 不用session。
    把user & md5('pass'.'xxx') & 登陆时的随机码 连成一个字段,用康盛的authcode函数加密一下,存进客户端cookie [usr]字段。这个usr就包含用户登录所需的全部信息。
    用户名、md5密文、随机码 在登录成功后全部缓进memcache。以后直接比对缓存即可。
    这样能破不?
    9hills
        8
    9hills  
       2013-12-09 00:00:02 +08:00   ❤️ 1
    碰撞几率是能算出来的,任意两个MD5的碰撞几率是 1/(2^64)

    如@Livid 所说在几万的数量级连SHA1也会发生碰撞现象有点不可思议,求实例(两个SHA1一样的字符串)
    raincious
        9
    raincious  
    OP
       2013-12-09 00:00:51 +08:00
    @bigcoon 是的,这也是为啥当初要做个Ticket用来辅助。

    Session实现的方案当初只是为了在浏览器和网站之间实现唯一性识别做的。当然,如果能唯一识别了,绑定个用户在上面也应该没什么问题吧理论上。


    @txlty

    抱歉,我自己的规范是不允许以任何形式把用户的密码发回去。无论是怎么Hash或者加密的。
    kingwkb
        10
    kingwkb  
       2013-12-09 00:01:38 +08:00 via Android
    @Livid session id碰撞有好的解决办法么
    raincious
        11
    raincious  
    OP
       2013-12-09 00:06:38 +08:00
    @Livid @9hills 哈。我倒是想通了。这个架构目标支持的最大同时在线数(Session表里面最多)也就5000同时在线吧到顶。考虑到产生的数据都是临时的,这个碰到的概率太小了。

    所以如果用户的Cookie不失窃的话,理论不太可能出现问题了。所以我就决定暂时先这么办嗯。

    不过我现在倒是担心如果Cookie失窃的话这个机制是不是能继续保证用户数据安全了(如果盗窃方拿不到IP地址的话)。
    9hills
        12
    9hills  
       2013-12-09 00:07:45 +08:00   ❤️ 1
    @raincious 其实用secure_cookie(里面存用户ID)+ redis/memcache(存server side session)的性能也挺好

    放客户端就麻烦多了,安全性各种考虑
    raincious
        13
    raincious  
    OP
       2013-12-09 00:15:17 +08:00
    @9hills 嗯,倒是。但是这牵扯到另一个问题:我懒。不想未来要给框架维护那么多服务器。

    而且我现在只是在设计接口,所以目前这套东西最后的最后只是丢出一个合法的SessionKey给用框架的家伙注册的函数,剩下的他自己解决了(想要读数据库什么的随便嗯)。我自己保证架构什么的越简单越好。

    反正就我自己的测试这样的设计。。。还算凑合吧,只要这样注册下,未来调用很方便嗯。。。
    https://gist.github.com/raincious/7859598
    9hills
        14
    9hills  
       2013-12-09 00:15:23 +08:00   ❤️ 1
    @raincious cookie可以参考下Tornado的Secure Cookie,只要server那段的secure key不泄漏,cookie是无法伪造的

    但是失窃么,所以用全程HTTPS吧,这样只能在client端窃取(client端被攻陷神仙也防不住)
    raincious
        15
    raincious  
    OP
       2013-12-09 00:22:39 +08:00
    @9hills 好的。我去看看。谢谢建议嗯。
    crny520
        16
    crny520  
       2013-12-09 08:56:25 +08:00
    @raincious 这是PHP5.4还是5.3新增的语言?
    raincious
        17
    raincious  
    OP
       2013-12-09 09:34:17 +08:00
    @crny520 是啊,用到了5.3的匿名函数:http://www.php.net/manual/en/functions.anonymous.php
    est
        18
    est  
       2013-12-09 11:11:01 +08:00
    担心md5碰撞就是地命海心。

    王小云的那个思路做出来的结果也只能是2个不同长度的字符串得到相同md5。还飞jb长。还是non-ascii 不可打印的字符为主。

    如果散列有那么容易碰撞,那就不叫散列了。那个叫车祸现场列。
    raincious
        19
    raincious  
    OP
       2013-12-09 11:47:06 +08:00
    @est 但是为了安全还是地命海心吧。程序质量更高,就不用担心过一段时间得重构什么的了。而且这样折腾下来速度也不会变慢很多。

    MD5这东西看似安全,但概率问题还是说不定的,我自己就在搜狐社区(不过是很多年前了)和优库(去年)的时候撞到了别人的Session里。所以感觉这方面还是小心为妙。
    est
        20
    est  
       2013-12-09 14:01:15 +08:00
    @raincious 这个session串用户了,确定和md5碰撞有关?
    raincious
        21
    raincious  
    OP
       2013-12-09 15:14:22 +08:00
    @est 不完全确定,但是清理掉了Cookie就解脱了。所以猜测是这样罢了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3226 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 13:24 · PVG 21:24 · LAX 06:24 · JFK 09:24
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.