共计 5651 个字符,预计需要花费 15 分钟才能阅读完成。
目前一般帐号系统,都是 https 来传输账户性息,申请一个 https 证书也不贵。但是网站的其它功能并不需要走 https 协议,https 和 http 混布比较麻烦,所以决定先实现一个 http 协议传输 RSA 非对称密钥算法加密密码的方案。这样做只能说是保证不明文传密码,但是并不能防身份伪造,所以其实还是不安全的,只是目前产品能接受,算是一个过渡期吧。有需要的话还是要改成 https 的。
关于 rsa 算法,具体参考维基百科相关的介绍。简单来说,用 rsa 算法产生一对公钥和私钥,通信双方 A 和 B,A 用公钥加密要发送的数据,B 用私钥来解密 A 发过来的密文,从而获得 a 想要发过来的数据。保证 rsa 密文不容易被破解的理论依据是对极大整数做因数分解的难度非常大。
下面具体看看实现过程。这里前端用到 rsa 的 js 实现方案 jsencrpt.js,后端用 php 的 open_pkey_new 等相关方法。
1.【后端】先看 php 生成公钥密钥对相关代码:
function generatePubPri() {$config = array("config" => '/path/to/openssl.cnf'); | |
$res = openssl_pkey_new($config); | |
openssl_pkey_export($res,$pri, null, $config); | |
$d= openssl_pkey_get_details($res); | |
$pub = $d['key']; | |
$pubFd = fopen("pub.txt", "w"); | |
fwrite($pubFd, $pub); | |
fclose($pubFd); | |
$priFd = fopen("pri.txt", "w"); | |
fwrite($priFd, $pri); | |
fclose($priFd); | |
} |
这里前提是要安装 openssl,php 要加载 openssl 扩展。执行 generatePubPri 即可的到如下的公钥密钥对,每次执行生成的都不一样。
[xxx@xxx makedemo]$ cat pri.txt | |
-----BEGIN RSA PRIVATE KEY----- | |
MIICXQIBAAKBgQCq/8HruBYhems80BluLiiP0uUTzM/NJSFktzxA1rfzjhEg8z0W | |
r0WAvIdbye2vTG0CYi6PGpjxgUkEVaaHLWEIMiA4g3TIFSUp5pmlWRpGNqilrxd4 | |
sXM5wzL13WkN1j6gBfZNJt62mO35A2Ubl9fbNw/YU2KNPR0+EHP0Z6agmwIDAQAB | |
AoGAViPcllf3ngnDN7FE/kH2YO1GRMEp9Re9SLUdfzQrGl/4tPaTUXgdtQpDzbNd | |
Lq97QnYfKiul3BLaq3pSF0p+1AUHtJby/HT1Tqz0380x9Y+QKjJErePycTs28zIq | |
FXmCMnOqxhaWPB89hxCIG0g7bVt9qGRDUZGY05kMwSM9gvECQQDcWjQoBfb4IQls | |
RUQlprzizQD+S4cHJdxCq5qh7TqyH1IPoHq04tQsuYFVEH2+Z0Spimz/oluNuDnJ | |
NppKdJZdAkEAxqmbtzs9bPbyihb9qpsD8Sne1DIo5uRBJ7G4/RE4vazaAXX9HUIS | |
HZg/To5XSGHzgQteIUXJRjpX5sYLCS8zVwJAQxElbMUb/Tu47X5LlpYgSXuSANQm | |
HfPVDWnDn+NfiRVlWaJDlsivQYmYprZlP02ZJW0fbdMRwJnA5NA8t8qydQJBAKZH | |
dERLW0CG+b7HO46+rPAAAbhOO5n2VuqogJOhBIMN2HL8lN0WXh9TPTm9PiUhhzTt | |
lN34kV0snEJWZQpM7YUCQQCgKhoAlp4DpcYvqq569UI7IE4ZL4l9RlkiNG1UYyda | |
iZoNVN7ji8K2ZvOKykJBwDeKIn4JrknUHrjZXEweRKEl | |
-----END RSA PRIVATE KEY----- | |
[xxx@xxx makedemo]$ cat pub.txt | |
-----BEGIN PUBLIC KEY----- | |
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq/8HruBYhems80BluLiiP0uUT | |
zM/NJSFktzxA1rfzjhEg8z0Wr0WAvIdbye2vTG0CYi6PGpjxgUkEVaaHLWEIMiA4 | |
g3TIFSUp5pmlWRpGNqilrxd4sXM5wzL13WkN1j6gBfZNJt62mO35A2Ubl9fbNw/Y | |
U2KNPR0+EHP0Z6agmwIDAQAB | |
-----END PUBLIC KEY----- |
2.【前端】用公钥加密一下密码 ”123456″。
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>JS->jsencrypt.js RSA 加密实现 </title> | |
<script type="text/javascript" src="jsencrypt.js"></script> | |
</head> | |
<body> | |
<script type="text/javascript"> | |
var crypt = new JSEncrypt(); // 新建 rsa 对象 | |
var publickey = '\ | |
-----BEGIN PUBLIC KEY-----\ | |
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq/8HruBYhems80BluLiiP0uUT\ | |
zM/NJSFktzxA1rfzjhEg8z0Wr0WAvIdbye2vTG0CYi6PGpjxgUkEVaaHLWEIMiA4\ | |
g3TIFSUp5pmlWRpGNqilrxd4sXM5wzL13WkN1j6gBfZNJt62mO35A2Ubl9fbNw/Y\ | |
U2KNPR0+EHP0Z6agmwIDAQAB\ | |
-----END PUBLIC KEY-----\ | |
'; | |
crypt.setPublicKey(publickey);// 添加来自服务端的 publickey | |
var result = crypt.encrypt('123456'); // 返回值为加密后的结果 | |
console.log(result); | |
</script> | |
</body> | |
</html> |
在浏览器里访问后,控制台会打印出如下的加密字符串:
SonHPbJpQBwygjZ5ZMtybfLEylnNCsd3poBsNxSt3QkUSDe+Pf7lf4JJIot9Ybd7mAXiOUgGZR7VctCSJhzzZQWNZp1or6h6dsYoFHE/dbDHIxJGcXMNfv5BqrfAMGqkQVvyrED3NHcrgXokataRJOrsU7yvKpQKW6e3j+zcZD8=
eRA40/RbbbqtuEC10Ee3NVDsnpfgibn8nRuTaPmvXI1XjVFX8pjwtMxiuT9xaBfX8K+LI/6ccgghYyJdxjd8V+DyxBPz6/QzT3f5eoOz9ULD85r0K//BuKvuTiyQ/NajProvPN3ns6UzxECmuFg0UNtrMNkOdFRpaAtueadKJDU=
Tqgagyx5DlDLI/tcxYsnN/3AbUPCX/EFE6yn5SoVMX3R/RQ6od6b4hT10LUctcBZ649RhHkwzxTFzIFfvbRS87OftOhebGXAP9JpN/xt9IsaXOU4wp8ZiyQKIrClnepXtRaSC10WF/ishsejgo3i7APXs7fWJiEMkoqRYwnbyPo=
。。。。。。奇怪的是每次刷新打印的都不一样。估计都可以用的。
3.【后端】解密前端发送过来的密文
解密的方法:
/** | |
* rsa 解密 | |
* @access public | |
* @param 密文 | |
* @return 解密后的字符串 | |
*/ | |
function decrypt($data, $privkey) {if (openssl_private_decrypt(base64_decode($data), $decrypted, $privkey)){$data = $decrypted; | |
}else {$data = ''; | |
} | |
return $data; | |
} |
priveKey=file g et c ontents(“pri.txt“); priveKey=filegetcontents(“pri.txt”); data = “SonHPbJpQBwygjZ5ZMtybfLEylnNCsd3poBsNxSt3QkUSDe+Pf7lf4JJIot9Ybd7mAXiOUgGZR7VctCSJhzzZQWNZp1or6h6dsYoFHE/dbDHIxJGcXMNfv5BqrfAMGqkQVvyrED3NHcrgXokataRJOrsU7yvKpQKW6e3j+zcZD8=
”;
echo decrypt(data, data, priveKey);
echo “\n”;
最后是解密出 ”123456″
[xxx@xxx makedemo]$ php rsa.php | |
123456 |
试了一下另外两个密文,非常棒,发现也是可以解出 ”123456″。
最后给一个完整的 demo,流程如下:
代码如下:
1.submitPassword.html
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>JS->jsencrypt.js RSA 加解密实现 </title> | |
<script type="text/javascript" src="jsencrypt.js"></script> | |
<script type="text/javascript" src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script> | |
</head> | |
<body> | |
<script type="text/javascript"> | |
var PassWord = "123456"; | |
function myEncrypt(pass) {var crypt = new JSEncrypt(); | |
var publickey = ""; | |
crypt.setPublicKey(publickey); | |
return crypt.encrypt(pass); | |
} | |
var promise = $.ajax({url: "getPublicKey.php", | |
method: "POST", | |
dataType: "json", | |
data: {}}); | |
promise.done(function(data){if(data.code === 0) {var passWord = myEncrypt(PassWord); | |
var passPromise = $.ajax({url: "recievePassword.php", | |
method: "POST", | |
dataType: "json", | |
data: {"password": passWord} | |
}); | |
passPromise.done(function(data){if(data.code === 0) {console.log("submit success."); | |
}else{console.log("submit failed."); | |
} | |
}); | |
passPromise.fail(function(err){console.log(err); | |
}); | |
}else {console.log("submit failed."); | |
} | |
}); | |
promise.fail(function(err){console.log(err); | |
}); | |
</script> |
2.getPublicKey.php
function generatePubPri() {$config = array("config" => '/home/users/zhutianpeng/.jumbo/etc/ssl/openssl.cnf'); | |
$res = openssl_pkey_new($config); | |
openssl_pkey_export($res,$pri, null, $config); | |
$d= openssl_pkey_get_details($res); | |
$pub = $d['key']; | |
$pubFd = fopen("pub.txt", "w"); | |
fwrite($pubFd, $pub); | |
fclose($pubFd); | |
$priFd = fopen("pri.txt", "w"); | |
fwrite($priFd, $pri); | |
fclose($priFd); | |
return $pub; | |
} | |
$publicKey = generatePubPri(); | |
$data = array("code" => 0, | |
"msg" => "success", | |
"data" => array("pubkey" => $publicKey)); | |
echo json_encode($data); |
3.recievePassword.php
$passWord = $_POST['password']; | |
$ret = array(); | |
if(!empty($passWord)) {$ret['code'] = 0; | |
$ret['msg'] = "success"; | |
}else {$ret['code'] = 1; | |
$ret['msg'] = "not recieved a password"; | |
} | |
echo json_encode($ret); |
[完]
本文永久更新链接地址 :http://www.linuxidc.com/Linux/2018-02/150891.htm