PHP 登录中 Session 和 Cookie 问题...

2015-08-16 18:14:37 +08:00
 zeacev

Web新手,最近想写一个完整的博客系统练练手,登录认证这一块有些地方思路不是很清晰,请教一下大家。

首先,单独的Session和Cookie我思路很清晰,但是两者结合再加上数据库后,思路就不怎么清晰了。出于安全考虑,各位在开发的时候,在本地Cookie会放一些什么内容?本地的Cookie内容是怎么和服务器上的Session打交道?希望各位不吝赐教。

然后,有没有必要在user表中增加一个字段比如说叫做AuthCode,再浏览器POST过来的username和password去数据库对比成功之后,将这个AuthCode写到Cookie去,下次浏览器发送请求的时候直接对比username和AuthCode就行了?

其次,我看了WordPress和Typecho的数据库表结构,里面没有类似于AuthCode的字段,但是登录之后却会有这么一个类似于AuthCode的Cookie值,比如说下图Typecho的:

网上那些教程都只简单的说了下到本地设置个Cookie就行了,这样真的安全?

处理登录的时候,各位是怎么在程序中实现的?能否说一下大致思路?

感谢各位的解答

5066 次点击
所在节点    PHP
39 条回复
kslr
2015-08-16 18:18:17 +08:00
没必要用Cookie,用Session就好了
oott123
2015-08-16 18:26:19 +08:00
设置了 cookie 之后签个名
lyragosa
2015-08-16 18:31:25 +08:00
不涉及多设备登录,交叉登录,登出一台设备自动登出所有设备等复杂的安全性措施的话。

可以完全不使用session,代价是每个页面都要重新请求一次数据库读出用户信息,然后比对客户端的cookie

cookie字串肯定要加密,简单的用几个hash加密加点盐再加点注册时间啊随机字符串就行。

这样做的好处就是程序结构非常简单清晰易读,也不涉及session什么的。缺点就是开销稍微大了一丢丢,不过无所谓啦。
zeacev
2015-08-16 19:11:28 +08:00
@lyragosa

@kslr 你们两位结论正好相反,能否详细说说你的思路?
imink
2015-08-16 19:32:55 +08:00
可以看下php文档里面的start_session() 方法(没记错的话),每次用户登录的时候session后台开启,保存用户的authCode(可以根据uid还有password加密),以确保如果要浏览需要验证的页面(比如修改个人主页,编辑日志)的时候拥有权限。至于cookie,由于存在本地,可以定时删除,一般的应用情景是,记录用户上次登录的状态(“勾选以便下次直接登录”),或者用户个人网站偏好。

你图片上的cookie,有可能是为了“勾选以便下次登录”而设置的。
我平常用的最多的还是操作session。
raincious
2015-08-16 19:46:09 +08:00
用 start_session() 启动会话之后,PHP 会自动帮你处理会话数据,包括向Client发Cookie(而不用你自己去发),然后将存在服务器上的用户数据填充给 $_SESSION。整个操作你只需要调用 start_session、剩下的 PHP 会帮你处理好,你只需要读写 $_SESSION,就是这么简单。

而 PHPSESSION 那个 Cookie 只是 PHP 自己的 Session 机制设定的一个 Session ID 而已。
incompatible
2015-08-16 19:50:09 +08:00
@lyragosa 每个请求都读数据库?
没有一个web开发的内行会这么干
rogeecn
2015-08-16 21:22:29 +08:00
都没给撸说说SESSIONID是通过cookie带过去的么?就像你登陆了再清空COOKIE肯定要被退出管理权限呀。
Keita1314
2015-08-16 21:46:36 +08:00
第一次登陆之后,服务器的session保存当前会话信息,然后在数据库的一张表保存sessionID与用户名,同时将sessionID写入浏览器的cookie。
再次登陆,服务端通过浏览器的cookie中取得sessionID,然后到数据库中根据sessioID判断出当前登陆用户。
大概流程就是这样子。
lyragosa
2015-08-16 21:52:55 +08:00
@incompatible 说了啊 肯定有坏处的,会有额外的开销。
但是如果是小型的产品的话,与其花时间折腾为了节省这点性能不如做与业务有关的事情。

换句话说就是,如果产品只有100个人用,就不要折腾优化十万并发请求的事情。
zeacev
2015-08-16 22:00:03 +08:00
@rogeecn 这个我知道
incompatible
2015-08-16 23:07:07 +08:00
@lyragosa 6楼已给出php中集成session的成熟方案
我比较熟悉的java servlet规范中也原生预置了类似的session方案
我没看出来这些开箱可用的方案哪里“折腾”了,反而你的方案还要写额外的代码,这才是真的折腾
ferock
2015-08-17 00:04:21 +08:00
都是一样的东西,不走ssl 都不安全
msg7086
2015-08-17 02:48:36 +08:00
#7 @incompatible 每个请求去读数据库有什么问题?又不会影响什么速度。
incompatible
2015-08-17 04:10:20 +08:00
@msg7086
当然会影响速度 读取数据库要耗时间在应用服务器与数据库服务器间的网络IO、要耗数据库的CPU

#3的最大问题不在于每个请求读数据库会影响速度,而是在于业内没人这么干。
如我12楼所说,PHP和Java中都有成熟的方案,非常简单,根本不需要造一个毫无必要的轮子。
xuhaoyangx
2015-08-17 04:14:24 +08:00
@incompatible 赞同
kanezeng
2015-08-17 09:01:57 +08:00
@incompatible 单服务器这样肯定没问题,不过这样的话session信息其实是保存在服务器内存本身吧。如果服务器扩展到两台甚至,有可能存在一种情况是用户的不同请求被分配到不同的服务器上,那么如果请求被分配到内存中没有session信息的那些服务器上,用户就又变成未登录状态了吧。
所以如果脱离单机环境的话,这种问题还是值得讨论一下的吧?
haiyang416
2015-08-17 10:25:57 +08:00
博客系统的登录状态一般来说需要保存特定时间长度,不推荐直接使用 session 来储存,因为你对其运行机制不熟悉,会遇到很多意外情况。
作为练手项目,我们可以直接使用 cookie 来保存登录状态。
比如你可以将用户 id 存入 cookie ,在每次打开页面都检查 $_COOKIE["uid"] 是否设置来判断用户是否登录。
然而只依靠一个 uid 来鉴权是非常危险的事情,因为 cookie 是可以伪造的,所以我们需要在 uid 以外另添加一个 cookie 来杜绝伪造。
这个 cookie 通常是一个 hash 值,比如就将它取名为 AuthCode ,它的值是可以是 hash ("sha256", uid + salt ) 或者其他类似的字符串。
那么在每次打开页面的时候就需要判断两种情况:是否设置了 $_COOKIE["uid"]; hash ("sha256", $_COOKIE["uid"] . "IAmSalt!") 是否和 $_COOKIE["authCode"] 相同;
那么只要 hash 算法或者 salt 不泄漏,就可以杜绝大部分伪造,一下就感觉安全了很多是不是?
当然,这只能应付“最最最”基本的情况,比如我的 cookie 被拦截了,这样的鉴权方式就算改密码都没用,怎么办?
只能靠楼主自己去了解相关的解决方式了。
incompatible
2015-08-17 10:56:48 +08:00
@kanezeng
集群环境下通常采用这两种方案之一:
- 在 load balancer 上做 sticky session ,把来自某个客户端的请求永远转发至相同的应用服务器
- 把 session 信息放在 redis/memcached 等支持高并发的缓存中
数据库虽然也可以做集中式存储,但是在高并发情况下性能会急剧下降,所以没人用它存 session
kanezeng
2015-08-17 12:23:49 +08:00
@incompatible 赞同,前面回复的时候我脑子里想的也是 redis , redis 的特性应该是最适合这种情况的吧。

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

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

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

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

© 2021 V2EX