您的位置:首页 > 其它

一种简单的登录加密方案

2016-04-20 20:27 323 查看
该方案使用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.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;

@RestController
public 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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: