A1-注入
A2-跨站脚本(XSS)
A3-错误的认证和会话管理
A4-不正确的直接对象引用
A5-伪造跨站请求(CSRF) -- Cross-Site Request Forgery
A7-限制远程访问失败
A8-未验证的重定向和传递
A9-不安全的加密存储
A10-不足的传输层保护
OWASP TOP10排名第3的威胁“遭破坏的认证和会话管理”,简而言之,就是攻击者窃听了我们访问HTTP时的用户名和密码,或者是我们的会话,从而得到sessionID,进而冒充用户进行Http访问的过程。
由于HTTP本身是无状态的,也就是说HTTP的每次访问请求都是带有个人凭证的,而SessionID就是为了跟踪状态的,而sessionID本身是很容易在网络上被监听的到,所以攻击者往往通过监听sessionID来达到进一步攻击的目的。
这些漏洞往往会存在于Web页面的“更改我的密码”、“记住我的密码”、“忘记密码”、“安全提问”、“注销登录”、“邮件地址”等环节上。
那么,一般来说,如何来防范这种漏洞呢?
第一, 我们要整体审视我们的架构
l 认证机制本身必须是简单、集中和标准化的;
l 使用容器提供给我们的标准session id;
l 确保在任何时候用SSL来保护我们的密码和session id
第二, 验证认证的实现机制
l 检查SSL的实现方法
l 验证所有与认证相关的函数
l 确保“注销登录”的动作能够关闭所有的会话
l 使用OWASP的WebScrab来测试你的应用
所谓认证,就是建立确信某物或某人是真实的这么一个过程,authentication来自于希腊语αυθεντικός,即真实的,可信的。认证本身依赖于多个认证因子,在计算机安全领域,认证意味着验证通讯发起者的数字身份,常见的认证过程就是用户登录认证,所谓认证测试就是理解系统中的认证机制并找到方法绕过该认证机制。
认证测试需要考虑的点有很多,下面我们逐一来进行解释说明
l 在加密通道上传递密码
原则上,用户的认证必须通过加密信道进行传输,我们在这里的目的不是要验证诸如HTTPS是否安全,我们要验证的仅仅是用户的认证信息是否已经被加密了。
在用户登录时,最常见的方式是用户输入用户名和密码后,通过POST方法传输,一般来说,认证信息或者是通过不安全的HTTP传递,或者是通过加密的HTTPS传递。我们注意到,甚至有些网站在登录页面显示给我们的是HTTPS,但事实上却仍然是用HTTP的,最简单的方法就是用网络监听工具,如SnifferPro或Ethereal来判断是否是真实加密了。
下面,我们用OWASP的WebScrab截取一些信息来做个例子
假设,登录页面要求用户输入用户名和密码,然后有一个“提交”按钮,那么在WebScrab中我们得到如下的请求数据:
POST http://www.example.com/AuthenticationServlet HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.14) Gecko/20080404
Accept: text/xml,application/xml,application/xhtml+xml
Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.example.com/index.jsp
Cookie: JSESSIONID=LVrRRQQXgwyWpW7QMnS49vtW1yBdqn98CGlkP4jTvVCGdyPkmn3S!
Content-Type: application/x-www-form-urlencoded
Content-length: 64
delegated_service=218&User=test&Pass=test&Submit=SUBMIT
在上面的数据中,我们可以看到,POST方法通过HTTP协议把数据发送到http://www.example.com/AuthenticationServlet,那么显然在这时,传送的数据没有进行加密,恶意用户通过监听网络就很容易得到用户名和密码。
再看下一个例子,假设是用HTTPS协议,那么请求的头数据如下:
POST https://www.example.com:443/cgi-bin/login.cgi HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.14) Gecko/20080404
Accept: text/xml,application/xml,application/xhtml+xml,text/html
Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: https://www.example.com/cgi-bin/login.cgi
Cookie: language=English;
Content-Type: application/x-www-form-urlencoded
Content-length: 50
Command=Login&User=test&Pass=test
可见,上述例子中的数据经加密后被传送到https://www.example.com:443/cgi-bin/login.cgi,这就确保了数据是加密的而不被其他人所窃取。
再看下面的一个例子,我们在一个可以通过HTTP协议访问到的页面上通过HTTPS协议来发送数据
POST https://www.example.com:443/login.do HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.14) Gecko/20080404
Accept: text/xml,application/xml,application/xhtml+xml,text/html
Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.example.com/homepage.do
Cookie: SERVTIMSESSIONID=s2JyLkvDJ9ZhX3yr5BJ3DFLkdphH0QNSJ3VQB6pLhjkW6F
Content-Type: application/x-www-form-urlencoded
Content-length: 45
User=test&Pass=test&portal=ExamplePortal
如上,我们看到,我们的请求通过HTTPS引向了https://www.example.com:443/login.do,但如果我们再看Referer的值,就发现我们是从HTTP页http://www.example.com/homepage.do过来的。在这种情况下,我们的浏览器窗口中并不会告诉我们现在使用的安全连接,而事实上我们却正在使用安全连接。
在上面的例子中,如果我们用Get方法,那么所输入的用户名和密码将会以明文的方式显示在URL中,这显然是不可取的。那么,如果我们经由Get方法通过HTTPS来传递数据是否可行呢,看下面的数据
GET https://www.example.com/success.html?user=test&pass=test HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; it; rv:1.8.1.14) Gecko/20080404
Accept: text/xml,application/xml,application/xhtml+xml,text/html
Accept-Language: it-it,it;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: https://www.example.com/form.html
If-Modified-Since: Mon, 30 Jun 2008 07:55:11 GMT
If-None-Match: "43a01-5b-4868915f"
从上面的例子可以看到,用户名和密码都以明文的方式在URL里存在,而不像上面的几个例子中都在消息体中,但并不是说攻击者就可以很容易看到这些信息,TLS/SSL毕竟是安全性很高的协议,整个HTTP数据包是加密的,但仍然要注意的是这些用户名和密码在传输过程中会被存储在代理和服务器上,这也就有可能会泄露用户信息。
用户列举测试法
这种测试,简而言之是通过与应用的认证机制的交互,尝试能否获得一些正确的用户名,这对后面我们会讲到的暴力破解很有效,确认了正确的用户名就能用暴力破解去尝试密码了。
通常,WEB应用对于用户名正确的输入会有一些信息反馈,例如,如果我们输错了密码,那么有时会反馈告知我们系统存在该用户,或密码错误。所以,作为测试人员,就要尝试不同的请求来判断系统是否会有不同的返回。
对于HTTP的响应消息测试:
输入正确的用户名和密码
期望结果:使用WebScrab抓取服务器的返回信息(HTTP 200 Response,消息的长度)
输入正确的用户名/错误的密码
期望结果:从浏览器我们往往会得到如下的返回
或者是如下返回
甚至是如下的返回
Login for User foo: invalid password
输入不存在的用户名
期望结果:返回可能如下
或者是如下的消息
Login failed for User foo: invalid Account
通常情况下,对于不同的出错信息,服务器往往返回的消息是一样的,但如果不同,测试人员就要去尝试在什么情况下不同,如下:
客户请求:正确用户/错误密码——>服务器返回:密码错误
客户请求:错误用户/错误密码——>服务器返回:用户不存在。
那么显然第一条就告诉我们我们输入的是正确的用户名,通过这种方式我们就可以获得一些正确的用户名信息。
还有其他一些尝试列举的方法:
有些应用程序会返回一些特定的出错信息;
分析URL以及重定向URL
如下面的URL:
http://www.foo.com/err.jsp?User=baduser&Error=0
http://www.foo.com/err.jsp?User=gooduser&Error=2
上面两个URL都告诉我们到了错误页面,但上一条是Error值为0,下一条Error值为2,那么我们可以猜测我们获得了一个正确的用户名。
URI探测
有时候,Web服务器在接受一个对目录访问请求时,根据目录是否存在会有不同的返回信息,例如在某些网站会给每个用户设定一个目录,那么我们如果尝试访问某个已存在的目录时,它可能的返回页面如下:
403 Forbidden error code
404 Not found error code
举例:
http://www.foo.com/account1-返回的出错信息: 403 Forbidden
http://www.foo.com/account2-返回的出错信息: 404 file Not Found
那么显然,account1是现实存在的。
l 探测性用户账户测试法
众所周知,在系统中往往会有默认账户或者很容易被猜到的常用账户,而且往往很多用户会使用默认的密码,同样,有些应用系统的测试账户研发人员有时也会忘记删除。这个问题事实上是一个漏洞,而这种漏洞往往是由于以下原因造成的:
没有经验的IT工程师,他们往往不会更改安装的架构组件的缺省密码;
编程人员在应用中留有后门以便测试,但在发布时忘记删除;
系统的管理员和用户采用了很简单的密码;
系统有内嵌的,无法删除的内部用户名和密码
……
对于注入Cisco路由器或WebLogic等,他们都有一些默认的用户名和密码,我们可以直接尝试,对于一些我们根本不了解的应用,我们可以做如下尝试:
尝试以下系统管理员的常用账号——"admin", "administrator", "root", "system", "guest", "operator", "super","qa", "test", "test1", "testing",针对用户名和密码组合尝试,也可以尝试诸如"password", "pass123", "password123", "admin",或guest"这些密码。如果这些都无法成功,我们可以写一些脚本来尝试类似的用户名和密码组合。
管理员的密码有时会与系统名字相关,如我们测试的应用系统叫“Obscurity”,那么可以尝试用户名/密码组合Obscurity/obscurity。
利用注册页面我们也可以猜测用户名和密码的格式和长度。
尝试上述提到的所有用户名和空密码。
查看页面的源文件,尝试找到所有引用到用户名和密码的信息,比如"If username='admin' then starturl=/admin.asp else /index.asp"
寻找那些源文件中注释中可能含有的用户名和密码信息;
…….
l 强力测试(暴力测试)
任何一种技术,在不同的人手里运用所达到的效果是不同的,正如暴力测试,也叫暴力破解,安全服务人员和测试人员利用这种技术来验证是否存在漏洞,而攻击者则利用其来寻找漏洞。
Web应用系统通常会有一些用户认证方式,这些方式包括证书、指纹、一次性令牌等等,但更多的,往往是用户名和密码的组合,这就使得暴力破解成为可能。
在对Web应用系统做暴力测试时,首先我们需要了解的是系统的认证机制,通常Web系统会采用以下两种机制:
HTTP认证——包含基本存取认证和数字存取认证。
基于HTML表单的认证。
我们下面对这些认证方式做一下简单介绍:
基本存取认证
基本存取认证假设假定用户会以用户名和密码的组合来表明自己的身份,当用户浏览器使用这种机制访问站点时,web服务器将会返回一个包含“WWW-Authenticate”头的401响应,且包含了一个“Basic”值,以及被保护的域名(例如,WWW-Authenticate: Basic realm=”wwwProtectedSite”)客户端会弹出一个需要用户输入该域用户名和密码的提示框。然后,客户端浏览器返回给服务器一个响应,响应包含“Authorization”头,还包含“Basic”值以及连接了用户名,冒号,密码的基于64位的编码(例如,Authorization: Basic b3dhc3A6cGFzc3dvcmQ=),但可惜的是,这个回复只要被攻击者监听到就很容易被解码。
我们来看一下这个过程:
1.客户端发送一个标准的HTTP请求
GET /members/docs/file.pdf HTTP/1.1
Host: target
2. web服务器定位到访问的这个资源是在一个受保护的目录;
3.服务器发送一个HTTP 401的认证请求;
HTTP/1.1 401 Authorization Required
Date: Sat, 04 Nov 2006 12:52:40 GMT
WWW-Authenticate: Basic realm="User Realm"
Content-Length: 401
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1
4.浏览器弹出要求输入用户名和密码的数据窗口;
5.用户输入用户名和密码后,包含以下数据后再次提交;
GET /members/docs/file.pdf HTTP/1.1
Host: target
Authorization: Basic b3dhc3A6cGFzc3dvcmQ=
6.服务器把客户信息和存储的信息进行比较;
7.如果身份验证正确,服务器发回被请求的内容,如果失败,服务器将会返回HTTP
www.owasp.org_Image-basm-sessid.jpg_Basm-sessid
www.owasp.org_Image-basm-sessid2.jpg_Basm-sessid2