使用RSA加密完成登录功能,防止用户信息被抓包泄漏!

  • Post author:
  • Post category:其他




前言

之前项目中,登录模块发送登录请求基本上都是明文传输用户名、密码,这样如果系统的请求被恶意抓取,用户的信息就会泄漏无疑,毫无安全可言,那么有什么办法可以提高安全性呢?

  1. js加密

    在js中加密用户的密码,使之在传输过程中程加密状态,这样,即使在被恶意拦截了请求,获取了用户名密码后,别人并不会知道密码,因此完成加密!
  2. RSA加密算法

    RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被广泛使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。


    到目前为止,世界上还没有任何可靠的攻击RSA算法的方式。只要其钥匙的长度足够长,用RSA加密的信息实际上是不能被解破的。



    2009年12月12日,编号为RSA-768(768 bits, 232 digits)数也被成功分解。这一事件威胁了现通行的1024-bit密钥的安全性,普遍认为用户应尽快升级到2048-bit或以上。



    了解更多关于RSA



调查

在寻找保密方法的时候,曾经查看过很多知名网站的登录,大部分都是用户名不管,密码加密即可,所以我们采用同样的方式。

  • 美团登录

    美团登录
  • 阿里云登录

    阿里云登录
  • 新浪登录

    新浪微博登录

    新浪可能是用户名也加密了,但是在请求中发现了
pwencode: rsa2
rsakv: 1330428213

基本可以初步判断新浪在登录上也是用了RSA加密

  • 京东

    京东登录

    在京东请求中发现了

    pubKey

    字段,京东可能也是使用了非对称加密。



简单原理


在使用RSA加密手段之前,我们需要了解RSA加密大概的流程,这样有助于帮助我们更好的使用此加密手段。

  1. 首先,系统跟根据一定的规则生成一对秘钥,
  2. 我们可以选择一个秘钥去公开它,另外一个一定要严格保密,通常公开的秘钥我们称之为

    公钥

    ,留下的秘钥称之为

    私钥

  3. 我们可以对外开放一个可以获取公钥的接口,用于外部程序来获取公钥,外部应用通过此公钥来加密数据,这些加密后的数据只能通过私钥才能解开,相对的,私钥加密的数据需要公钥来解密,即使别人获取了你的公钥、’密文,只要私钥不泄露,只要秘钥位数足够长,是解不开的。



代码



页面处理

在页面上使用rsa加密非常简单,我们只需要在页面写下如下代码,即可完成加密功能

var encrypt=new JSEncrypt();
encrypt.setPublicKey(public_key);
var rsa_password = encrypt.encrypt($('#password').val());

这样,密码就加密完成了。



后台处理

package rsalogin.util;

import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
 
import javax.crypto.Cipher;
 
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
 
public class RSAUtil {
	//生成秘钥对
	public static KeyPair getKeyPair() throws Exception {
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
		keyPairGenerator.initialize(1024);
		KeyPair keyPair = keyPairGenerator.generateKeyPair();
		return keyPair;
	}
	
	//获取公钥(Base64编码)
	public static String getPublicKey(KeyPair keyPair){
		PublicKey publicKey = keyPair.getPublic();
		byte[] bytes = publicKey.getEncoded();
		return byte2Base64(bytes);
	}
	
	//获取私钥(Base64编码)
	public static String getPrivateKey(KeyPair keyPair){
		PrivateKey privateKey = keyPair.getPrivate();
		byte[] bytes = privateKey.getEncoded();
		return byte2Base64(bytes);
	}
	
	//将Base64编码后的公钥转换成PublicKey对象
	public static PublicKey string2PublicKey(String pubStr) throws Exception{
		byte[] keyBytes = base642Byte(pubStr);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		return publicKey;
	}
	
	//将Base64编码后的私钥转换成PrivateKey对象
	public static PrivateKey string2PrivateKey(String priStr) throws Exception{
		byte[] keyBytes = base642Byte(priStr);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}
	
	//公钥加密
	public static byte[] publicEncrypt(byte[] content, PublicKey publicKey) throws Exception{
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		byte[] bytes = cipher.doFinal(content);
		return bytes;
	}
	
	//私钥解密
	public static byte[] privateDecrypt(byte[] content, PrivateKey privateKey) throws Exception{
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] bytes = cipher.doFinal(content);
		return bytes;
	}
	
	//字节数组转Base64编码
	public static String byte2Base64(byte[] bytes){
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(bytes);
	}
	
	//Base64编码转字节数组
	public static byte[] base642Byte(String base64Key) throws IOException{
		BASE64Decoder decoder = new BASE64Decoder();
		return decoder.decodeBuffer(base64Key);
	}
}



Demo

主要代码如上所示,如果需要示例可以访问码云来查看我写的一个例子。


示例

如果发现错误或者其它问题请留言指正,谢谢!

  • 此Demo采用了Springboot 2.0.4开发,模拟了登录加密的流程。
  • 采用了定时刷新秘钥对策略,有助于私钥定期刷新。

页面所用的加密js的GitHub地址如下

页面加密js GitHub地址



版权声明:本文为New_Yao原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。