关于用户登录、验证的常见做法,是在验证用户的用户名和密码之后将用户的ID保存在Cookie中:
user_id=123456
验证的时候,将user_id从Cookie中取出,然后从数据库中获取对应ID的用户:
GET /users/123456
如果获取失败,就重定向到登录界面,否则算验证登录成功。这时候,一般也会看看该用户是否已经被封禁,如果被封的话,同样也会重定向到登录界面。
为了防止通过篡改Cookie的user_id值实现更换用户(也许这个用户本身不属于篡改者),还会保存一个将用户ID和密钥字符串放在一起摘要的摘要字符串(摘要算法可以使用MD5):
user_id=123456;login_sum=abcdabcdabcdabcdabcdabcdabcdabcd
这样可以在一定程度上防止冒名顶替的事情发生。
但是现有的网站一般都提供了“记住我”选项,而且一般勾选该选项都会导致用户的登录信息在Cookie中保存一个月甚至更长的时间。
如果在此期间,用户访问了一些不安全的网站,暴露了自己保存在Cookie中的用户信息,由于登录信息的摘要字符串在Cookie消失之前是不会改变的,这就有可能使不安全网站的拥有者使用用户本人的用户信息登录进网站。
为了解决这个问题,我们可以引入login_sum_expires参数,定义该摘要字符串的过期时间(Unix时间戳记):
user_id=123456;login_sum=abcdabcdabcdabcdabcdabcdabcdabcd;login_sum_expires=1234567890
同时,login_sum的计算公式中也加入该时间,保证随着过期时间的不同,摘要字符串也不一样。
之后再设置一个比较合适的过期时间(一般是20min),超过这个时间之后,即宣告该摘要字符串过期,同时为其设置一个新的过期时间并随之产生新的摘要字符串。
这样,即使用户被不安全网站窃取了Cookie中的用户信息,20min(甚至更短)之后由于其持有的用户信息已失效,就没有办法冒名顶替了。
真的是这样吗?
事实上,不安全网站拥有者持有该信息进入网站后,网站无法识别其是否是真正的用户。网站会按照一般流程,自动为摘要字符串续期!
为了能够识别用户的合法性,我们可以引入login_ip参数,记录该用户登录时的IP地址:
user_id=123456;login_sum=abcdabcdabcdabcdabcdabcdabcdabcd;login_sum_expires=1234567890;login_ip=222.222.222.222
同时,login_sum的计算公式中也加入该IP地址,保证随着登录IP的不同,摘要字符串也不一样。
这时候,即使用户被不安全网站窃取了Cookie中的用户信息,由于IP地址不同,网站也会视该登录信息失效,从而解决冒名顶替问题。
login_sum_expires参数已无用处!
(未完待续……)