经常有读者询问,如何在其站点上使用javascript,以确保用户登录时的口令不会外泄。对于这样的问题,我的第一反应就是告诉他们使用ssl(安全套接字协议层)。如使用正确,ssl对于安全要求较高的web应用是最佳的解决方案。但是,也有相当一部分开发者,他们的web应用对安全性的要求并不高,因此他们并不希望访问者使用ssl 登录。
web应用一般使用一种叫做“会话状态管理”(session state management) 的技术来追踪和管理浏览器与服务器之间的相互活动。因为每个浏览器的浏览要求相对于其他浏览器都是独立的(正如超文本传输协议中定义的那样),所以web 应用必然使用某些技巧,如cookie、隐藏表格字段、或重写url,它们可以识别出服务器与某个浏览器进行的独立会话。大多数的服务器端编程环境(如asp、php、coldfusion等)都使用cookie。
会话状态管理的问题在于从根本上讲它是不安全的。这些被用来管理会话状态的cookie、表单值、或url要在浏览器和服务器之间往来传送,黑客可以在途中拦截它们。一旦拦截成功,黑客就可以利用这些信息强行接管用户会话。
在大多数服务器端脚本编写环境里,你都可以采取一些措施以减少此类泄密的发生。例如,你可以为cookie设定很短的使用期限,应用“难预期会话状态”信息。然而,最安全的解决方案还是使用ssl。使用ssl,不论用户口令,还是会话状态信息都会受到保护。
如果你不使用ssl,那么可以要求用户对你的应用中的每个敏感页进行重新认证。但是,从用户的角度来讲,这种方式未免太过麻烦。总之,你必须清楚你和你的用户究竟愿意承担多高的风险。如果口令泄露的风险过高,你就需要使用ssl建立应用。如果你不能使用ssl,可以采用基于md5的登录方式作为代替。它至少可以保护你的用户的口令免于外泄。另外,再选用一种可以防止会话状态信息被窃的服务器端脚本编写技术。
通常,如果一个用户不使用ssl登录(即原来的http),那么从离开浏览器直到到达目标网络服务器的这段时间里,用户口令都处于无保护的暴露状态,正如下页中的图表所示。
不过,我们可以利用一种不可逆的函数开发一种登录方案,利用这种方案就不会暴露用户的口令。函数是集合的元素之间的一种对应关系,在从集合a到集合b的函数中,a中每个元素在b中都有一个唯一的元素与之相对应。不可逆函数在计算上很难逆转——即给定集合b中的一个元素,很难确定在集合a中的哪个元素与之相对应。
这好比是一台碎纸机。把文件放入碎纸机中销毁是很容易的。但是反之,如果要把销毁后的碎纸屑重新拼凑成原文可就难上加难了。
<b>采用md5解决方案<b>
当今最流行的不可逆函数应用程序之一就是由ronald rivest开发的md5算法。ronald rivest还是著名的rsa(rivest,shamir,adelman)加密算法的开发者之一。md5算法能为任何长度的信息生成一个16字节大小的“数字指纹”。这个信息可以是一个字符串、一个文件、一个文本流或任何其它形式的字节序列。在rfc1321中有md5算法的详细描述。
我们要开发一种使用md5算法的登录方式,用以保护从一个浏览器发送至网络服务器的用户口令。
当一名用户对某个网络应用提出登录请求时,其网络服务器就会提供给用户一个登录表格。这是一个带有随机生成值的表格。其中的随机生成值由服务器端脚本从一个数亿记的取值空间中随机选取生成。
<img src="/uploadfiles/newsphoto/esastep1.gif">
用户在登录表格中输入他或她的用户名和口令,用户端脚本给口令附加一个随机值,然后用md5不可逆算法对结果进行计算。再用计算得出的值代替原口令。我把这个值称为md5口令。
最后,用户端脚本把用户名和这个md5口令发送到网络服务器。因为在浏览器与服务器之间传送的是md5的运算结果,所以任何人都无法通过计算得出用户所输入的原始口令。
<img src="/uploadfiles/newsphoto/esastep2.gif">
网络服务器在接收用户名和md5口令后,会执行与用户浏览器相同的运算。它给用户口令(从服务器的被保护区域中提取)附加上随机值(即已发送给用户的随机值),并计算出正确的md5口令值。然后网络应用程序把这个值和它从浏览器收取的值相比较。如果两值相等,网络应用程序就会生成一个服务器端会话变量,证明此用户身份正确。
<img src="/uploadfiles/newsphoto/esastep3.gif">
说到这里,你也许会置疑使用随机值的必要性。其实,这个随机值是用来防止再度攻击的。如果只有原始用户口令通过md5,那么相应得出的md5口令就会总是同一个值。黑客只要截获md5口令就同样可以登录进入网络应用。使用了随机值后,每次登录时生成的md5口令都是唯一的,这样就避免了上述问题的出现。
<b>javascript实现</b>
在javascript中实现使用md5加密的登录方案是比较容易的。paul johnston 的站点为您提供了md5算法实现的丰富资料。其它有关md5的信息可以在此站点中找到。请将代码 拷贝至一个文本文件,并命名为md5-js.txt。
我们将在asp环境下完成服务器端的脚本编写(因为asp支持jscript——微软版的javascript)。你可以使用任何一种服务器端脚本编写语言,但是你必须把md5算法翻译成你所选择的语言。
以下内容就是一个在asp环境下实现的登录表格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>
以上内容中只有三行包含asp脚本。(在<%和%>之间的内容为asp脚本。)文件的第一行把asp语言确定为jscript 。
<%@ language = "jscript" %>
在第二行asp中,名为“sharedvalue”的服务器端会话变量的值被设置成随机浮点数的字符串表示形式“string”。在用户会话的全过程中,这个会话变量会存在于服务器中。
<% session("sharedvalue") = math.random().tostring() %>
下面一行将名为“sharedvalue”的用户端javascript变量设置为同名的服务器端变量的值。
var sharedvalue = "<% =session("sharedvalue") %>"
用户在表格中输入他的用户名和口令,并点击“登录”键,这样就会激活handlelogin()函数。handlelogin()函数启动calculatemd5value()函数,为用户口令附加随机值并计算出相应的md5值。接着,sendmd5value()函数会收取这个值,并以之替换原表格中所填写的用户口令,最后提交表格。
这里有一点应注意:单独一行的script标记表示脚本中包含md5.js文件。以上就是md5的实现,你可以(而且应该)从paul johnston的站点上拷贝此算法。calculatemd5value()函数所使用的calcmd5()函数在md5.js中有详细定义。
在服务器一方,我们使用一个名为checkpassword.asp的asp脚本对用户名 和md5值进行确认。此脚本内容如下:
<%@ 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()函数。字段request.form("userid")把用户在提交表格时所输入的用户名返回。通过返回的用户名在一个应用变量中找到真正的用户口令值。(如果你打算使用asp,你可能希望使用另一种办法,让脚本可以通过其它方式获取口令。)使用pw变量储存用户口令。从会话变量中取回发送给用户的原始随机值,并附加到用户口令上。然后,函数对附加了随机值的用户口令进行计算并将所得结果返回。
function calculatemd5value() {
var pw = "" + application(request.form("userid"))
pw += session("sharedvalue")
return calcmd5(""+pw)
}
用户身份认证这一过程的核心部分是由四行代码来执行完成,这四行代码均使用calculatemd5value()函数。由用户提交的md5口令被划为“客户口令”(clientpassword)变量,由服务器计算得出的值被划为“服务器口令”(serverpassword)变量。将这两个值进行比较。如果两值相符,那么用户浏览器就会打开page1.htm,这是已写保护的网络应用的首页。如果两值不符,用户浏览器会打开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代码翻译成在你的服务器端脚本编写环境中所使用的语言。
作者blog:_articlecontent1_authorbloglink href="http://blog.csdn.net/zdg/" target=_blank>http://blog.csdn.net/zdg/
