buguge - Keep it simple,stupid

知识就是力量,但更重要的,是运用知识的能力why buguge?

导航

系统网站登录,如何合规传输用户登录密码?

对于系统登录页面来说,我们作为开发人员,应该没有陌生的吧。就像下面这样子。

 

 

点击登录,调用/login 接口。来看下面截图中的 载荷(payload)数据,其中,密码 password 的值是明文。 

 

这里要说的是,在信息安全层面,用户登录密码属于用户隐私数据。

首先,隐私数据属于敏感数据,不能明文传输;

其次,严格地讲,用户的密码应该只能由用户本人知道,系统不能直接触碰用户密码。假如用户密码是“jishup@ss0rd”,这个密码只能用户本人知道。一旦系统知道,就会有密码泄露的风险。安全性低的程序,甚至会直接把用户密码打印到log文件里。

 

因此,如何设计我们的登录程序,以满足上面两点要求呢?

 

直接公布我的idea。————前后端交互所传输的password,转换成不可逆的md5值。即:所传输的password = md5(用户输入的明文)。

如此这般,浏览器F12看到的将是下面这样子。

对于系统的server程序来说,首先,在初始设定用户密码阶段,数据库持久化存储用户密码时,要明确密码的加密算法,例如:实际存储的用户password = md5(md5(用户明文密码), salt)。

接下来我们说登录接口。服务端收到的密码参数,是一个md5串,从而做到了隐私数据的保护。下面是部分示意代码。

@RequestMapping("/login")
public Result login(HttpServletRequest request){
    ...
    String loginAcc = readFromRequest(request, "login_account");
    String passwordMD5 = readFromRequest(request, "password"); // 前端传过来的 md5 串
    LoginAccount loginAccount = loginAccountRepository.findByLoginName(loginAcc);
    if (loginAccount == null) {
        return Result.error("用户不存在");
    }
    String password = PasswordUtil.encrypt(passwordMD5, loginAccount.getSalt());
    if (!loginAccount.getPassword().contentEquals(password)) {
        return Result.error("登录口令错误");
    }
    ...
}

 

 

上面说login这一环节的用户密码安全,其实也牵涉到设定用户密码的安全控制。为此,整体来总结一下用户密码安全的系统实现方案。 

前端页面
 
server端
 
DB
【CASE1】设定用户密码
passwordMD5=MD5(用户密码)
接收loginAcc、passwordMD5
encryptPwd = PasswordUtil.encrypt(passwordMD5, salt)
持久化保存 login record
(含loginAcc、password、salt,
其中password=encryptPwd)
.
.
.
 
 
 
 
【CASE2】用户登录
passwordMD5=MD5(用户输入的密码)
→ 
接收loginAcc、passwordMD5
 
→ 
根据loginAcc获取 login record 
 
 
得到loginRecord
↓ 
encryptPwd = PasswordUtil.encrypt(passwordMD5, loginRecord.salt)
比较encryptPwd与loginRecord.password
 ←
 ↓

 

 

是不是很优雅? 

不,还可以更优雅。

 

仍然以login接口的安全控制来阐释。细心的同学会注意到存在这样一个情况:用户在不修改密码的情况下,每次系统登录调用login接口时,传输的密码是相同的md5串。这多少让我们开发者有些不爽!

为此,我们继续琢磨这个login安全增强。

我们借助可逆的加密算法改造一下,将md5的密码作为加密数据的一部分进行传输。

具体来讲,前后端约定一套加密算法,作为所传输的password参数的值。如 所传输的password = base64(des(passwordMD5, timestamp)),其中的 timestamp是系统当前时间戳,这也有效保证了每次请求所传输的password参数值各不相同。后端login接口里,按照相同的加密算法来解密得到所需的passwordMD5。

你也许会疑惑于用户浏览器与服务器两端的时间不一致。一种应对方式是,可以将这个timestamp作为longin接口的一个参数上送给服务端,另一种应对方式,不新增参数也没关系,这个我在姊妹篇中有应对方案了,戳网站登录,如何避免明文传输用户登录密码?

 

ref:发现一肉鸡接口,快来围攻啦~

 

【EOF】欢迎关注我的微信公众号「靠谱的程序员」,让我们一起做靠谱的程序员。

posted on 2024-12-17 21:42  buguge  阅读(600)  评论(3)    收藏  举报