最近做完系统登录模块的重构,登录这块的核心在于安全的控制。下面通过本文来总结一下登录模块的设计实现,以及哪些方面需要注意。
用户创建
- 密码保存需要做不可逆加密。即密码不能明文保存且即使是内部技术人员也无法得到真实密码,常见的加密方法有MD5,SHA系列算法,如果对加密算法不太了解的可以移步这里。
- 密码强度限制。不允许使用弱口令,比如跟用户生日相等。
- 手机、邮箱验证。方便后续找回密码。
用户登录
需要注意的问题
- 使用验证码。增加暴力破解的成本。
- 登录错误次数限制,一定时间后自动解锁,彻底堵死暴力破解。
- 关键cookie设置HTTPOnly属性,防止xss盗取用户cookie。
- 保证密码在网络传输中的安全。启用HTTPS,或使用RAS加密。请求登录界面时,生成公钥与私钥,私钥放在服务器端,密码传输前,使用公钥加密,服务器端收到密文后使用私钥解密密文得到用户输入的真实密码。
- 集群状态下,采用session共享的方式实现SSO时,在session上记录的登录状态信息需要可序列化。
- 页面跳转时使用服务器端跳转,
request.getRequestDispatcher().forward()
。尽量不要使用response.sendRedirect()
,因为每次redirect都会触发客户端304,重新再次发起一次HTTP请求。
记住密码
可以考虑这样去实现记住密码功能:cookie中需要保存如下3个值
username:用户的登录名
token:使用公钥加密过的用户密码
sequence:登录序列(防重放攻击。如果自动登录的该字段与服务器的不相符时,则证明用户在其他地方登录过。)
当勾选记住密码登录时,在服务器端保存当前的私钥、生成一个随机的登录序列(UUID)保存起来。同时,把用户名、登录传输过来的已经用公钥加密的密文、新生成的sequence保存到cookie中。下次用户请求登录页面时,从cookie中取得用户名放到用户名的输入框中,任意字符串放到密码框中,继续勾选上记住密码框。这个时候只需要输入验证码即可点击登录按钮。服务器端,判断出本次登录是记住密码登录,首先验证cookie中的sequence是否跟服务保存的一致,如果不一致,则登录失败。一致时,取出私钥解密从cookie中拿到的token,得到真实密码,接着按照常规登录流程完成登录验证。
密码变更
- 修改密码需要提供原始密码
- 相关信息在网络传输中需保证加密传输
- 找回密码功能可以考虑使用手机验证码,邮件链接实现。另外,还可考虑提供用户在本系统中的留痕供用户选择(比如什么时候注册、最近做了什么操作等),从而识别出真正的用户。
日志记录
- 记录用户的登录日志。可记录下登录时间、退出时间、IP等信息,分析过往日志,甄别出异常登录并提醒用户。
- 记录用户登录失败日志。限制登录失败重试次数,防止暴力破解。
服务器相关
有时应用的安全部分做得再好,也抵不住服务器直接被攻破,所以运行应用的服务器的安全也需要特别注意。
- 服务器访问日志(建议开启)
- 可疑用户
- 可疑进程
- 可疑服务
- 操作系统日志(日志最大大小) 定期备份