你的位置:首页 > Java教程

[Java教程]一种简单的登录加密方案


该方案使用RSA加密和解密。

  每次登录前,客户端从服务器端获取公钥和随机值。

  公钥用于加密明文;

  随机值可以加强每一次操作的安全性,随机值也加入明文中一并加密,服务端对随机值进行校验,校验后从缓存中销毁,这样就算被别人拿到加密后的密文再次发起请求,由于随机值已失效,请求也是无效的。

 

 

 

下面以js客户端为例,演示一下流程:

1、假设客户的密码以SHA256加密后存在数据库中

 

2.、客户输入用户名和密码点击 “登录”后,客户端发起请求,从服务器端获取公钥和随机值。

{  "rand": "SAXpJg",  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK+oqElHP94+1BhhiTKX0pzziepN+C5Ff/qgmind2XvD35eWlCqzypGIXBoki526ZbsqrssbxTy5imhthe4eUTenLGUKkUgYUmDWrus8NmJm6IlXuqbGHaEY1zocsnlqVezOMj0AIUq5L65Y6e5XnEf1ludSzTF73MtFTjW8TRyQIDAQAB"}

 

3、客户端将用户输入的密码使用SHA256加密

<!--下载地址:https://github.com/Caligatio/jsSHA -->     <script type="text/javascript" src="sha.js"></script>     <!--下载地址:https://github.com/travist/jsencrypt-->     <script type="text/javascript" src="jsencrypt.js"></script>     <script>                 //用户输入的密码        var password1 = '123456';                //从服务端获得的公钥        var publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK+oqElHP94+1BhhiTKX0pzziepN+C5Ff/qgmind2XvD35eWlCqzypGIXBoki526ZbsqrssbxTy5imhthe4eUTenLGUKkUgYUmDWrus8NmJm6IlXuqbGHaEY1zocsnlqVezOMj0AIUq5L65Y6e5XnEf1ludSzTF73MtFTjW8TRyQIDAQAB";                  //从服务端获得的随机值        var rand = 'SAXpJg';                //SHA-256加密        var shaObj = new jsSHA("SHA-256", "TEXT");        shaObj.update(password1);        var hash = shaObj.getHash("HEX");            //组装明文:由加密后的密码和随机值组成        var text = hash + '|' + rand;        console.log("待加密的文本: " + text);                //使用RSA公钥加密        var encrypt = new JSEncrypt();         encrypt.setPublicKey(publicKey);                // password就可以发送到服务端进行解密校验了        var password = encrypt.encrypt(text);                console.log("加密后的密文:" + password);       </script>

  控制台打印出来的结果:

待加密的明文:8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92|SAXpJg加密后的密文:dgUBkZPZgL76+zMbKckAxb3C072I8b4nqAZlWUD/24Hp7UpAgiKx4P90xgs1UhWM2qputsjgpsgXLCNUg2vtO9MxpQk6zWUbyh4cxL08UcmMv3KIMO5rnbFxKEmuIbQ2G/3UZT8c+w899ERLCpDVyHrKSijdpvVoKrB6PzyjP+w=

  然后将加密后的密文传到服务器端即可。

 

4、服务器端代码

  RSAUtils.java

import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.SecureRandom;import java.security.Security;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import javax.crypto.Cipher;import org.apache.commons.codec.binary.Base64;import org.bouncycastle.jce.provider.BouncyCastleProvider;/** * RSA 工具 * @author Luxh * */public class RSAUtils {        private static final String ALGORITHM = "RSA";    private static final String PROVIDER = "BC";    private static final String TRANSFORMATION = "RSA/None/PKCS1Padding";    private static final int KEY_SIZE = 1024;    private static KeyPair keyPair = null;      /**   * 初始化密钥对   */  static {    try{       Security.addProvider(new BouncyCastleProvider());       SecureRandom secureRandom = new SecureRandom();       KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, PROVIDER);       keyPairGenerator.initialize(KEY_SIZE, secureRandom);       keyPair = keyPairGenerator.generateKeyPair();    }catch(Exception e) {      e.printStackTrace();    }  }      /**   * 获取公钥   * @return   */  public static RSAPublicKey getRSAPublicKey() {     return (RSAPublicKey)keyPair.getPublic();  }     /**   * 获取Base64编码的公钥   * @return   */  public static String getBase64PublicKey() {    RSAPublicKey publicKey = getRSAPublicKey();    //return new String(Base64.encodeBase64(publicKey.getEncoded()));    return Base64.encodeBase64String(publicKey.getEncoded());  }       /**   * 使用公钥加密   * @param data   * @return   */  public static String encrypt(byte[] data) {    String ciphertext = "";    try {      Cipher cipher = Cipher.getInstance(keyPair.getPublic().getAlgorithm());      cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());      ciphertext = Base64.encodeBase64String(cipher.doFinal(data));    } catch (Exception e) {      e.printStackTrace();    }    return ciphertext;  }        /**   * 使用私钥解密   * @param ciphertext   * @return   */  public static String decrypt(String ciphertext) {    String plaintext = "";    try {      Security.addProvider(new BouncyCastleProvider());      Cipher cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);      RSAPrivateKey pbk = (RSAPrivateKey)keyPair.getPrivate();      cipher.init(Cipher.DECRYPT_MODE, pbk);      byte[] data = cipher.doFinal(Base64.decodeBase64(ciphertext));      plaintext = new String(data);    }catch (Exception e) {      e.printStackTrace();    }    return plaintext;  }  }

View Code

 

  DemoController.java

import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang3.RandomStringUtils;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;import com.google.common.collect.Maps;import io.caimi.util.RSAUtils;@RestControllerpublic class DemoController {      /**   * 获取公钥和随机值   *   */  @RequestMapping("/secret")  public Map<String, Object> secret(HttpServletRequest request) {        Map<String, Object> resultMap = Maps.newHashMap();        // 获取公钥    String publicKey = RSAUtils.getBase64PublicKey();    resultMap.put("publicKey", publicKey);        // 生成随机值    String rand = RandomStringUtils.randomAlphabetic(6);    resultMap.put("rand", rand);        // 将生成的随机值存到session中,实际使用可以存到第三方缓存中,并设置失效时间    request.getSession().setAttribute("rand", rand);        return resultMap;      }      /**   * 校验   *   */  @RequestMapping(value="/check", method=RequestMethod.POST)  public String check(HttpServletRequest request) {    // 取得密文    String password = request.getParameter("password");        // 解密    String plaintext = RSAUtils.decrypt(password);        String[] arr = plaintext.split("\\|");        // 校验随机值    String rand = arr[1];    String randInSession = (String) request.getSession().getAttribute("rand");    //随机值失效    request.getSession().removeAttribute("rand");        if(!rand.equals(randInSession)) {      return "非法的请求";    }        // 校验密码    String passwd = arr[0];        // 实际中根据用户名从数据库中查询出密码    String realPasswd = "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92";         if(!realPasswd.equals(passwd)) {      return "密码输入错误";    }        return "校验通过";  }  }

View Code

 

  maven依赖的一些jar

<dependency>      <groupId>commons-codec</groupId>      <artifactId>commons-codec</artifactId>      <version>1.10</version>    </dependency>    <dependency>      <groupId>org.bouncycastle</groupId>      <artifactId>bcprov-jdk15on</artifactId>      <version>1.54</version>    </dependency>        <dependency>      <groupId>com.google.guava</groupId>      <artifactId>guava</artifactId>      <version>18.0</version>    </dependency>        <dependency>      <groupId>org.apache.commons</groupId>      <artifactId>commons-lang3</artifactId>      <version>3.4</version>    </dependency>