如何避免cookie伪造?

2011-06-04 13:55:12 +08:00
 supersheep
我用的php,初学者的做法一般就是
这样设置

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

再这样读取

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

这种做法的话用户名和密码就都是明文保存在本地的,不安全对吧。
那我可以加密后再保存到cookie里,登陆的时候再在后台程序里解密,加解密的方法只有我自己知道。
这样是可以避免用户名密码泄露,但是要通过cookie伪造登陆应该还是很方便。
我想知道后者一般是如何避免的?谢谢指教。
14104 次点击
所在节点    PHP
26 条回复
manhere
2011-06-04 14:05:25 +08:00
用session啊
Hyperion
2011-06-04 14:08:09 +08:00
session+1 cookie是绝对不可信的
icyflash
2011-06-04 14:10:09 +08:00
cookies+session
icyflash
2011-06-04 14:11:59 +08:00
不过伪造登陆的话,除非你把会话状态时间设置很短或关闭浏览器就清除,不然抓包后都可以伪造的
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
2011-06-04 17:10:40 +08:00
@icyflash @Hyperion @manhere 下午一直在看cookie+session验证的内容。
大致思想似乎是把sessionid存在cookie里,然后每次只通过session来确认状态,这个我能明白。
但是关闭浏览器就失效了,这个时候cookie里的session就只是一个值而已了。是不是要把相关信息存在数据库里?具体要怎么做,我有点迷糊。

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

password肯定在服务器端,验证并不是要返回密码给客户端,只是给它一个合法的身份。
reus
2011-06-04 17:44:46 +08:00
@supersheep password就在数据表里面啊,就是再次生成一次加密串,看和cookie里面的是否一样,一样就是合法的否则非法
supersheep
2011-06-04 17:47:05 +08:00
@Livid php也不算深入,只不过是自己目前实现想法最顺手的工具,还有就是部署方便。python有机会再研究吧,gae被墙多少会有点儿别扭。感谢推荐。
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
2011-06-04 17:59:58 +08:00
V2EX,豆瓣,知乎,42区,下厨房……国内其实已经有不少网站是完全用 Python 做的了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/13993

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX