网站用户登录系统设计——jsGen实现版
ZENSH严清 http://weibo.com/zensh
jsGen 是基于 node.js、AngularJS 和 MongoDB 的网站系统。其用户登录系统也是相当独特。主要有以下特点:
- 用户注册时就在浏览器端对密码进行了二次哈希加密;
- 用户可使用用户名、注册邮箱或用户ID登录,通过浏览器端加密,每次登录请求发出的数据都完全不同,而且具有时效性;
- 自动登录机制;
注册
var data = {
name: 'xxxxx',
email: 'xxx@xxx.xxx',
passwd: '********'
};
data.passwd = CryptoJS.SHA256(data.passwd).toString();
data.passwd = CryptoJS.HmacSHA256(data.passwd, 'jsGen').toString();
注册时,浏览器端取得注册数据后,对原始密码进行二次哈希加密,再 POST 到服务器存储。
因为窃取者通常都有海量一次和二次 SHA256
的字典表,使用 HmacSHA256
加密后他们的字典表就没用了,暴利破解的话难度就高了很多。
浏览器端使用了 crypto-js 加密。
登录
var data = {
logtime: Date.now() - app.timeOffset,
logname: 'xxxxx' //用户名、邮箱或者用户ID
logpwd: '********' //原始密码
}
data.logpwd = CryptoJS.SHA256(data.logpwd).toString();
data.logpwd = CryptoJS.HmacSHA256(data.logpwd, 'jsGen').toString();
data.logpwd = CryptoJS.HmacSHA256(data.logpwd, data.logname + ':' + data.logtime).toString();
jsGen 支持用户名、邮箱或者用户ID登录,并且引入了时间因素。源码中的timeOffset
是浏览器与服务器的时间差。
相对于注册,登录时多了一层 HmacSHA256
加密,这层加密引入了登录名和登录时间。时间因素有两个作用,一是每次生成的登录数据都不同,二是该登录数据具有了时效性,服务器能判断该登录数据是否超时(有效)。也就是说,即使用户登录数据能被非法截取,截取的数据每次都会不一样,而且只在短暂的时间内有效。
该登录数据 POST 到服务器后,服务器先通过 logtime
判断登录数据是否有效,然后再通过 logname
检索用户,提取先前注册时保存的 passwd
密文,经过如上第三层HmacSHA256
加密后判断是否与 logpwd
一致。
自动登录
若用户开启自动登录,则服务器在用户每次登录(包括自动登录)成功时会生成新的自动登录 cookie
,生成规则如下:
var data = {
n: user._id,
t: Date.now()
};
data.p = HmacSHA256(user.passwd, data.n + ':' + data.t);
var cookie = new Buffer(JSON.stringify(data)).toString('base64'));
如上,加密规则实际上与登录一致,取用户ID、时间因素和密文,加密后变成一个标准的登录数据对象,先转成 JSON 字符串再转成 base64
字符串,然后种到用户的cookie
中。
用户向服务器发起数据请求时,服务器会先判断用户是否已登录,未登录则尝试cookie
自动登录,自动登录验证如下:
var data = new Buffer(req.cookie.autologin, 'base64').toString();
data = parseJSON(data);
if (data) {
data.logname = data.n;
data.logtime = data.t;
data.logpwd = data.p;
data.ip = req.ip;
userLogin(data);
}
也就是将 cookie
数据还原成标准登录数据再进行登录。
结束语
设计以上登录机制时我并没有任何经验,那时也正是学习 JS 编程阶段。现在来看,相对于很多网站系统,这个登录机制已经相当先进了。只是,自动登录机制还有漏洞~