javascript
JS关于提交的RSA加密算法
我們平時做用戶登錄表單提交,用戶名密碼都是明文直接POST到后端,這樣很容易被別人從監(jiān)聽到。
?
注:包括使用MD5等哈希函數(shù)處理后的數(shù)據(jù),這里也算做明文(現(xiàn)在MD5爆破網(wǎng)站已經(jīng)很多了~)。
?
對安全性要求較高的網(wǎng)站,比如銀行和大型企業(yè)等都會使用HTTPS對其進行加密通訊。
?
但是由于效率原因,使用HTTPS的代價是及其昂貴的,對于訪問量稍大的網(wǎng)站就會造成嚴重的性能瓶頸。解決方法一般只能采用專門的SSL硬件加速設(shè)備如F5的BIGIP等。
?
所以很多網(wǎng)站選擇了模擬SSL的做法,使用RSA來對密碼等安全信息進行公鑰加密,服務(wù)端用私鑰解密。
?
通常是對密碼進行加密,本文也拿密碼加密為例。
?
網(wǎng)上相關(guān)信息太少,折騰了幾天,終于有眉目了,先貼代碼,關(guān)鍵部分后面說明。
?
首先加載三個RSA的js庫文件,可以到這里下載 http://www.ohdave.com/rsa/
?
javascript部分代碼(with jQuery)
?
view plaincopy to clipboardprint?
$(document).ready(function(){ ?
//十六進制公鑰 ?
var rsa_n = "C34E069415AC02FC4EA5F45779B7568506713E9210789D527BB89EE462662A1D0E94285E1A764F111D553ADD7C65673161E69298A8BE2212DF8016787E2F4859CD599516880D79EE5130FC5F8B7F69476938557CD3B8A79A612F1DDACCADAA5B6953ECC4716091E7C5E9F045B28004D33548EC89ED5C6B2C64D6C3697C5B9DD3"; ?
??????
$("#submit").click(function(){ ?
????setMaxDigits(131); //131 => n的十六進制位數(shù)/2+3 ?
????var key ?????= new RSAKeyPair("10001", '', rsa_n); //10001 => e的十六進制 ?
????var password = $("#password").val(); ?
????password = encryptedString(key, password); //不支持漢字 ?
????$("#password").val(password); ?
????$("#login").submit(); ?
????alert(password); //test ?
}); ?
}); ?
?
PHP部分代碼
?
view plaincopy to clipboardprint?
?
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); ?
????} ?
} ?
?
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 ; ?
} ?
//JS->PHP 測試 ?
$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); ?
?
其中密鑰的獲取是關(guān)鍵(其他難點已經(jīng)被從代碼中解決)
?
由于密鑰從x.509證書中獲取,所以要先生成密鑰及證書文件(本文中用的1024位密鑰),具體生成方法可以參考我之前的那篇《Nginx下配置HTTPS(SSL)安全站點》
?
這里重點說一下怎么獲取十六進制的密鑰。
?
從文件中讀取密鑰之前嘗試了很多方式,無論怎么都無法提取正確的十六進制密鑰。網(wǎng)上查了發(fā)現(xiàn)數(shù)據(jù)是用ASN.1編碼過的……汗~
?
最后無意中注意到linux下用openssl命令貌似可以從密鑰文件(key或pem)提取。方式如下:
?
openssl asn1parse -out temp.ans -i -inform PEM < server.pem
?
顯示結(jié)果如下:
?
?
?
從這里可以看到最終的16進制密鑰。
?
個人感覺這種方法并不算模擬HTTPS,只是利用其用到的RSA非對稱加密算法實現(xiàn)小數(shù)據(jù)量安全加密。若要較完全的模擬SSL通信,就需要用RSA對另一密鑰加密,然后通過一系列握手流程再進行對稱加密。
?
PHP中openssl擴展公私鑰加密函數(shù)只支持小數(shù)據(jù),加密時117字節(jié),解密時128字節(jié)。若不然得自己循環(huán)加密后合并。
?
SSL本身也只是用RSA來進行密鑰加密,數(shù)據(jù)加密則是利用這個加密的密鑰進行對稱加密,以保證速度。所以萬不可將其用于大數(shù)據(jù)量加密!
?
最后總結(jié)下本方案幾處優(yōu)點:
?
1、安全性高。基于非對稱的RSA算法加密數(shù)據(jù),只要在私鑰不被暴露的前提下,密鑰長度足夠長,短時間內(nèi)基本是無法破解的。
?
2、使用方便。前端使用現(xiàn)成的JS庫來實現(xiàn)加密,PHP端則可直接使用現(xiàn)成的openssl擴展,而不用RSA的PHP源碼實現(xiàn)或自己開發(fā)擴展。
?
3、速度靠譜。由于RSA解密算法相當復(fù)雜,而該操作交由PHP端擴展來實現(xiàn),效率上比網(wǎng)上的PHP代碼要高許多。
?
4、便于升級。密鑰是直接從linux下openssl工具生成的證書中獲取,不僅不用其他密鑰生成工具,也方便今后升級到真正的HTTPS。
總結(jié)
以上是生活随笔為你收集整理的JS关于提交的RSA加密算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP正则表达式快速学习方法
- 下一篇: Linux下svn搭建配置流程