下面考虑网站一个简化版用户账户系统,从注册,登录,使用,登出四个方面做个简单的设计
account表包含下面三个字段
id 一个表唯一的id,标识用户
user 用户名
passwd 用户密码(为了防止数据库被侵入泄露密码,需要如md5(passwd)或者crypt单向加密)
1,用户注册(POST /register.php)
① 如果网站是https协议,直接通过POST方式提交用户名和密码等信息;
② 如果是http协议,考虑到有可能传输数据被监听,可以用js对信息加密(比如对密码计算md5);
注:由于用户注册是一次性行为,这里可以简化业务。不过为了防止恶意程序批量注册用户,可以引入验证码或者限制IP一段时间内调用此接口次数。
POST:
account [email protected]
user ciaos
passwd passwd
服务器端用md5或者crypt处理密码后存入数据库,如下
{ "_id" : ObjectId("50b324a33ec92c5bfbbda3df"), "user" : "ciaos", "passwd" : "76a2173be6393254e72ffa4d6df1030a" }
2,用户登录(POST /login.php)
这是一个很频繁的行为,容易被第三者监听,密码一般需要加密。为了防止被穷举用户密码,可以引入一个随机数避免频繁调用,后台也应该控制一定时间内的接口调用次数。
POST:
user ciaos
passwd md5(md5(passwd)+tag)
tag time()
服务器端按照同样算法计算md5(数据库中加密后密码+tag)是否与passwd一致
md5(md5(passwd)+tag) equal or not md5(数据库密码密文+tag)
如果用户登录成功,生成一个cookie保存用户信息用于以后验证用户,由于后续步骤需要从cookie中提取用户信息,所以需要用可逆算法。为了避免别人猜测cookie,服务器端需要保存一份私钥。
Http Basic/Digest认证以及AES,DES加密都是比较成熟安全的解决方案,不过有点复杂。我们这里实现一个最简单的cookie生成算法。
<?php function alterstring($content) { //私钥 $secret = "abcdefghijklmnopqrstuvwxyz"; //加密解密算法 for($i=0;$i < strlen($content);$i++){ $content[$i] = $content[$i] ^ $secret[$i%strlen($secret)]; } return $content; } ?>
生成cookie的方式(此处用主键_id代替user,减少账号泄露风险)
<?php $c_userid = base64_encode(alterstring($_id)); setcookie("userid",$c_userid,time()+3600*24); ?>
浏览器就保存了cookie(userid = AgsCCxY%3D)
3,访问网站
使用第二步得到的cookie访问网站,服务器端脚本解析cookie获取用户信息
<?php if(isset($_COOKIE["userid"])) { $userid = $_COOKIE["userid"]; $_id = alterstring(base64_decode($userid)); //查询数据库判断用户权限,db.account.findOne({"_id":$_id}) //查询用户信息 $userinfo = db.userinfo.findOne({"_id":$_id}) } ?>
4,登出网站
删掉cookie即可
<?php setcookie("userid","",time() - 3600); header("Location: index.php"); ?>
附加思考:第三步需要频繁读取数据库,可以考虑缓存或者记录session等方式避免频繁的数据库操作。
可以考虑使用下面的流程:
① 判断服务器端是否有session,如果有则直接访问受限资源,如果无转②;
② 查询数据库或者缓存校验cookie是否合法,如果cookie不存在或者合法则跳转到登录页面,如果合法,则生成session。
③ 如果采用这种设计,登出网站时还需要清除session才行