如何避免cookie伪造? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
supersheep
V2EX    PHP

如何避免cookie伪造?

  •  
  •   supersheep 2011-06-04 13:55:12 +08:00 14649 次点击
    这是一个创建于 5244 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我用的php,初学者的做法一般就是
    这样设置

    setcookie('username','xxx',time()+3600*24);
    setcookie('password','xxx',time()+3600*24);

    再这样读取

    $logged = false;
    $username = @$_COOKIE['username'];
    $password = @$_COOKIE['password'];
    if(isst($username)&&isset($password)){
    $logged=true;
    $user = getUser($username,$password);
    }

    这种做法的话用户名和密码就都是明文保存在本地的,不安全对吧。
    那我可以加密后再保存到cookie里,登陆的时候再在后台程序里解密,加解密的方法只有我自己知道。
    这样是可以避免用户名密码泄露,但是要通过cookie伪造登陆应该还是很方便。
    我想知道后者一般是如何避免的?谢谢指教。
    26 条回复    1970-01-01 08:00:00 +08:00
    manhere
        1
    manhere  
       2011-06-04 14:05:25 +08:00
    用session啊
    Hyperion
        2
    Hyperion  
       2011-06-04 14:08:09 +08:00
    session+1 cookie是绝对不可信的
    icyflash
        3
    icyflash  
       2011-06-04 14:10:09 +08:00
    cookies+session
    icyflash
        4
    icyflash  
       2011-06-04 14:11:59 +08:00
    不过伪造登陆的话,除非你把会话状态时间设置很短或关闭浏览器就清除,不然抓包后都可以伪造的
    reus
        5
    reus  
       2011-06-04 17:00:46 +08:00
    $key = rand(0, 65535);
    //然后把$key存起来,每个用户都不同的
    setcookie('username', $username, xxx);
    setcookie('sig', sha1($username . $key . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']), xxx);

    验证的话:
    $logged = false;
    $key = get_key($_COOKIE['username']);
    if (sha1($_COOKIE['username'] . $key . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']) == $_COOKIE['sig']) {
    $logged = true;
    }
    supersheep
        6
    supersheep  
    OP
       2011-06-04 17:10:40 +08:00
    @icyflash @Hyperion @manhere 下午一直在看cookie+session验证的内容。
    大致思想似乎是把sessionid存在cookie里,然后每次只通过session来确认状态,这个我能明白。
    但是关闭浏览器就失效了,这个时候cookie里的session就只是一个值而已了。是不是要把相关信息存在数据库里?具体要怎么做,我有点迷糊。

    @reus 的方法看明白了,这个$key也是存在数据库里吗?感觉随机数也有一定的重复概率啊,不过好像这里重复也没有关系。
    reus
        7
    reus  
       2011-06-04 17:22:43 +08:00
    @supersheep 就是动态密钥,其实你全部用同一个密钥也是ok的,风险会大些
    要伪造一个cookie那必然需要知道加密密钥,而通过sha1或者md5过的字符串是不能反推出密钥的,所以没法伪造
    把ip和user-agent加入加密过程里可以对抗cookie泄漏,不是那个ip那个浏览器,泄漏了也不能用
    挺安全的,除非你机器整个被拿下……
    reus
        8
    reus  
       2011-06-04 17:26:35 +08:00
    哦,还要把密码也加进去,这样密码修改以后,验证也会失效,用来防止密码泄漏
    sha1($username . $password . $key . $ip . $user_agent) 这样
    supersheep
        9
    supersheep  
    OP
       2011-06-04 17:28:52 +08:00
    @reus 嗯,你的方法我看明白了,就是要多开一个地方存这个key。另外还是想继续听听前几楼的见解。
    reus
        10
    reus  
       2011-06-04 17:30:09 +08:00
    @supersheep 觉得麻烦可以用同一个key啊,phpmyadmin就是只用一个key的,在配置文件里面可以看到
    supersheep
        11
    supersheep  
    OP
       2011-06-04 17:32:05 +08:00
    @reus 嗯,先用这种方式好啦,谢谢哈!
    Livid
        12
    Livid  
    MOD
    PRO
       2011-06-04 17:34:31 +08:00
    嗯,赞成 8 楼的做法。

    在 cookie 里存 session id。

    在服务器上存 session data。session data 有 user id 及第一次验证成功时的 IP 和 user-agent。

    session data 在每次读取出来之后,进行验证,如果发现 IP 或 user-agent 有变,那么就撤销此 session。
    supersheep
        13
    supersheep  
    OP
       2011-06-04 17:41:17 +08:00
    @Livid 如何根据cookie里存的session去获得服务器上对应的session data呢?
    @reus 想到,验证需要password的话,password是存在哪里呢?
    reus
        14
    reus  
       2011-06-04 17:42:43 +08:00
    @Livid 如果不验证密码,那如果密码泄漏了,即使自己修改了密码,窃取方也还是可以成功验证的,所以需要保证密码修改之后所有session都失效
    Livid
        15
    Livid  
    MOD
    PRO
       2011-06-04 17:43:15 +08:00
    @supersheep 服务器的 MySQL 数据库有一张 session 表,PK 是 session id,也就是在客户端 cookie 里存的那个 session id。

    另外,我觉得都 2011 年了,可以考虑不用学 PHP 了,建议你看看这个:

    http://www.v2ex.com/tornado/index.html
    manhere
        16
    manhere  
       2011-06-04 17:44:15 +08:00
    @supersheep
    验证需要password的话,password是存在哪里呢?

    password肯定在服务器端,验证并不是要返回密码给客户端,只是给它一个合法的身份。
    reus
        17
    reus  
       2011-06-04 17:44:46 +08:00
    @supersheep password就在数据表里面啊,就是再次生成一次加密串,看和cookie里面的是否一样,一样就是合法的否则非法
    supersheep
        18
    supersheep  
    OP
       2011-06-04 17:47:05 +08:00
    @Livid php也不算深入,只不过是自己目前实现想法最顺手的工具,还有就是部署方便。python有机会再研究吧,gae被墙多少会有点儿别扭。感谢推荐。
    reus
        19
    reus  
       2011-06-04 17:58:48 +08:00
    部署方便也是我还在用php的原因,因为SAE只支持php,做面向国内大众的站,这是成本最低的方式了,免费空间和流量
    虚拟主机也不难找,选择多
    python或者rails的话,没有虚拟主机,都必须用vps或者独立主机,这个成本太高了,国内的话。国外的vps网速是不够的
    php语言本身是很不好的,嗦,函数命名不规范,写起来不美观。解决方法是用这个 http://code.google.com/p/php-snow/ 或者 这个 http://fructoselang.org/
    或者干脆自己做个DSL,我选择了这个……
    Livid
        20
    Livid  
    MOD
    PRO
       2011-06-04 17:59:58 +08:00
    V2EX,豆瓣,知乎,42区,下厨房……国内其实已经有不少网站是完全用 Python 做的了。
    reus
        21
    reus  
       2011-06-04 18:09:26 +08:00
    我也是用python来做php的代码生成器..
    supersheep
        22
    supersheep  
    OP
       2011-06-04 18:13:10 +08:00
    @reus 平时js写得比较多,一到php里发现不能把函数当参数传,函数返回数组不能直接用[]引用什么的就觉得很不爽……
    lijia18
        23
    lijia18  
       2011-06-04 18:27:46 +08:00
    伪造是挡不住的,唯一靠谱的方法是随机一个字符串。
    reus
        24
    reus  
       2011-06-04 18:48:14 +08:00
    @supersheep 是啊,语言那是相当的不现代…
    walleve
        25
    walleve  
       2011-06-04 18:53:56 +08:00
    不用就是最安全的。

    建议直接数据库存储cookie/session
    supersheep
        26
    supersheep  
    OP
       2011-06-04 19:32:08 +08:00
    @Livid 写着写着又有不明白了,ua和ip的信息应该已经隐含在cookie里了,为什么还要在数据库里存一份呢?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2684 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VESION: 3.9.8.5 24ms UTC 14:52 PVG 22:52 LAX 07:52 JFK 10:52
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86