标签:tostring encrypt 加密 byte 登录失败 ext sdn code lang
/**
* 密码加密
*
* @param pwd 原始密码
* @param salt 盐值
* @return
*/
public String encryptedPassword(String pwd, String salt) {
String pwdSalt = new Md5Hash(pwd, salt, 3).toString();
return pwdSalt;
}
//生成盐
String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
//最后生成加密后的密码存入数据库
String pwdSalt = this.encryptedPassword(pwd, salt);
在用户登录时,首先拿到数据库的盐值,再与用户输入的密码进行加密处理,最后与数据库的pwdSalt进行匹配实现登录
http请求很容易被截获,在写登录模块时,直接使用明文密码请求,很容易明文密码泄露;若在js页面对密码进行一次加密后在传输,虽不是明文密码,但也完全可以截获加密后的暗文,伪造http请求进行登录。为了防止密码泄露,通过参考各种方案,找到了以下比较好实现的方法:
1、登录请求分两次进行,第一次仅传用户名
2、服务器收到用户名后,生成一串随机数,将随机数响应给客户端,并将用户名和随机数存到session
3、客户端收到响应后,将密码和随机数安一定的规则组合起来,再md5加密,再http请求(此时保证了每一次登录请求的密码会随随机数的不同而不同,这个随机数为服务器生成,相当于一个公钥,与本次登录操作唯一且一一对应,客户端无法伪造)
4、服务器收到请求,取出session中的用户名和随机数串,核对用户名,再取数据库中的正确密码,再按相同的规则与随机数组合并md5加密,再比较请求的密码暗文,返回登录结果。
附一张更清晰的图,可以看到就算在传输过程的所有信息都暴露出来,也无法根据这些伪造出http请求登录成功。
Java后端
/**
* 生成公钥
* @return
* @throws Exception
*/
@ClearInterceptor(ClearLayer.ALL)
public void Rdspwd() throws Exception{
HttpServletResponse response = getResponse();;
PrintWriter writer = response.getWriter();
String publicKey = RSAUtils.generateBase64PublicKey();
writer.write(publicKey);
renderNull();
}
public class RSAUtils {
//KeyPair is a simple holder for a key pair.
private static final KeyPair keyPair = initKey();
/**
* 初始化方法,产生key pair,提供provider和random
* @return KeyPair instance
*/
private static KeyPair initKey() {
try {
//添加provider
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
//产生用于安全加密的随机数
SecureRandom random = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", provider);
generator.initialize(1024, random);
return generator.generateKeyPair();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
/**
* 产生public key
* @return public key字符串
*/
public static String generateBase64PublicKey() {
PublicKey publicKey = (RSAPublicKey)keyPair.getPublic();
//encodeBase64(): Encodes binary data using the base64
//algorithm but does not chunk the output.
//getEncoded():返回key的原始编码形式
return new String(Base64.encodeBase64(publicKey.getEncoded()));
}
/**
* 解密数据
* @param string 需要解密的字符串
* @return 破解之后的字符串
*/
public static String decryptBase64(String string) {
//decodeBase64():将Base64数据解码为"八位字节”数据
return new String(decrypt(Base64.decodeBase64(string.getBytes())));
}
private static byte[] decrypt(byte[] byteArray) {
try {
Provider provider = new org.bouncycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(provider);
//Cipher: 提供加密和解密功能的实例
//transformation: "algorithm/mode/padding"
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider);
PrivateKey privateKey = keyPair.getPrivate();
//初始化
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//doFinal(): 加密或者解密数据
byte[] plainText = cipher.doFinal(byteArray);
return plainText;
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
//解密帐号
username = RSAUtils.decryptBase64(username);
//解密密码
password = RSAUtils.decryptBase64(password);
js 前端
<button type="button" id="login-btn" class="width-35 btn btn-sm btn-primary" οnclick="doLogin()">
<i class="ace-icon fa fa-key"></i>
<span class="bigger-110" >登录</span>
</button>
//在页面一加载的时候就Ajax请求生成公钥的方法
//获取public key
var publicKey = null;
function getPublicKey(dologin){
$.ajax({
url: "/login/Rdspwd",
type: "post",
dataType: "text",
success: function(data) {
if(data) publicKey = data;
if(dologin==1){
if(publicKey==null){
$("#msg").html("获取publicKey失败,请联系管理员!");
$("#login-btn").removeAttr("disabled");
}else{
doLogin(1);
}
}
}
});
}
var ustring = $.trim($("#ustring").val());
var pstring = $.trim($("#pstring").val());
//根据公钥进行加密:
var encrypt = new JSEncrypt();
if(publicKey != null){
encrypt.setPublicKey(publicKey);
var password = encrypt.encrypt(pstring);
var username = encrypt.encrypt(ustring);
//提交之前,检查是否已经加密。假设用户的密码不超过20位,加密后的密码不小于20位
if(password.length < 20) {
//加密失败提示
alert("登录失败,请稍后重试...");
}else{
$.ajax({
url: "${contextPath}/dologin",
type: "post",
data: {"usname": username,"pwd": password,"vcstring": vcstring},
dataType: "json",
....
)}
}
}
// https://github.com/travist/jsencrypt JSEncrypt
标签:tostring encrypt 加密 byte 登录失败 ext sdn code lang
原文地址:https://www.cnblogs.com/zhanglw456/p/13175604.html