前端登录密码JS加密,后端PHP解密的非对称RSA加解密方案
前端登录信息一般通过post方式提交,这其中账号密码一般明文传输,在开启了https的情况下安全性没有太大问题。
但对于一些比较大的平台,或网站经常需要在不安全网络下使用,在传输过程中仍然有被截获数据的可能性,这些信息用来定向攻击或被用来组成彩虹表进行撞库破解。
比如前些年一些比较著名的bbs平台,会有不法分子大规模攻击控制无线网络,并通过截取相关平台的登录信息,继而登录该平台发布违法信息用于诈骗。
在登录过程中对密码等明文信息加密传输是个比较流行的解决办法,一般采用RSA非对称加密算法,通过RSA密钥对将公钥、私钥分开存储,公钥用于前端加密,私钥用于后端解密。
实施过程:
1、前端引入加密库jsencrypt.js(https://github.com/travist/jsencrypt)。
2、生成一份RSA密钥对,公钥放置于前端可访问位置,可以是文件,也可以是页面变量。后端要加密存储严防泄露。
公钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhXzH9nldFX03YmKChOtQ
3L3sEmfBoNQpuLUblZUP/gvgbJNsLvOXbP17jAsNz6hMtAHcU3BZd1ihL8p4al1M
mg0FH07GPHrpcuaOyYm6DvZi+VmLCE0lOTOTSlB8xlq3E1G8sRNXj3B/PRA2T0Ia
WgYWke9DNfKO34SfphtRig3rp2GFk+QSPBd4WJvApwIoh8kNQvls+69A1TJPzio6
F2+dZRF3GxeSuc1YnSli15OYujQZ9t1zTI9h7yhXPfbqayf8y4ktD+bRi8anOR1A
7U6pawjf51hnWhuts0w6cEHQwu5yvs3PMSasgOM8BQs3yPrn8os7aC8ssGOfDdaI
twIDAQAB
-----END PUBLIC KEY-----
私钥:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAhXzH9nldFX03YmKChOtQ3L3sEmfBoNQpuLUblZUP/gvgbJNs
LvOXbP17jAsNz6hMtAHcU3BZd1ihL8p4al1Mmg0FH07GPHrpcuaOyYm6DvZi+VmL
CE0lOTOTSlB8xlq3E1G8sRNXj3B/PRA2T0IaWgYWke9DNfKO34SfphtRig3rp2GF
k+QSPBd4WJvApwIoh8kNQvls+69A1TJPzio6F2+dZRF3GxeSuc1YnSli15OYujQZ
9t1zTI9h7yhXPfbqayf8y4ktD+bRi8anOR1A7U6pawjf51hnWhuts0w6cEHQwu5y
vs3PMSasgOM8BQs3yPrn8os7aC8ssGOfDdaItwIDAQABAoIBABOrKamTA1itvRHl
kvaz15PW9ihWGm0wpb8eDGTzdEpKBLTq2fdnFApOpTwiytOsqDSjy4uN09jmecWZ
bzm46pcOURFmYYY61BgGicZ/YSdgPYAhJf/Aojn18/9wsZnmdvBFTGjJAU9U06Kz
N1VhV5GpMP0qxHv38/5SQ9XNU6vkHdcyoMrxPn04fxrxYRTPKu2pZnrkaghcDWPF
UvwDyvokbwWU7cQqT/XIiQ0jyC+uZJY8RFbBo7wLt5h6f/OahBCQj698iOkEN9DQ
1TqfwB7yLS1msT32S9j+a+iJPJKiGDL2YdVd4LlNb5kW727ComCTpZaxLAp3gcXd
KuK4vkECgYEA8EgC24XB4wfsjBlpRn0xAx0LUfbtSkA7HgzDBiTOi2/PpOjjgwZc
PFrJfvJQOSbpPl+fTIPw5X2yf5CkkrW7cJDcHYjYEyV/h9+KBZT2yM4cofp1M4Pb
ua8e4ILPqqRNsh77A6vasVmw/ct9iRJXpTqzd1N7o7MK1/xWPBN6AsECgYEAjjhL
PtgkxV/N98fVW6GgDi9V2I6a7ImIKHX+hJlWnnH7o9zaE+ry7UfKtgGEGEYJnKCF
LCu68+isFnG0tUyOx/2eU6rfbmq88reNjc/5EDHncCecGZhZJVsTyfFmkXhmn6PD
YCDxEqY9C4xU1nDMK7PAT5EcAbTqUblsGj+8gXcCgYEA5mwoUVx0EsQGlFPKIU7t
MY8oy/GAnTP7fVW/sKSbbhxLhFnR1FTFHxvxH0xAoo4uHyKUIUxmN63S/4I2UHr2
xXwlmi0hCTtskWBNfAzenLMLwkntGvnYPLkzYxoPDBWEbMxI67xifLEGilwahtiQ
NGOWt1fXuaR5Qac7C2GiIAECgYAiToAQM9GC7x5fNAxKo01Zvp9lsti6UF7Q682u
rNKRPAuotoDApz9cb6H9j5YOyO5OowYc5puddLX2YA1oYoRax9omcqSdHRBhOFfk
KpP5DSC4FEX6gp6WfUbjwuCsHLAcuENL8AZXKlS1cW+RnvoRXLX6O5XW745KkoD6
P/+39wKBgQCGJsez3LS1sQ7T2CSDe3LKzU3Pk6TeZMdqASXtYpgizPULMYkG5nqQ
+0dCnEDw3hff2hnsYAOX/7h+GAP/xa7og+I08fRZK6FAxNHTRoBImuLYsk+ku9bd
f7ervjm1oxVnNDrShtYKH7KApNIoKBW2tMWgJEVfvulPL9SvnAgGkQ==
-----END RSA PRIVATE KEY-----
3、在登录信息提交前进行加密:
var password = $("#password").val();
var encrypt = new JSEncrypt();
encrypt.setPublicKey('这里填写公钥');
var encrypted = encrypt.encrypt(password);
$("#password").val(encrypted);
4、后端接收逻辑中先进行解密再进行正确性检验。
$password = $_POST['password'];//获取密码
$private_key = "这里填写私钥";
$pi_key = openssl_pkey_get_private($private_key);
$decrypted = "";//解密后的密码存放在这个变量
openssl_private_decrypt(base64_decode($password),$decrypted,$pi_key);//这里使用base64_decode是因为再前端到后端的传输过程中浏览器会自动对数据进行base64_encode
$password = $decrypted;//解密后的密码
改造后的登录提交效果:
前端js的加密和解密使用方式
var data = 'testData';
//公钥加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey('这里填写公钥');
var data_encrypted = encrypt.encrypt(data);
//私钥解密
var decrypt = new JSEncrypt();
decrypt.setPrivateKey('这里填写私钥');
var data_decrypted = decrypt.decrypt(data_encrypted);
if (data == data_decrypted) {
console.log('加密、解密成功');
}
后端PHP进行RSA加密、解密过程
$pi_key = openssl_pkey_get_private('这里填写私钥');//这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id
$pu_key = openssl_pkey_get_public('这里填写公钥');//这个函数可用来判断公钥是否是可用的
$data = "testData";//原始数据
$data_encrypted = "";//加密后的数据
$data_decrypted = "";//解密后的数据
//私钥加密
openssl_private_encrypt($data, $data_encrypted, $pi_key);
$data_encrypted = base64_encode($data_encrypted);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
//公钥解密
openssl_public_decrypt(base64_decode($data_encrypted), $data_decrypted, $pu_key);//私钥加密的内容通过公钥可用解密出来
echo $data.'<br/>';
echo $data_encrypted.'<br/>';
echo $data_decrypted.'<br/>';
$data_encrypted2 = "";//加密后的数据
$data_decrypted2 = "";//解密后的数据
//公钥加密
openssl_public_encrypt($data, $data_encrypted2, $pu_key);
$data_encrypted2 = base64_encode($data_encrypted2);
openssl_private_decrypt(base64_decode($data_encrypted2), $data_decrypted2, $pi_key);
echo $data.'<br/>';
echo $data_encrypted2.'<br/>';
echo $data_decrypted2.'<br/>';
jsencrypt.js生成密钥对的方式:
var crypt = new JSEncrypt({default_key_size: 1024});
crypt.getKey();
crypt.getPrivateKey();
crypt.getPublicKey();