Chinaunix首页 | 论坛 | 博客
  • 博客访问: 521030
  • 博文数量: 135
  • 博客积分: 3568
  • 博客等级: 中校
  • 技术积分: 1942
  • 用 户 组: 普通用户
  • 注册时间: 2006-10-19 17:52
文章分类

全部博文(135)

文章存档

2012年(29)

2011年(41)

2010年(26)

2009年(12)

2008年(9)

2007年(12)

2006年(6)

分类: 网络与安全

2011-05-10 20:12:42

最近对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观察请求信息-响应如下:
请求头:==============================
  1. GET /test/auth/basic/ HTTP/1.1
  2. Host: localhost
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-cn,zh;q=0.5
  6. Accept-Encoding: gzip,deflate
  7. Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
  8. Keep-Alive: 115
  9. Connection: keep-alive
  10. Cookie: JOSSO_REMEMBERME_josso=R%2FxwdHnP7shH%2Ftk%2FPavyCQ%3D%3D; style=null
  11. Authorization: Basic emhhbmczOjEyMzQ1Ng==
响应头:==============================
  1. HTTP/1.1 200 OK
  2. Date: Tue, 10 May 2011 11:57:34 GMT
  3. Server: Apache/2.2.17 (Win32)
  4. Last-Modified: Wed, 16 Mar 2011 13:05:52 GMT
  5. Etag: "16000000012722-48-49e99345de22a"
  6. Accept-Ranges: bytes
  7. Content-Length: 72
  8. Keep-Alive: timeout=5, max=100
  9. Connection: Keep-Alive
  10. 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观察请求信息-响应如下:
请求头:==============================
  1. GET /test/auth/digest/ HTTP/1.1
  2. Host: localhost
  3. User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Gecko/20100722 Firefox/3.6.8
  4. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  5. Accept-Language: zh-cn,zh;q=0.5
  6. Accept-Encoding: gzip,deflate
  7. Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
  8. Keep-Alive: 115
  9. Connection: keep-alive
  10. Cookie: JOSSO_REMEMBERME_josso=R%2FxwdHnP7shH%2Ftk%2FPavyCQ%3D%3D; style=null
  11. 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"
响应头:==============================
  1. HTTP/1.1 200 OK
  2. Date: Tue, 10 May 2011 11:57:48 GMT
  3. Server: Apache/2.2.17 (Win32)
  4. Authentication-Info: rspauth="5517bbc34a40766eb50310ce6051cc8e", cnonce="082c875dcb2ca740", nc=00000001, qop=auth
  5. Last-Modified: Wed, 16 Mar 2011 13:06:08 GMT
  6. Etag: "1f000000009a66-4a-49e99355464e1"
  7. Accept-Ranges: bytes
  8. Content-Length: 74
  9. Keep-Alive: timeout=5, max=99
  10. Connection: Keep-Alive
  11. Content-Type: text/html



补充:如何通过Ajax用两种方式后台登录呢?
创建测试页面${DocumentRoot}/test/auth/index.html ,尝试使用2个按钮分别获取不同的内容
  1. <html>
  2. <head>
  3. <script type="text/javascript" language="javascript" src="prototype.js"></script>
  4. <script type="text/javascript" language="javascript" src="base64.js"></script>
  5. <script type="text/javascript" language="javascript">

  6. // 注意:目录要以斜杠结尾,否则会因为301跳转而丢失自定义的Header信息,造成认证失败
  7. function testBasicAuth (){
  8.   new Ajax.Request('basic/', {
  9.     method:"get",
  10.     requestHeaders:{
  11.       "Authorization":"Basic "+Base64.encode("zhang3:123456")
  12.     },
  13.     onFailure:function(transport){
  14.       alert("Failure - \n"+transport.toJSON());
  15.     },
  16.     onSuccess:function(transport){
  17.       alert("Success - \n"+transport.responseText);
  18.     }
  19.   });
  20. };

  21. function testDigestAuth (){
  22.   new Ajax.Request('digest/', {
  23.     method:"get",
  24.     requestHeaders:{
  25.       //"Authorization":"Basic "+Base64.encode("zhang3:123456") // 很复杂的
  26.     },
  27.     onFailure:function(transport){
  28.       alert("Failure - \n"+transport.toJSON());
  29.     },
  30.     onSuccess:function(transport){
  31.       alert("Success - \n"+transport.responseText);
  32.     },
  33.     // 401回调函数的执行是出现在浏览器的用户名、密码弹出窗口之后,
  34.     // 因此无意义,也做不到通过JavaScript完成完整的摘要认证流程。
  35.     on401:function(transport){
  36.      alert("401 - \n"+transport.responseText);
  37.     }
  38.   });
  39. };
  40. </script>
  41. </head>
  42. <body><h1>Digest auth~</h1>
  43. <p>
  44. Test HTTP Basic && Digest Authentacate.<br>
  45. <input type="button" onclick="testBasicAuth();" value="Basic Auth" />
  46. <input type="button" onclick="testDigestAuth();alert(9);" value="Digest Auth" />
  47. <div id="log"></div>
  48. </p>
  49. </body>
  50. </html>
结论:
  由于Basic认证比较简单,虽说可以通过Javascript完成,但是不安全,还是不用的为好。
  而Digest认证则要复杂,与服务器交互的时候,需要先从服务器获取一个高度随机的nonce字符串,然后在使用用户名、密码按照约定的摘要方式计算摘要值,然后再携带摘要值完成认证。而且IE6 , 火狐3.5目前都会自己弹出要求用户手动输入用户名、密码的小弹出窗口(后台Ajax也会弹),目前尚未找到能通过JavaScript禁止弹出此窗口的方法(就算能,那后面也需要通过JavaScript实现一套完成的HTTP 摘要认证框架了,且不说性能如何,光实现起来就很复杂的)
  因此,个人觉得最好的登录方式可以以Google的登录为例:
  通过HTTPS载入登录的表单页面,然后通过HTML的FORM构建用户登录UI,然后提交到后台完成登录。然后再根据将这个简单的登录画面作为SSO的登录方式即可。

最好是通过HTTPS + 一个单独的登录页面通过Cookie做到SSO。


阅读(2640) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~