码迷,mamicode.com
首页 > 其他好文 > 详细

用户登录相关安全

时间:2020-06-22 11:15:07      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:tostring   encrypt   加密   byte   登录失败   ext   sdn   code   lang   

1

用户登录密码加密

/**
* 密码加密
*
* @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进行匹配实现登录

2

http登录模块加密登录安全登录方法

http请求很容易被截获,在写登录模块时,直接使用明文密码请求,很容易明文密码泄露;若在js页面对密码进行一次加密后在传输,虽不是明文密码,但也完全可以截获加密后的暗文,伪造http请求进行登录。为了防止密码泄露,通过参考各种方案,找到了以下比较好实现的方法:
1、登录请求分两次进行,第一次仅传用户名
2、服务器收到用户名后,生成一串随机数,将随机数响应给客户端,并将用户名和随机数存到session
3、客户端收到响应后,将密码和随机数安一定的规则组合起来,再md5加密,再http请求(此时保证了每一次登录请求的密码会随随机数的不同而不同,这个随机数为服务器生成,相当于一个公钥,与本次登录操作唯一且一一对应,客户端无法伪造)
4、服务器收到请求,取出session中的用户名和随机数串,核对用户名,再取数据库中的正确密码,再按相同的规则与随机数组合并md5加密,再比较请求的密码暗文,返回登录结果。
附一张更清晰的图,可以看到就算在传输过程的所有信息都暴露出来,也无法根据这些伪造出http请求登录成功。
技术图片

3

用户登录对密码进行加密

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

4

如何正确对用户密码进行加密

用户登录相关安全

标签:tostring   encrypt   加密   byte   登录失败   ext   sdn   code   lang   

原文地址:https://www.cnblogs.com/zhanglw456/p/13175604.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!