(JS-PHP)使用RSA算法進行加密通信

     用戶名密碼明文直接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

相關文章
相關標籤/搜索