用户名密码明文直接POST到后端,很容易被别人从监听到。注:包括使用MD5等哈希函数处理后的数据,这里也算作明文(如今MD5爆破网站已经不少了~)。对安全性要求较高的网站,好比银行和大型企业等都会使用HTTPS对其进行加密通信。可是因为效率缘由,使用HTTPS的代价是及其昂贵的,对于访问量稍大的网站就会形成严重的性能瓶颈。解决方法通常只能采用专门的SSL硬件加速设备如F5的BIGIP等。因此不少网站选择了模拟SSL的作法,使用RSA来对密码等安全信息进行公钥加密,服务端用私钥解密。javascript
一般是对密码进行加密,具体以下:php
1.加载三个RSA的js库文件,能够到这里下载 http://www.ohdave.com/rsa/。html
2.获取秘钥:前端
#1. 相关信息:java
一般状况下网站的SSL证书是由专门的CA机构(如VeriSign)颁发,同时须要交纳必定数额的费用。但是对于平时开发测试或其余状况下,咱们本身也能够充当CA来生成本身颁发的证书。固然与前者相比缺点很明显:不能得到各个浏览器的信任,会弹出警告提示。不过,好消息是,对安全性要求稍低的网站如今能够考虑使用免费的CA认证(貌似是其级别最低的证书)。linux
跟VeriSign同样,StartSSL(网址:http://www.startssl.com,公司名:StartCom)也是一家CA机构,它的根证书好久以前就被一些具备开源背景的浏览器支持(Firefox浏览器、谷歌Chrome浏览器、苹果Safari浏览器等)。在2009年9月份,StartSSL居然搞定了微软:微软在升级补丁中,更新了经过Windows根证书认证程序(Windows Root Certificate Program)的厂商清单,并首次将StartCom公司列入了该认证清单,这是微软首次将提供免费数字验证技术的厂商加入根证书认证列表中。如今,在Windows 7或安装了升级补丁的Windows Vista或Windows XP操做系统中,系统会彻底信任由StartCom这类免费数字认证机构认证的数字证书,从而使StartSSL也获得了IE浏览器的支持。git
#2.要生成得到证书所需的密钥等文件:算法
openssl genrsa -des3 -out server.pem 1024 openssl req -new -key server.pem -out server.csr openssl rsa -in server.pem -out server.pem
使用上面的命令就会建立一个证书申请,这里咱们会要求输入国家、组织、姓名等信息,可是不会要求输入证书有效天数,由于证书有效天数是CA认证中心给咱们的;而后咱们会把这个生成好的cert.csr(Certificate Signing Request (CSR):证书签名申请)发给CA认证中心。CA认证中心经过后,会反馈(一般是邮件)回来认证的信息,再导入便可。后端
把上面生成的文件内容提交给CA,便可换取证书;若自行生成则:浏览器
openssl x509 -req -days 365 -in server.csr -signkey server.pem -out server.crt
把它们放到指定目录(例如:/ssl/),供下一步使用。
#3.获取十六进制的密钥:
数据是用ASN.1编码过的,因此能够用openssl命令从密钥文件(key或pem)提取秘钥
openssl asn1parse -out temp.ans -i -inform PEM < server.pem
3.javascript 加密代码:
function rsa_pwd(content){ //十六进制公钥
var rsa_n = "DB89C01D4550F9974C30AF5370214F3...."; setMaxDigits(131); //131 => n的十六进制位数/2+3
var key = new RSAKeyPair("10001", '', rsa_n); //10001 => e的十六进制
content_rsa = encryptedString(key, content); //不支持汉字
return content_rsa; }
4.php 加密/解密代码:
<?php /** * 公钥加密 * * @param string 明文 * @param string 证书文件(.crt) * @return string 密文(base64编码) */
function publickey_encodeing($sourcestr, $fileName) { $key_content = file_get_contents($fileName); $pubkeyid = openssl_get_publickey($key_content); if (openssl_public_encrypt($sourcestr, $crypttext, $pubkeyid)) { return base64_encode("".$crypttext); } } /** * 私钥解密 * * @param string 密文(二进制格式且base64编码) * @param string 密钥文件(.pem / .key) * @param string 密文是否来源于JS的RSA加密 * @return string 明文 */
function privatekey_decodeing($crypttext, $fileName, $fromjs = FALSE) { $key_content = file_get_contents($fileName); $prikeyid = openssl_get_privatekey($key_content); $crypttext = base64_decode($crypttext); $padding = $fromjs ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING; if (openssl_private_decrypt($crypttext, $sourcestr, $prikeyid, $padding)) { return $fromjs ? rtrim(strrev($sourcestr), "/0") : "".$sourcestr; } return ''; } ?>
5.测试代码:
//JS->PHP 测试 $_POST['password']是js加密后的信息
$txt_en = $_POST['password']; $txt_en = base64_encode(pack("H*", $txt_en)); $file = 'ssl/server.pem'; $txt_de = privatekey_decodeing($txt_en, $file, TRUE); var_dump($txt_de); //PHP->PHP 测试
$data = "汉字:1a2b3c"; $config = Core::getInstance()->config; $file1 = 'ssl/server.crt'; $file2 = 'ssl/server.pem'; $a = publickey_encodeing($data, $file1); $b = privatekey_decodeing($a, $file2); var_dump($b);
6.需注意:
#1.PHP中openssl扩展公私钥加密函数只支持小数据,加密时117字节,解密时128字节。若否则得本身循环加密后合并。
#2.SSL自己也只是用RSA来进行密钥加密,数据加密则是利用这个加密的密钥进行对称加密,以保证速度。因此万不可将其用于大数据量加密!
7.本方案几处优势:
#1.安全性高。基于非对称的RSA算法加密数据,只要在私钥不被暴露的前提下,密钥长度足够长,短期内基本是没法破解的。
#2.使用方便。前端使用现成的JS库来实现加密,PHP端则可直接使用现成的openssl扩展,而不用RSA的PHP源码实现或本身开发扩展。
#3.速度靠谱。因为RSA解密算法至关复杂,而该操做交由PHP端扩展来实现,效率上比网上的PHP代码要高许多。
#4.便于升级。密钥是直接从linux下openssl工具生成的证书中获取,不只不用其余密钥生成工具,也方便从此升级到真正的HTTPS。
8.参考文章:
http://www.jishuer.com/static/article-270.html
http://blog.csdn.net/linvo/article/details/5619807
http://blog.sina.com.cn/s/blog_4fcd1ea30100yh4s.html
http://blog.csdn.net/fenglibing/article/details/8610280