This is the fifth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021
preface
This section introduces the SysProfileController section of the ruoyi-Admin module of Ruoyi-Vue. So let’s talk about resetting the password and how the foreground password is going to be passed to the background.
/** * reset password */
@PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword) {
LoginUser loginUser = getLoginUser();
String userName = loginUser.getUsername();
String password = loginUser.getPassword();
if(! SecurityUtils.matchesPassword(oldPassword, password)) {return AjaxResult.error("Failed to change password. Old password is incorrect.");
}
if (SecurityUtils.matchesPassword(newPassword, password)) {
return AjaxResult.error("New password cannot be the same as old password");
}
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) {
// Update the cache user password
loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
tokenService.setLoginUser(loginUser);
return AjaxResult.success();
}
return AjaxResult.error("Failed to change password. Please contact administrator.");
}
Copy the code
Here we can see the incoming is the password for user input, the front there is no operation, no encryption or hash, but in the background. Only use the SecurityUtils encryptPassword on the user’s password encryption.
This raises an interesting question: How should the foreground password be passed to the background?
How does the foreground password pass to the background
How to transfer the foreground password to the background is a very interesting question. There are many methods, including direct transfer to the back end, md5 encryption to the background, and RSA encryption to the back end decryption
directly
Directly plaintext password is one of the most simple method, but also can bring certain risks at the same time, if you are not using HTTPS, so for all the people on the path of your password is transparent, even though the site may not have what important role, a malicious person also can use this password to other websites of library operation. It is also possible to print out your password when printing a log. After all, as in Ruoyi, the password is directly put into the URL. If Nginx logs access, then your password is at risk of leakage.
MD5 digest algorithm
We use Hutool to simulate the existing MD5 password of the back-end database.
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.15</version>
</dependency>
Copy the code
Front end to use MD5js we use BlueIMP – MD5
https://www.bootcdn.cn/blueimp-md5/
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.js"></script>
Copy the code
Let’s set up a front-end HTML that does MD5 once for the password we want to pass to the background, or MD5 twice for security.
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.js"></script>
</head>
<body>
<button>Md5 Sending request</button>
<script>
$("button").click(function () {
var password = md5("123456");
$.ajax({
type: "POST".url: "/api/testMd5".data: {password: password}
}).done(function (msg) {
alert("Data Saved: " + msg);
});
});
</script>
</body>
</html>
Copy the code
The back end uses the interface to receive and compare with the data after md5 on the back end. Here we use Hutool’s digestUtil.md5HEX method.
@PostMapping("/testMd5")
public boolean testMd5(@RequestParam("password") String password) {
String backPassword = DigestUtil.md5Hex("123456");
if (backPassword.equals(password)) {
return true;
} else {
return false; }}Copy the code
The advantage of using MD5 is that it is simple and convenient, but the disadvantage is that we can’t know whether the password used by the user meets our requirements in the back end. We can only verify it in the front end, because we can’t know what the user typed after MD5. In addition, the problem brought by MD5 is that if the user uses a common password, it may be bumped out, which brings a hidden danger to the security of the user’s other websites.
RSA encryption and decryption
Front end we encrypt RSAjs using jsENCRYPT
https://www.bootcdn.cn/jsencrypt/
<script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.2.1/jsencrypt.js"></script>
Copy the code
Website is travistidwell.com/jsencrypt/ we first need to generate the RSA public key and key can use www.metools.info/code/c80.ht… To generate
The length I chose is 1024 and the format is PKCS#8, which adds the validation data section to ensure the key is correct.
Front-end public key encryption
To perform RSA encryption, we want to expose a public key in the front end, so we use a fixed public key for simplicity.
Jsencrypt will generate a string of Base64. As you can see from the parameter comment in the decryption part of the code, the string of Base64 is converted to hex.
var encrypt = new JSEncrypt();
debugger
encrypt.setPublicKey($("#publicKey").html());
var encrypted = encrypt.encrypt("123456");
Copy the code
Using the above code, we have encrypted the password with a public key, and now it is sent to the background for decryption.
Background private key decryption
Background decryption we also use Hutool originally I thought it would be very simple, because the front end according to the public key encryption has been completed, Hutool also gave the private key decryption example, just copy it.
But here’s the bad partHexUtil.decodeHex
Here it is, here it isString a
It’s actually a hexadecimal string, so I’m passing in a Base64 string, which I started with
byte[] aByte = HexUtil.decodeHex(Base64.decodeStr(password));
Copy the code
DecodeStr is not a hexadecimal string, HexUtil. DecodeHex is not a byte array, but I thought it was incompatible without annotations, so I tried a lot of different things until I traced the decryption part of the front-end JS code
Let’s take the values in ret asHexUtil.decodeHex
Base64tohex = base64Tohex = base64Tohex = base64Tohex = base64Tohex = base64Tohex
byte[] decoded = Base64.getDecoder().decode(password);
Copy the code
In this way, our RSA encryption and decryption is complete! The backend can know whether the password entered by the user meets our requirements of the password format and strength, while in the process of transmission will not be leaked.