Web应用安全测试-权限篡改
任意用户密码修改/重置
++漏洞描述:++
可通过篡改用户名或ID、暴力破解验证码等方式修改/重置任意账户的密码。
++测试方法:++
密码修改的步骤一般是先校验用户原始密码是否正确,再让用户输入新密码。修改密码机制绕过方式大概有以下三种:
- 如果输入新密码的接口可以直接访问,那么在未知原始密码的的情况下即可直接修改密码,通常知道了他人的用户名即可任意修改他人的密码。
- 如果系统未校验修改密码的用户身份,那么在提交修改密码请求时,攻击者通过输入密码,将用户名或者用户ID修改为其他人的,即可成功修改他人的密码。
- 当修改密码时系统需要电子邮件或者手机短信确认,而应用程序未校验用户输入的邮箱和手机号,那么攻击者通过填写自己的邮箱或手机号接收修改密码的链接和验证码,以此修改他人的密码。
密码重置机制绕过攻击方式主要有以下两种:
- 通过正常手段获取重置密码的链接,猜解链接的组成结构和内容(如用户名或者时间戳的MD5值)。在得知他人邮箱的情况下,构造重置他人密码的链接。
- 在得知他人手机号的情况下,通过穷举手机验证码重置他人的密码。
++风险分析:++
密码修改功能常采用分步骤方式来实现,攻击者在未知原始密码的情况下绕过某些检验步骤修改用户密码。
重置密码过程一般是首先验证注册的邮箱或者手机号,获取重置密码的链接(一般会包含一串唯一的字符串)或者验证码,然后访问重置密码链接或者输入验证码,最后输入新密码。密码重置机制绕过攻击是指在未知他人的重置密码链接或手机验证码的情况下,通过构造重置密码链接或穷举手机验证码的方式直接重置他人的密码。
++风险等级:++
【高危】:其它用户的密码被修改/重置成功
++修复方案:++
- 一次性填写校验信息(原始密码、新密码等)后再提交修改密码请求。
- 对客户端提交的修改密码请求,应对请求的用户身份与当前登录的用户身份进行校验,判断是否有权修改用户的密码并对原始密码是否正确也进行判断。
- 不应将用于接收验证信息的手机、邮箱等信息全部明文传到客户端,应对手机、邮箱等信息进行屏蔽处理,或不将此类信息返回到客户端。
- 对原始密码进行了验证的情况下,限制输入原始密码的错误次数,防止攻击者暴力破解原始密码。
- 重置密码链接中的关键信息应随机化,不可预测(例如token机制),且禁止将关键信息返回到客户端。
**++注意事项:++**暂无
SSO认证缺陷
**++漏洞描述:++**SSO认证存在缺陷,可越权登录他人账户。
**++测试方法:++**建议从以下两个方向进行测试:
1、信息传输缺乏安全保证
SSO认证通信过程中大多数采用明文形式传送敏感信息,这些信息很容易被窃取,致使重要信息泄露。另外,在通信过程中大多数方案也没有对关键信息进行签名,容易遭到伪装攻击。
2、Web服务的安全缺陷
由于单点登录基本上是基于Web服务实现的,所以也不可避免的存在Web服务的安全缺陷,如跨站脚本攻击、越权攻击等。
**++风险分析:++**因为只需要登录一次,所有的授权的应用系统都可以访问,可能导致一些很重要的信息泄露。
++风险等级:++
【高危】:可导致用户在单点登录之后任意登录其他系统和其他用户账号信息
**++修复方案:++**建议从以下几个方面进行防御:
- 建议在不影响业务的前提下,使用HTTPS协议传输
- 严格校验SSO认证过程中的用户身份
- 过滤用户传入的参数,对特殊符号进行转义或屏蔽。
**++注意事项:++**暂无
越权
**++漏洞描述:++**越权访问,这类漏洞是指应用在检查授权(Authorization)时存在纰漏,使得攻击者在获得低权限用户帐后后,可以利用一些方式绕过权限检查,访问或者操作到原本无权访问的高权限功能。在实际的代码安全审查中,这类漏洞往往很难通过工具进行自动化检测,因此在实际应用中危害很大。其与未授权访问有一定差别。
++测试方法:++
- 以超管 admin(高权限用户) 身份登录系统
- 找到一个只有超管(高权限)才有的功能的链接,比如:"http://localhost/mywebappname/userManage/userList.do" , 显示出所有的user,并复制此链接。
- 以普通用户登录进系统,在地址栏输入: userManage/userList.do,如果可以查看到其所有的user,则就造成了,普通用户的越权访问。
- 检测说明:权限管理测试更多的是进行人工分析,自动化工具无法了解页面的具体应用场景以及逻辑判断过程。因此这里的测试需要首先测试人员理解测试业务系统的逻辑处理流程,并在此基础上进行如下测试。这里有几个测试的参考依据:
- 页面是否进行权限判断;
- 页面提交的资源标志是否与已登录的用户身份进行匹配比对;
- 用户登录后,服务器端不应再以客户端提交的用户身份信息为依据,而应以会话中保存的已登录的用户身份信息为准;
- 必须在服务器端对每个请求URL进行鉴权,而不能仅仅通过客户端的菜单屏蔽或者按钮Disable来限制。
**++风险分析:++**目前存在着两种越权操作类型:横向越权操作和纵向越权操作。前者指的是攻击者尝试访问与他拥有相同权限的用户的资源;而后者指的是一个低级别攻击者尝试访问高级别用户的资源,如图所示的情况。
++风险等级:++
【高危】:任意水平或垂直越权
**++修复方案:++**对用户操作进行权限校验,防止通过修改参数进入未授权页面及进行非法操作,建议在服务端对请求的数据和当前用户身份做校验检查。流程描述:在服务器接收到用户发送的页面访问请求时,根据预设的识别策略,从用户的页面访问请求中提取该用户对应的用户唯一标识信息,同时提取所述页面访问请求对应的应答页面中的表单及该表单中不可修改参数,将所述表单及不可修改参数与所述用户唯一标识信息绑定后记录到参数列表中;检测到用户提交请求页面的表单时,将所述请求页面的表单及不可修改参数与该用户对应的所述参数列表中记录的表单及不可修改参数进行比对,控制该用户的访问。例如:
|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 登录时将用户名存入session session.setAttribute("username",username); 在相关页面判断 if((String)session.getAttribute("username")!=admin){ (response.sendRedirect("XXX.jsp")); |
注意: xxx.jsp为自定义的错误页面
**++注意事项:++**暂无
Cookies伪造
**++漏洞描述:++**Cookie伪造攻击指攻击者通过修改cookie(Web网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密)),获得用户未授权信息,进而盗用身份的过程,攻击者利用此漏洞可打开新账号或获取用户已存在账号的访问权限。
**++测试方法:++**使用burpsuite等代理软件或浏览器Cookie修改插件,篡改Cookie信息。
**++风险分析:++**Cookie中通常使用以下几种方式来确定一个会话:
- 唯一标识ID
- 使用token
- 时间戳
攻击者可以对Cookie中的属性进行逆向分析,当Cookie中的唯一标识ID、token和时间戳可预测(如ID采用顺序增加方式,token值是用户名的MD5值)时,攻击者可通过遍历唯一标识ID、猜测token手段构造Cookie,来模拟一个有效的用户登录系统。
++风险等级:++
【高危】:伪造 cookie 后,成功进入业务系统或获取用户权限
++修复方案:++
- 服务器端在Set-Cookie时在Cookie的值后面加上一段防篡改的验证串,然后再发送到客户端,客户端得到的Cookie形如:user_name=admin|ab95ef23cc6daecc475de,用|分割的后面部分是防篡改验证串,可以使用以下方式生成:SHA1(cookie内容+密钥)、DES(cookie的内容+密钥)、MD5(cookie内容+密钥),密钥是保存在服务器端的固定字符串,应妥善保管。服务器接收到Cookie后,根据Cookie内容和密钥重新计算防篡改验证串,然后和客户端提交的防篡改验证串比较,若两者一致则认为Cookie未被篡改。
- 若使用了WebSphere中间件,通过配置LTPA认证方式可防止Cookie被篡改。
**++注意事项:++**暂无
会话变量可控
**++漏洞描述:++**会话中的参数可由客户端控制,导致客户端可以控制并修改会话参数。
**++测试方法:++**查看HTTP请求,分析会话中的可控参数并修改。
**++风险分析:++**攻击者可通过篡改会话变量,达到欺骗服务器的目的。
++风险等级:++
【中危】:会话中存在字段是由可控参数生成
**++修复方案:++**禁止从客户端传入会话变量
**++注意事项:++**暂无
跨站请求伪造(CSRF)
++漏洞描述:++ 跨站请求伪造攻击,Cross-Site Request Forgery(CSRF),攻击者在用户浏览网页时,利用页面元素(例如img的src),强迫受害者的浏览器向Web应用服务器发送一个改变用户信息的HTTP请求。CSRF攻击可以从站外和站内发起。从站内发起CSRF攻击,需要利用网站本身的业务,比如"自定义头像"功能,恶意用户指定自己的头像URL是一个修改用户信息的链接,当其他已登录用户浏览恶意用户头像时,会自动向这个链接发送修改信息请求。从站外发送请求,则需要恶意用户在自己的服务器上,放一个自动提交修改个人信息的htm页面,并把页面地址发给受害者用户,受害者用户打开时,会发起一个请求。威胁描述:攻击者使用CSRF攻击能够强迫用户向服务器发送请求,导致用户信息被迫修改,甚至可引发蠕虫攻击。如果恶意用户能够知道网站管理后台某项功能的URL,就可以直接攻击管理员,强迫管理员执行恶意用户定义的操作。
++测试方法:++
检测方式多种多样:工具常常会扫描得到CSRF的漏洞,但是一般常常为误报,重点还是依靠手工来进行检测,以下来举例说明其中一种检测以及攻击方案:
1、设置页面test.htm中,页面中有一个表单,和一段脚本,脚本的作用是,当页面加载时,浏览器会自动提交请求。页面代码如下:
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <form id="modify" action="http://www.test.com/servlet/modify" method="POST"> <input name="email"> <input name="tel"> <input name="realname"> <input name="userid"> <input type="submit"> </form> <script> document.getElementById("modify").submit(); </script> |
2、诱使用户在登录目标系统后访问URL链接http://xx.x.xx.xxx /test.htm
3、用户打开test.htm后,会自动提交表单,发送给www.test.com下的那个存在CSRF漏洞的web应用,用户信息被篡改。
4、在整个攻击过程中,受害者用户仅看到了一个空白页面(可以伪造成其他无关页面),并且不知道自己的信息已经被修改。
**++风险分析:++**结合社会工程学(如通过电子邮件或聊天发送的链接),攻击者诱骗受害者点击恶意链接,而恶意链接中包含了诸如转账等敏感操作。下图简单阐述了CSRF攻击的思想:
从上图可以看出,完成一次CSRF攻击,受害者必须依次完成两个步骤:
- 登录受信任网站A,并在本地生成Cookie。
- 在不退出A的情况下,访问危险网站B。
CSRF利用方式可分为以下两种:
1、GET类型的CSRF
GET类型的CSRF利用非常简单,只需要一个HTTP请求。攻击者诱骗受害者访问恶意页面,通常这个恶意页面包含标签<img src=http://www.mybank.com/Transfer.jsp?toBankId=hackerID\&money=1000 />,受害者一旦访问了恶意页面会向http://www.mybank.com/Transfer.jsp?toBankId=hackerID\&money=1000发送HTTP请求,该请求是转账操作,受害者在不知情的情况下向攻击者账户转账了1000元。
2、POST类型的CSRF
为了杜绝上面的问题,银行决定改用POST请求完成转账操作。因此,银行网站A的Web表单如下:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <form action="Transfer.jsp" method="POST"> <p>ToBankId: <input type="text" name="toBankId" /></p> <p>Money: <input type="text" name="money" /></p> <p><input type="submit" value="Transfer" /></p> </form> |
后台处理页面Transfer.jsp的伪代码如下:
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public void doPost(HttpServletRequest req, HttpServletResponse res) { HttpSession session = request.getSession(false); If(session==null) { response.sendRedirect("../SessionLogin.htm"); } String bankID=request.getParameter("toBankId"); String money=request.getParameter("money"); BankTools.transferMoney(bankID,double.parse(money)); } |
危险网站B的HTML代码如下:
html
<html>
<head>
<script type="text/javascript">
function steal()
{
iframe = document.frames["steal"];
iframe.document.Submit("transfer");
}
</script>
</head>
<body onload="steal()">
<iframe name="steal" display="none">
<form method="POST" name="transfer" action="http://www.myBank.com/Transfer.jsp">
<input type="hidden" name="toBankId" value="11">
<input type="hidden" name="money" value="1000">
</form>
</iframe>
</body>
</html>
从以上代码看出,危险网站B暗地里发送了POST请求到银行,且该POST请求是转账操作,攻击者访问危险网站B时在不知情的情况下向攻击者转账了1000元。
++风险等级:++
【高危】:核心系统关键操作(账户操作,审批确认......)
【中危】:普通系统关键操作(账户操作,审批确认......)
++修复方案:++
1、通过referer判断页面来源进行CSRF防护,该方式无法防止站内CSRF攻击及referer字段伪造。
2、重要功能点使用动态验证码进行CSRF防护。
3、通过token方式进行CSRF防护:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1. 在Session中绑定token。如果不能保存到服务器端Session中,则可以替代为保存到Cookie里。 2. 在form表单中自动填入token字段,比如 <input type=hidden name="anti_csrf_token" value="$token" />。 3. 在HTTP请求中自动添加token。 在服务器端对比POST提交参数的token与Session中绑定的token是否一致,以验证CSRF攻击 |
4、为每个session创建唯一的随机字符串,并在受理请求时验证:
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <form action="/transfer.do" method="post"> <input type="hidden" name="randomStr" value=<%=request.getSession().getAttribute("randomStr")%>> ...... </form> //判断客户端提交的随机字符串是否正确 String randomStr = (String)request.getParameter("randomStr"); if(randomStr == null) randomStr=""; if(randomStr.equals(request.getSession().getAttribute("randomStr"))) {//处理请求} else{ //跨站请求攻击,注销会话 } |
**++注意事项:++**暂无