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


     用戶名密碼明文直接POST到后端,很容易被別人從監聽到。注:包括使用MD5等哈希函數處理后的數據,這里也算做明文(現在MD5爆破網站已經很多了~)。對安全性要求較高的網站,比如銀行和大型企業等都會使用HTTPS對其進行加密通訊。但是由於效率原因,使用HTTPS的代價是及其昂貴的,對於訪問量稍大的網站就會造成嚴重的性能瓶頸。解決方法一般只能采用專門的SSL硬件加速設備如F5的BIGIP等。所以很多網站選擇了模擬SSL的做法,使用RSA來對密碼等安全信息進行公鑰加密,服務端用私鑰解密。

通常是對密碼進行加密,具體如下:

1.加載三個RSA的js庫文件,可以到這里下載 http://www.ohdave.com/rsa/

2.獲取秘鑰:

  #1. 相關信息:

  通常情況下網站的SSL證書是由專門的CA機構(如VeriSign)頒發,同時需要交納一定數額的費用。可是對於平時開發測試或其他情況下,我們自己也可以充當CA來生成自己頒發的證書。當然與前者相比缺點很明顯:不能獲得各個瀏覽器的信任,會彈出警告提示。不過,好消息是,對安全性要求稍低的網站現在可以考慮使用免費的CA認證(貌似是其級別最低的證書)。

   跟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瀏覽器的支持。

 #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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM