最近对RESTful Web Service有点兴趣,但是对于其安全性的了解现在只能参考到使用HTTP协议中规定的两种认证方式 Basic 认证和 Digest认证。当然HTTP协议里貌似新追加了一个OAuth协议。但是前两者属于认证(Authentication),而后者貌似属于授权(Authorization)。先用老牌的Web服务器 ——Apache搭建一个简单的测试例子,以对他们有些直观的了解吧。
写在前面:网上例子不少哦,而且网上也有翻译的Apache HTTP Server的中文文档。大家可以多百度下哈~。
查找一些资料的时候,看到了某人的博客的签名:“纸上得来终觉浅,绝知此事要躬行”,呵呵,偶也那么实践一把吧~~~
Auth_test_Apache2.2.zip 前提:
安装 Apache:
本文基于Apache 2.2 Windows版的全新默认安装。
安装路径为:C:/Program Files/Apache Software Foundation/Apache2.2/
配置环境变量:
并且将以下路径追加到环境变量PATH下:
C:/Program Files/Apache Software Foundation/Apache2.2/bin
测试设计:
假设要在以下目录中设置权限认证:
${DocumentRoot}/test/auth/basic/ -- HTTP Basic 认证
${DocumentRoot}/test/auth/digest/ -- HTTP Digest 认证
1. 首先创建上述目录,并分别创建一个测试index.html页面。
比如在 ${DocumentRoot}/test/auth/basic/index.html 中写入 “HTTP basic authenticated page.”
在 ${DocumentRoot}/test/auth/digest/index.html 中写入 “HTTP digest authenticated page.”
2. 修改 ${HTTPD_HOME}/conf/httpd.conf
(1) 允许Apache使用对test目录使用 .htaccess 文件
Options All
AllowOverride AuthConfig
(2) 默认是仅支持HTTP Basic认证,但不支持HTTP Digest认证。
所以确保以下一行未被注释以支持HTTP Digest认证:
LoadModule auth_digest_module modules/mod_auth_digest.so
3. 配置并测试HTTP Basic认证
3.1 创建密码文件:(最后一个参数是用户名,每个命令之后要为其输入密码,这里全部为“123456”)
CMD/> htpasswd -c C:/passwords zhang3
CMD/> htpasswd C:/passwords li4
CMD/> htpasswd C:/passwords wang5
3.2 如果你想使用用户组来进行认证的话,可以继续创建一个纯文本文件
内容格式为:
组名: 成员名1 成员名2 ...
这里的示例文件为:C:/groups.txt
内容为:
testGroup: li4
3.3 配置 ${DocumentRoot}/test/auth/basic/.htaccess文件
AuthType Basic
AuthName "Test Basic Auth"
AuthUserFile C:/passwords
AuthGroupFile C:/groups.txt
# 只能使用一个 group / user,貌似
#Require group testGroup
Require user zhang3
3.4 测试
在浏览器中的地址栏中输入:
输入用户名 “zhang3”, 密码:“123456”
通过Firefox的FireBug观察请求信息-响应如下:
请求头:==============================
- GET /test/auth/basic/ HTTP/1.1
-
Host: localhost
-
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
-
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-
Accept-Language: zh-cn,zh;q=0.5
-
Accept-Encoding: gzip,deflate
-
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
-
Keep-Alive: 115
-
Connection: keep-alive
-
Cookie: JOSSO_REMEMBERME_josso=R%2FxwdHnP7shH%2Ftk%2FPavyCQ%3D%3D; style=null
-
Authorization: Basic emhhbmczOjEyMzQ1Ng==
响应头:==============================
- HTTP/1.1 200 OK
-
Date: Tue, 10 May 2011 11:57:34 GMT
-
Server: Apache/2.2.17 (Win32)
-
Last-Modified: Wed, 16 Mar 2011 13:05:52 GMT
-
Etag: "16000000012722-48-49e99345de22a"
-
Accept-Ranges: bytes
-
Content-Length: 72
-
Keep-Alive: timeout=5, max=100
-
Connection: Keep-Alive
-
Content-Type: text/html
4. 配置并测试HTTP Digest认证
4.1 创建密码摘要文件:(最后一个参数是用户名,每个命令之后要为其输入密码,这里全部为“123456”)
CMD/> htdigest -c C:/users_digest "Test Digest Auth" zhang3
CMD/> htdigest C:/users_digest "Test Digest Auth" li4
CMD/> htdigest C:/users_digest "Test Digest Auth" wang5
4.2 配置 ${DocumentRoot}/test/auth/digest/.htaccess文件
AuthType Digest
AuthName "Test Digest Auth"
#AuthDigestDomain /test/auth/digest
#摘要算法允许为 MD5/MD5-sess,但是MD5-sess尚未实现
#AuthDigestAlgorithm MD5
AuthDigestProvider file
AuthUserFile C:/users_digest
#Require zhang3
Require valid-user
# IE6对摘要认证的算法有问题,可以使用以下方式解决,且不会对IE7有影响
BrowserMatch "MSIE" AuthDigestEnableQueryStringHack=On
4.3 测试
在浏览器中的地址栏中输入:
/
输入用户名 “zhang3”, 密码:“123456”
通过Firefox的FireBug观察请求信息-响应如下:
请求头:==============================
- GET /test/auth/digest/ HTTP/1.1
-
Host: localhost
-
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
-
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
-
Accept-Language: zh-cn,zh;q=0.5
-
Accept-Encoding: gzip,deflate
-
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
-
Keep-Alive: 115
-
Connection: keep-alive
-
Cookie: JOSSO_REMEMBERME_josso=R%2FxwdHnP7shH%2Ftk%2FPavyCQ%3D%3D; style=null
-
Authorization: Digest username="zhang3", realm="Test Digest Auth", nonce="FLX8qeqiBAA=fbdd6903d69d19f24796c57df9eefbb2cf91c1f7", uri="/test/auth/digest/", algorithm=MD5, response="5bab9d5fd9b892f6a8d03a7e92481115", qop=auth, nc=00000001, cnonce="082c875dcb2ca740"
响应头:==============================
- HTTP/1.1 200 OK
-
Date: Tue, 10 May 2011 11:57:48 GMT
-
Server: Apache/2.2.17 (Win32)
-
Authentication-Info: rspauth="5517bbc34a40766eb50310ce6051cc8e", cnonce="082c875dcb2ca740", nc=00000001, qop=auth
-
Last-Modified: Wed, 16 Mar 2011 13:06:08 GMT
-
Etag: "1f000000009a66-4a-49e99355464e1"
-
Accept-Ranges: bytes
-
Content-Length: 74
-
Keep-Alive: timeout=5, max=99
-
Connection: Keep-Alive
-
Content-Type: text/html
补充:如何通过Ajax用两种方式后台登录呢?
创建测试页面${DocumentRoot}/test/auth/index.html ,尝试使用2个按钮分别获取不同的内容
- <html>
-
<head>
-
<script type="text/javascript" language="javascript" src="prototype.js"></script>
-
<script type="text/javascript" language="javascript" src="base64.js"></script>
-
<script type="text/javascript" language="javascript">
-
-
// 注意:目录要以斜杠结尾,否则会因为301跳转而丢失自定义的Header信息,造成认证失败
-
function testBasicAuth (){
-
new Ajax.Request('basic/', {
-
method:"get",
-
requestHeaders:{
-
"Authorization":"Basic "+Base64.encode("zhang3:123456")
-
},
-
onFailure:function(transport){
-
alert("Failure - \n"+transport.toJSON());
-
},
-
onSuccess:function(transport){
-
alert("Success - \n"+transport.responseText);
-
}
-
});
-
};
-
-
function testDigestAuth (){
-
new Ajax.Request('digest/', {
-
method:"get",
-
requestHeaders:{
-
//"Authorization":"Basic "+Base64.encode("zhang3:123456") // 很复杂的
-
},
-
onFailure:function(transport){
-
alert("Failure - \n"+transport.toJSON());
-
},
-
onSuccess:function(transport){
-
alert("Success - \n"+transport.responseText);
-
},
-
// 401回调函数的执行是出现在浏览器的用户名、密码弹出窗口之后,
-
// 因此无意义,也做不到通过JavaScript完成完整的摘要认证流程。
-
on401:function(transport){
-
alert("401 - \n"+transport.responseText);
-
}
-
});
-
};
-
</script>
-
</head>
-
<body><h1>Digest auth~</h1>
-
<p>
-
Test HTTP Basic && Digest Authentacate.<br>
-
<input type="button" onclick="testBasicAuth();" value="Basic Auth" />
-
<input type="button" onclick="testDigestAuth();alert(9);" value="Digest Auth" />
-
<div id="log"></div>
-
</p>
-
</body>
-
</html>
结论:
由于Basic认证比较简单,虽说可以通过Javascript完成,但是不安全,还是不用的为好。
而Digest认证则要复杂,与服务器交互的时候,需要先从服务器获取一个高度随机的nonce字符串,然后在使用用户名、密码按照约定的摘要方式计算摘要值,然后再携带摘要值完成认证。而且IE6 , 火狐3.5目前都会自己弹出要求用户手动输入用户名、密码的小弹出窗口(后台Ajax也会弹),目前尚未找到能通过JavaScript禁止弹出此窗口的方法(就算能,那后面也需要通过JavaScript实现一套完成的HTTP 摘要认证框架了,且不说性能如何,光实现起来就很复杂的)
因此,个人觉得最好的登录方式可以以Google的登录为例:
通过HTTPS载入登录的表单页面,然后通过HTML的FORM构建用户登录UI,然后提交到后台完成登录。然后再根据将这个简单的登录画面作为SSO的登录方式即可。
最好是通过HTTPS + 一个单独的登录页面通过Cookie做到SSO。
阅读(2688) | 评论(0) | 转发(0) |