經(jīng)常有讀者詢問,如何在其站點上使用JavaScript,以確保用戶登錄時的口令不會外泄。對于這樣的問題,我的第一反應就是告訴他們使用SSL(安全套接字協(xié)議層)。如使用正確,SSL對于安全要求較高的Web應用是最佳的解決方案。但是,也有相當一部分開發(fā)者,他們的Web應用對安全性的要求并不高,因此他們并不希望訪問者使用SSL 登錄。
Web應用一般使用一種叫做“會話狀態(tài)管理”(Session State Management) 的技術來追蹤和管理瀏覽器與服務器之間的相互活動。因為每個瀏覽器的瀏覽要求相對于其他瀏覽器都是獨立的(正如超文本傳輸協(xié)議中定義的那樣),所以Web 應用必然使用某些技巧,如Cookie、隱藏表格字段、或重寫URL,它們可以識別出服務器與某個瀏覽器進行的獨立會話。大多數(shù)的服務器端編程環(huán)境(如ASP、PHP、ColdFusion等)都使用Cookie。
會話狀態(tài)管理的問題在于從根本上講它是不安全的。這些被用來管理會話狀態(tài)的Cookie、表單值、或URL要在瀏覽器和服務器之間往來傳送,黑客可以在途中攔截它們。一旦攔截成功,黑客就可以利用這些信息強行接管用戶會話。
在大多數(shù)服務器端腳本編寫環(huán)境里,你都可以采取一些措施以減少此類泄密的發(fā)生。例如,你可以為Cookie設定很短的使用期限,應用“難預期會話狀態(tài)”信息。然而,最安全的解決方案還是使用SSL。使用SSL,不論用戶口令,還是會話狀態(tài)信息都會受到保護。
如果你不使用SSL,那么可以要求用戶對你的應用中的每個敏感頁進行重新認證。但是,從用戶的角度來講,這種方式未免太過麻煩??傊?,你必須清楚你和你的用戶究竟愿意承擔多高的風險。如果口令泄露的風險過高,你就需要使用SSL建立應用。如果你不能使用SSL,可以采用基于MD5的登錄方式作為代替。它至少可以保護你的用戶的口令免于外泄。另外,再選用一種可以防止會話狀態(tài)信息被竊的服務器端腳本編寫技術。
通常,如果一個用戶不使用SSL登錄(即原來的HTTP),那么從離開瀏覽器直到到達目標網(wǎng)絡服務器的這段時間里,用戶口令都處于無保護的暴露狀態(tài),正如下頁中的圖表所示。
不過,我們可以利用一種不可逆的函數(shù)開發(fā)一種登錄方案,利用這種方案就不會暴露用戶的口令。函數(shù)是集合的元素之間的一種對應關系,在從集合A到集合B的函數(shù)中,A中每個元素在B中都有一個唯一的元素與之相對應。不可逆函數(shù)在計算上很難逆轉(zhuǎn)——即給定集合B中的一個元素,很難確定在集合A中的哪個元素與之相對應。
這好比是一臺碎紙機。把文件放入碎紙機中銷毀是很容易的。但是反之,如果要把銷毀后的碎紙屑重新拼湊成原文可就難上加難了。
<B>采用MD5解決方案<B>
當今最流行的不可逆函數(shù)應用程序之一就是由Ronald Rivest開發(fā)的MD5算法。Ronald Rivest還是著名的RSA(Rivest,Shamir,Adelman)加密算法的開發(fā)者之一。MD5算法能為任何長度的信息生成一個16字節(jié)大小的“數(shù)字指紋”。這個信息可以是一個字符串、一個文件、一個文本流或任何其它形式的字節(jié)序列。在RFC1321中有MD5算法的詳細描述。
我們要開發(fā)一種使用MD5算法的登錄方式,用以保護從一個瀏覽器發(fā)送至網(wǎng)絡服務器的用戶口令。
當一名用戶對某個網(wǎng)絡應用提出登錄請求時,其網(wǎng)絡服務器就會提供給用戶一個登錄表格。這是一個帶有隨機生成值的表格。其中的隨機生成值由服務器端腳本從一個數(shù)億記的取值空間中隨機選取生成。
<img src="/Newhua_Files/Net_pic/2006-1/18/0611815115410665.gif"">
用戶在登錄表格中輸入他或她的用戶名和口令,用戶端腳本給口令附加一個隨機值,然后用MD5不可逆算法對結(jié)果進行計算。再用計算得出的值代替原口令。我把這個值稱為MD5口令。
最后,用戶端腳本把用戶名和這個MD5口令發(fā)送到網(wǎng)絡服務器。因為在瀏覽器與服務器之間傳送的是MD5的運算結(jié)果,所以任何人都無法通過計算得出用戶所輸入的原始口令。
<img src="/Newhua_Files/Net_pic/2006-1/18/0611815115696921.gif"">
網(wǎng)絡服務器在接收用戶名和MD5口令后,會執(zhí)行與用戶瀏覽器相同的運算。它給用戶口令(從服務器的被保護區(qū)域中提取)附加上隨機值(即已發(fā)送給用戶的隨機值),并計算出正確的MD5口令值。然后網(wǎng)絡應用程序把這個值和它從瀏覽器收取的值相比較。如果兩值相等,網(wǎng)絡應用程序就會生成一個服務器端會話變量,證明此用戶身份正確。
<img src="/Newhua_Files/Net_pic/2006-1/18/0611815120053685.gif"">
說到這里,你也許會置疑使用隨機值的必要性。其實,這個隨機值是用來防止再度攻擊的。如果只有原始用戶口令通過MD5,那么相應得出的MD5口令就會總是同一個值。黑客只要截獲MD5口令就同樣可以登錄進入網(wǎng)絡應用。使用了隨機值后,每次登錄時生成的MD5口令都是唯一的,這樣就避免了上述問題的出現(xiàn)。
<B>JavaScript實現(xiàn)</B>
在JavaScript中實現(xiàn)使用MD5加密的登錄方案是比較容易的。Paul Johnston 的站點為您提供了MD5算法實現(xiàn)的豐富資料。其它有關MD5的信息可以在此站點中找到。請將代碼 拷貝至一個文本文件,并命名為md5-js.txt。
我們將在ASP環(huán)境下完成服務器端的腳本編寫(因為ASP支持JScript——微軟版的JavaScript)。你可以使用任何一種服務器端腳本編寫語言,但是你必須把MD5算法翻譯成你所選擇的語言。
以下內(nèi)容就是一個在ASP環(huán)境下實現(xiàn)的登錄表格login.asp。你可以進行在線模擬登錄模擬用戶名為jason, 用戶口令為f2#5%rsq。
<%@ LANGUAGE = "JScript" %>
<HTML>
<HEAD>
<TITLE>Please log in!</TITLE>
<% Session("sharedValue") = Math.random().toString() %>
<SCRIPT LANGUAGE="JavaScript" SRC="md5.js"></SCRIPT>
<SCRIPT LANGUAGE="JavaScript">
var sharedValue = "<% =Session("sharedValue") %>"
function handleLogin() {
sendMD5Value(calculateMD5Value())
}
function calculateMD5Value() {
var pw = document.forms["login"].elements["password"].value
pw += sharedValue
return calcMD5(pw)
}
function sendMD5Value(hash) {
document.forms["login"].elements["password"].value = hash
document.forms["login"].submit()
}
</SCRIPT>
</HEAD>
<BODY>
<FORM NAME="login" METHOD="POST" ACTION="checkpassword.asp">
User ID: <INPUT TYPE="TEXT" NAME="userid" SIZE="40"><BR>
Password: <INPUT TYPE="PASSWORD" NAME="password" SIZE="40"><BR>
<INPUT TYPE="BUTTON" NAME="startLogin" VALUE="Login" onClick="handleLogin()">
</FORM>
</BODY>
</HTML>
以上內(nèi)容中只有三行包含ASP腳本。(在<%和%>之間的內(nèi)容為ASP腳本。)文件的第一行把ASP語言確定為JScript 。
<%@ LANGUAGE = "JScript" %>
在第二行ASP中,名為“sharedValue”的服務器端會話變量的值被設置成隨機浮點數(shù)的字符串表示形式“String”。在用戶會話的全過程中,這個會話變量會存在于服務器中。
<% Session("sharedValue") = Math.random().toString() %>
下面一行將名為“sharedValue”的用戶端JavaScript變量設置為同名的服務器端變量的值。
var sharedValue = "<% =Session("sharedValue") %>"
用戶在表格中輸入他的用戶名和口令,并點擊“登錄”鍵,這樣就會激活handlelogin()函數(shù)。handlelogin()函數(shù)啟動calculateMD5Value()函數(shù),為用戶口令附加隨機值并計算出相應的MD5值。接著,sendMD5Value()函數(shù)會收取這個值,并以之替換原表格中所填寫的用戶口令,最后提交表格。
這里有一點應注意:單獨一行的SCRIPT標記表示腳本中包含md5.js文件。以上就是MD5的實現(xiàn),你可以(而且應該)從Paul Johnston的站點上拷貝此算法。calculateMD5Value()函數(shù)所使用的calcMD5()函數(shù)在md5.js中有詳細定義。
在服務器一方,我們使用一個名為checkpassword.asp的ASP腳本對用戶名 和MD5值進行確認。此腳本內(nèi)容如下:
<%@ LANGUAGE = "JScript" %>
<!--#include file ="md5.inc"-->
<%
function calculateMD5Value() {
var pw = "" + Application(Request.Form("userid"))
pw += Session("sharedValue")
return calcMD5(""+pw)
}
clientPassword = Request.Form("password")
serverPassword = calculateMD5Value()
if(clientPassword == serverPassword) Response.Redirect("page1.htm")
else Response.Redirect("tryagain.htm")
%>
下面一行表示在checkpassword.asp腳本中包含文件md5.inc(在服務器端):
<!--#include file ="md5.inc"-->
這個文件就是處在ASP的<% 和 %>標記之間的文件md5.js。標準ASP語言都帶inc.后綴。
另一個服務器端腳本描述了calculateMD5Value()函數(shù)。字段Request.Form("userid")把用戶在提交表格時所輸入的用戶名返回。通過返回的用戶名在一個應用變量中找到真正的用戶口令值。(如果你打算使用ASP,你可能希望使用另一種辦法,讓腳本可以通過其它方式獲取口令。)使用pw變量儲存用戶口令。從會話變量中取回發(fā)送給用戶的原始隨機值,并附加到用戶口令上。然后,函數(shù)對附加了隨機值的用戶口令進行計算并將所得結(jié)果返回。
function calculateMD5Value() {
var pw = "" + Application(Request.Form("userid"))
pw += Session("sharedValue")
return calcMD5(""+pw)
}
用戶身份認證這一過程的核心部分是由四行代碼來執(zhí)行完成,這四行代碼均使用calculateMD5Value()函數(shù)。由用戶提交的MD5口令被劃為“客戶口令”(clientPassword)變量,由服務器計算得出的值被劃為“服務器口令”(serverPassword)變量。將這兩個值進行比較。如果兩值相符,那么用戶瀏覽器就會打開page1.htm,這是已寫保護的網(wǎng)絡應用的首頁。如果兩值不符,用戶瀏覽器會打開tryagain.htm,用戶被告知此次登錄失敗,需要重新登錄。
clientPassword = Request.Form("password")
serverPassword = calculateMD5Value()
if(clientPassword == serverPassword) Response.Redirect("page1.htm")
else Response.Redirect("tryagain.htm")
要制作這一腳本,只要把page1.html定義為需寫保護的Web應用的首頁。如果你不使用ASP,那么你就要把ASP代碼翻譯成在你的服務器端腳本編寫環(huán)境中所使用的語言。
------------------------------- · 相關文檔瀏覽 · --------------------------------------------------------------------- · 熱門文檔瀏覽 · -------------------------------------