按照等保要求,密码类的信息必须经过RSA加密后才能传递:
需要对密码传输过程中进行加密方式传输。
如采用md5加验或SM1、SM2、SM4、3DES、AES、RSA加密算法,
同时也不要直接采用暴露在互联网上的md5、base64算法、URL编码转换。
虽然仅仅用base64来加密已被禁止,但是思路还是一样的:“客户端使用js加密,服务端使用php解密”。
jsencrypt.js
和jsrsasign.js
都可以实现加密解密,但jsencrypt.js
更方便,jsrsasign.js
更全面;
jsencrypt.js
加密后就已经是base64格式
,而jsrsasign
需要分两步分别实现RSA加密
和base64编码
。
好了,话不多说,言归正传。
RSA基本原理就是客户端上有一把公钥,服务器上有一把私钥,这两把钥匙长相不同,但有着不可思议的数学关系,能互相识别对方。
客户端传递信息前,先利用公钥把信息加密(加密过程有随机数参与,所以每次结果都不同),到达后,服务端利用私钥再把信息解密还原成原信息。
正是由于公私两把钥不一样,甚至其中一把是外人所不知的,所以这种加密方式也叫“非对称加密”。
实际使用时把公钥对外公布,可以由很多客户端拥有,而私钥只限服务端,这样由于没有私钥,即便客户端传递数据时被人拦截,那这些被拦截的数据也是无法解密的。
为了进一步提高安全性,还可以加入签名,这里就不赘述了。
参考学习
《RSA加密、解密、签名、验签的原理及方法》
《RSA算法》
配置并获得公钥和私钥。
jsencrypt.js
地址:https://github.com/travist/jsencrypt,解压后将其中jsencrypt.min.js
安装到指定目录。
jsrsasign.js
地址:https://kjur.github.io/jsrsasign/,解压后将其中jsrsasign-all-min.js
安装到指定目录。
配置服务器php.ini
去掉 ;
,激活extension=openssl
获取公私密钥
二选一即可
本文代码案例以第二种“在线生成”后的公私钥字符串作为变量进行操作。
//注意每隔64位必须要有一个换行
//公钥
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCC2Kh46ZE2/k6hBfRHXOm37lQh
Q9g7phdw2jGo0KNgW+wxW2pmZzQhLg+Dx9FyEXa3j0YraktnCIBkx816DLw/xUIh
RObjYX4+5hUnv6IGtHf5pNyP9v/utiRdkko+Vj1BDWtI4lw/0DXruLJIV06EIf95
TFfZaEk81/EO31FdpQIDAQAB
-----END PUBLIC KEY-----
//私钥
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCC2Kh46ZE2/k6hBfRHXOm37lQhQ9g7phdw2jGo0KNgW+wxW2pm
ZzQhLg+Dx9FyEXa3j0YraktnCIBkx816DLw/xUIhRObjYX4+5hUnv6IGtHf5pNyP
9v/utiRdkko+Vj1BDWtI4lw/0DXruLJIV06EIf95TFfZaEk81/EO31FdpQIDAQAB
AoGATyoMTBNsY2xbYDr8/4wsb7cHOZUVp4km14V71BpfLnaPIZGgf1JjjMuUYXOs
uantPMO3fZ7y/eR74f2syPIZllFqSI0CP1HkDyTH5BsLqKqTmzWcbvrWx1Pc2Dis
OCf9KVz4o/Scly3igI8Nblrk5zP03NMBb7dqyNzqsP2i6gUCQQDGojaHEWZ4qTZm
wFhTccKX/DHc1vJesjS3JQHRU6TDWSML476KGoH3+S23XRfRsIFzN1QWrhqfopfg
phP2gcPnAkEAqKKnmAOY0BhzMh0D7q94dtGZbg/MxQPpBRWvEcLsragv8NilM5Mp
6gUjLcWSgEoBq4VcywQE/AOosXbOaQcgkwJAdedRgIkGjza50PH5O8a54CdVnaWF
Bkq3WcLAunTwxvfBAsyzjBxB62RgC4hZnCEuJarA4hmEOh90EWfjT54lHwJALSni
2MOd2Z2yvGko9HPqP2hDP0bcAKfbcJEuIgOif5/btxVOqVFwmExn74pKgjFP4TAG
ehjJfPU96Ml43ogaIQJAYpbORQgUvJilLJGTIisWNF8Wa+lEt1J4tn7p47IDMOAa
CwcbmDGnhnh67CXrwwJvb4F8tK/NiwNqlLhyDrONyg==
-----END RSA PRIVATE KEY-----
<script type="text/javascript" src="jQuery.min.js"></script>
<script type="text/javascript" src="jsencrypt.min.js"></script>
<script type="text/javascript" src="jsrsasign-all-min.js"></script>
<script type="text/javascript">
//公钥,注意换行符\n
var pubKey = "-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCC2Kh46ZE2/k6hBfRHXOm37lQh\n" +
"Q9g7phdw2jGo0KNgW+wxW2pmZzQhLg+Dx9FyEXa3j0YraktnCIBkx816DLw/xUIh\n" +
"RObjYX4+5hUnv6IGtHf5pNyP9v/utiRdkko+Vj1BDWtI4lw/0DXruLJIV06EIf95\n" +
"TFfZaEk81/EO31FdpQIDAQAB\n" +
"-----END PUBLIC KEY-----";
//用户录入的内容
var content = 'hello world';
console.log('content:' + content);
//=======方法一:jsencrypt初始化,创建加密对象实例=======
var encryptor = new JSEncrypt();
//设置公钥
encryptor.setPublicKey(pubKey);
//加密,已经实现了RSA+base64
var c = encryptor.encrypt(content);
console.log('jsencrypt Base64:' + c);
//jsencrypt方式提交
jQuery.post("check.php",{"c":c},function(r){
console.log('jsencrypt Result:' + r);
});
//=======方法二:jsrsasign初始化=======
var pub = KEYUTIL.getKey(pubKey);
//RSA加密,生成16进制字符串
var enc = KJUR.crypto.Cipher.encrypt(content,pub);
console.log('jsrsasign RSA:' + enc);
//base64对数据重新编码
c = hextob64(enc);
console.log('jsrsasign Base64:' + c);
//jsrsasign方式提交
jQuery.post("check.php",{"c":c},function(r){
console.log('jsrsasign Result:' + r);
});
</script>
参考学习
《前端利用jsencrypt.js进行RSA加密》
《JS 使用RSA加密解密》
《采用JSEncrypt,js与PHP服务端加密》
《jsrsasign使用笔记(加密,解密,签名,验签)》
《前端 rsa加密参数的实现(加密库:jsrsasign)》
//注意每隔64位必须要有一个换行
//公钥,本变量在本例中并未用到
/*$public_key = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCC2Kh46ZE2/k6hBfRHXOm37lQh
Q9g7phdw2jGo0KNgW+wxW2pmZzQhLg+Dx9FyEXa3j0YraktnCIBkx816DLw/xUIh
RObjYX4+5hUnv6IGtHf5pNyP9v/utiRdkko+Vj1BDWtI4lw/0DXruLJIV06EIf95
TFfZaEk81/EO31FdpQIDAQAB
-----END PUBLIC KEY-----';*/
//私钥
$private_key = '-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCC2Kh46ZE2/k6hBfRHXOm37lQhQ9g7phdw2jGo0KNgW+wxW2pm
ZzQhLg+Dx9FyEXa3j0YraktnCIBkx816DLw/xUIhRObjYX4+5hUnv6IGtHf5pNyP
9v/utiRdkko+Vj1BDWtI4lw/0DXruLJIV06EIf95TFfZaEk81/EO31FdpQIDAQAB
AoGATyoMTBNsY2xbYDr8/4wsb7cHOZUVp4km14V71BpfLnaPIZGgf1JjjMuUYXOs
uantPMO3fZ7y/eR74f2syPIZllFqSI0CP1HkDyTH5BsLqKqTmzWcbvrWx1Pc2Dis
OCf9KVz4o/Scly3igI8Nblrk5zP03NMBb7dqyNzqsP2i6gUCQQDGojaHEWZ4qTZm
wFhTccKX/DHc1vJesjS3JQHRU6TDWSML476KGoH3+S23XRfRsIFzN1QWrhqfopfg
phP2gcPnAkEAqKKnmAOY0BhzMh0D7q94dtGZbg/MxQPpBRWvEcLsragv8NilM5Mp
6gUjLcWSgEoBq4VcywQE/AOosXbOaQcgkwJAdedRgIkGjza50PH5O8a54CdVnaWF
Bkq3WcLAunTwxvfBAsyzjBxB62RgC4hZnCEuJarA4hmEOh90EWfjT54lHwJALSni
2MOd2Z2yvGko9HPqP2hDP0bcAKfbcJEuIgOif5/btxVOqVFwmExn74pKgjFP4TAG
ehjJfPU96Ml43ogaIQJAYpbORQgUvJilLJGTIisWNF8Wa+lEt1J4tn7p47IDMOAa
CwcbmDGnhnh67CXrwwJvb4F8tK/NiwNqlLhyDrONyg==
-----END RSA PRIVATE KEY-----';
//可以先预判一下openssl扩展是否开启
//if (extension_loaded('openssl')){}
//私钥定位,如果是文件,则使用$private_key_res=file_get_contents($path)
$private_key_res = openssl_pkey_get_private($private_key);
if(!$private_key_res ){
//私钥不可用
return FALSE;
}
//返回值
$data = '';
//解码,可能出现加号被转成空格的情况
$password = base64_decode(str_replace(' ','+', $_POST['c']));
//解密
$result = openssl_private_decrypt($password, $data, $private_key_res);
if(!$result ){
//解密失败
return FALSE;
}
echo $data;
?>
参考学习
《php RSA加解密》
《PHP RSA加解密详解(附代码)》
demo版本点击此处:《RSA:js加密,php解密》
\n
和 +
;//例如
var pubKey = "-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCC2Kh46ZE2/k6hBfRHXOm37lQh\n";
js
获得的 value
就不用手动增加 \n
来改写公钥了;//例如
<input type="hidden" id="pk" value="$public_key;?>" />
<script type="text/javascript">
var v = jQuery('#pk').val();
console.log(v);
</script>
+
变成 空格
,所以要完成一次过滤。当然,直到目前我还没发现有这个问题;str_replace(' ','+', $p)