使用RSA对前台账号密码加密后台解密流程记录

前言:项目使用base64对用户账号和密码进行编码,然后通过网络输出到后台,由于base64是可逆的,所以攻击者很容易就知道了这些敏感信息。所以,要对这些敏感信息先加密输出到后台,然后后台进行解密,这就要前台和后台约定好加密和解密的密钥,刚开始想法是使用AES对称加密,但是由于要将密钥在网络上进行传输,这种就造成攻击者很容易截取信息进行伪造,所以改用了RSA非对称加密对账号和密码对这些敏感信息加密,前台先从后台获取公钥,后台生成对应的私钥并存储,然后使用公钥对敏感信息进行加密传输到后台,后台接收之后使用之前存储对应的私钥进行解密,之后再按照原先的逻辑处理。

1.前台引入加密相关js文件

<script src="${ctx}/static/js/jsencrypt.min.js"></script>

文件下载地址: https://pan.baidu.com/s/1Q5Y3YUgeptju8efK6mfkxw 提取码: trp3

2.项目引入加密相关的依赖

<dependency>
	<groupId>commons-codec</groupId>
	<artifactId>commons-codec</artifactId>
	<version>1.9</version>
</dependency>

3.后台创建一个RSA工具类RSAUtils

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>rsa工具类</p>
 *
 * @author  xxx
 * @create 2021/3/3 21:45
 */
public class RSAUtils {

    private static final Logger logger = Logger.getLogger(RSAUtils.class);

    public static void main(String[] args) throws Exception {
        String s= "123456";
        Map<Integer,String> map = RSAUtils.genKeyPair();
        String s2 = RSAUtils.encrypt(s, map.get(0));
        System.out.println("公钥加密后:"+s2);
        System.out.println("私钥解密后:"+RSAUtils.decrypt(s2, map.get(1)));

    }

    /**
     * 随机生成密钥对
     */
    public static Map<Integer, String> genKeyPair() {

        Map<Integer, String> keyMap = new HashMap<Integer, String>();  //用于封装随机产生的公钥与私钥

        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            
          // 初始化密钥对生成器,密钥大小为96-1024位
           keyPairGen.initialize(1024,new SecureRandom());
           // 生成一个密钥对,保存在keyPair中
           KeyPair keyPair = keyPairGen.generateKeyPair();
           RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
           RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥
           // 得到公钥字符串
           String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
           // 得到私钥字符串
           String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
           // 将公钥和私钥保存到Map
           keyMap.put(0,publicKeyString);  //0表示公钥
           keyMap.put(1,privateKeyString);  //1表示私钥
        } catch (Exception e) {
            logger.info("生成公钥私钥异常:"+e.getMessage());
            return null;
        }

        return keyMap;
    }


    /**
     * RSA公钥加密
     * @param str  需要加密的字符串
     * @param publicKey  公钥
     * @return 公钥加密后的内容
     */
    public static String encrypt( String str, String publicKey ){
        String outStr=null;
        try {
            //base64编码的公钥
            byte[] decoded = Base64.decodeBase64(publicKey);
            RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
            //RSA加密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        } catch (Exception e) {
            logger.info("使用公钥加密【"+str+"】异常:"+e.getMessage());
        }
        return outStr;
    }


    /**
     * RSA私钥解密
     * @param str  加密字符串
     * @param privateKey  私钥
     * @return 私钥解密后的内容
     */
    public static String decrypt(String str, String privateKey){
        String outStr=null;
        try {
            //64位解码加密后的字符串
            byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
            //base64编码的私钥
            byte[] decoded = Base64.decodeBase64(privateKey);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
            //RSA解密
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            outStr = new String(cipher.doFinal(inputByte));
        } catch (Exception e) {
            logger.info("使用私钥解密异常:"+e.getMessage());
        }
        return outStr;
    }

}

4.编写统一返回公共实体类ResponseEntity

public class ResponseEntity extends Throwable {
	private static final long serialVersionUID = 2134346833392248650L;
	/** 状态码,正常为0 其它为错误(默认为0) */
	private Integer code = 0;
	/** 错误信息 */
	private Object msg = "";
	/** 返回数据对象 */
	private Object data = "";
	/** jsessionId */
	private String sid = "";
	/** toke*/
	private String toke = "";


	public ResponseEntity() {
		super();
	}

	public ResponseEntity(Integer code) {
		super();
		this.code = code;
	}

	public ResponseEntity(Integer code,String toke) {
		super();
		this.code = code;
		this.toke = toke;
	}

	public ResponseEntity(Object data) {
		super();
		this.data = data;
	}

	public ResponseEntity(String toke) {
		super();
		this.toke = toke;
	}

	public ResponseEntity(String toke,Object data) {
		super();
		this.toke = toke;
		this.data = data;
	}

	
	public ResponseEntity(Integer code, Object msg) {
		super();
		this.code = code;
		this.msg = msg;
	}

	public ResponseEntity(Integer code, Object msg, Object data) {
		super();
		this.code = code;
		this.msg = msg;
		this.data = data;
	}

	public Integer getCode() {
		return code;
	}

	public ResponseEntity setCode(Integer code) {
		this.code = code;
		return this;
	}

	public ResponseEntity setData(Object data) {
		this.data = data;
		return this;
	}

	public Object getData() {
		return data;
	}

	public Object getMsg() {
		return msg;
	}

	public ResponseEntity setMsg(Object msg) {
		this.msg = msg;
		return this;
	}

	public String getSid() {
		return sid;
	}
	
	public ResponseEntity setSid(String sid) {
		this.sid = sid;
		return this;
	}
	
	public String getToke() {
		return toke;
	}

	public ResponseEntity setToke(String toke) {
		this.toke = toke;
		return this;
	}
}

5.编写后台接口用于获取公钥并存储对应私钥

    //存储私钥的对象
   public static Map<String, String> privateMap = new HashMap<>();


    // 获取非对称加密的公钥,并存储对应的私钥
    @ResponseBody
    @RequestMapping(value = "/getPublicKey", method = RequestMethod.GET)
    public ResponseEntity getPublicKey() {
       Map<Integer, String> map = RSAUtils.genKeyPair();
        privateMap.put("private", map.get(1));
        return new ResponseEntity(map.get(0));
    }

5.前台获取公钥,并使用公钥对账号和密码进行加密

<form method="" action="${ctx}/goLogin" id="loginForm">
        <div class="position">
            <input type="search" id="username" placeholder="请输入用户名">
        </div>
        <div class="position">
            <input type="password" id="password" placeholder="请输入密码">
        </div>
        <input type="submit" value="登录"/>
        <input type="hidden" id="digestu" name="digestu">
        <input type="hidden" id="digest" name="digest">
</form>
jQuery(document).ready(function(){
       // 先请求后台接口获取公钥
       var _pubkey;
       $.get("${ctx}/getPublicKey",{},function (data) {
           _pubkey = data.toke;
         }
       );
       // 使用非对称加密的方式,对用户名和密码进行公钥加密,私钥解密
       $("#loginForm").submit(function(){
           var encrypt = new JSEncrypt();
           encrypt.setPublicKey(_pubkey);
           var username = encrypt.encrypt($('#username').val());
           var password = encrypt.encrypt($('#password').val());
           $('#digestu').val(username);
           $('#digest').val(password);
           $('#username,#password').val('');
           return true;
       });
 });

6.后台获取到加密之后账号和密码字段,使用之前存储对应的私钥进行解密

    @RequestMapping(value = "/goLogin", method = RequestMethod.POST)
    public String login(HttpServletRequest request, String digestu, String digest) {
        // 后台用私钥解密用户名和密码
        String privateKey = privateMap.get("private");
        digestu = RSAUtils.decrypt(digestu, privateKey);
        digest = RSAUtils.decrypt(digest, privateKey);
        return "";
    }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值