0
6月21日,一则刑事判决书出现在大众眼里,其中几位被告人用爬虫抓取服务器内容,一审判决认为他们触犯了《刑法》第 285 条”非法获取计算机信息系统数据罪”,判处有期徒刑和罚金XXX。(点这里)
底下的围观群众炸了:
网友甲:刚学爬虫没多久,是不是要弃坑了?
网友乙:怎么办,跑吗?
网友丙:做爬虫的我瑟瑟发抖.jpg
网友丁:爬虫工程师这个岗位是不是要凉?
不过也有比较理智的群众,比如说:离职员工利用对系统的熟悉,或者也许是自己留的后门,伪造特定 UA 抓取内容被老东家告了。
还比如:大家不要恐慌,有看到v2有知情人说其实不是爬虫,是在内部服务器偷数据。
总之爬虫技术这个明星词汇又进入了大众眼中,有缘的是,就在不久前由阿里云主办的先知大会上,雷锋网宅客频道也听到一个有关爬虫的议题。
演讲者是阿里云高级安全专家猪猪侠,长期从事自动化安全测试工作,熟悉多种开发技术,擅长渗透测试与数据挖掘。
猪猪侠介绍了如何基于历史经验和已知场景,构造并实现一个动态爬虫。通过浏览器提供的Headless调试模式,来遍历一个网页的所有动态对象,自动填充输入表单的参数值,并触发对象上的绑定的事件,有效解决安全测试过程中的攻击面挖掘。
以下为猪猪侠演讲内容,雷锋网整理。
在讲爬虫技术之前,先思考一个问题:我们为什么需要一个扫描器爬虫?
据大量调查分析显示,国内多数企业做安全测试时还停留在人肉过程中。自动化测试程度相对较低,且企业在日常安全测试过程中,投入了大量人力成本在重复性工作上。
人毕竟是血肉之躯,有时候会累,也有时候情绪激动。可能某公司测试人员在心情不好时候做测试,最后的安全测试结果就是看心情,只有攻击面和测试准备充分的时候才能够得到保障。同时Web2.0框架很活跃,导致非常多的是失效的,他们的爬虫无法识别出整个网页的链接结构。
这个时候我们需要一个爬虫帮助我们提升整个安全测试的效率。
首先,业界同行和安全工程师是怎么实现爬虫的?先举一个例子,之前微信群有个朋友说,他使用下图这串代码爬取seebug没有爬到结果。这是因为seebug网站利用了代码混淆的技术,并一直频繁更新,最终导致以前纯静态性的爬虫完全失效。
怎样解决静态爬虫的缺陷?
只需要引入一点新的技术,比如说带GS引擎的爬虫就能够解决这个问题,你用PIP安装一个安装包,使用左边的代码就能够完整的爬到seebug的链接信息了。
这个项目是继承谷歌的无界面浏览器开发的。无界面建成为healless浏览器,现在有四种,它们缺点是使用诸多第三方库非常不稳定。后来phantomjs出现,但phantomjs有很多无法修复的问题,作者之后宣布不再对其进行维护,只能选择谷歌的无界面浏览器。
为什么使用谷歌的phantomjs进行爬虫,主要有三点。第一有谷歌大厂支持,谷歌浏览器世界占有率第一,稳定率高,几小时一个版本更新。另外谷歌对W3C标准组织的支持度在全球所有浏览器中是最高的,兼容性也较好。
回到今天的主题,什么是启发式爬虫?
简而言之启发式爬虫是基于所有历史经验及曾经看到过的已知场景,通过分析这些场景和利用已知的经验构建并实现规则的爬虫。
接下来我们来看看整体的启发式爬虫最佳实践流程。首先可以把爬虫看作一个工厂流水线系统,流水线系统一定会有一个总队长负责各条生产线任务调度,在这里ROP就是总队长。流程明确后,每个步骤都各司其职实现各自的功能。
爬虫总队长这个管理器的功能负责任务调度和事件管理。在做扫描器爬虫的第一步先将URL传给任务调度器总队长,总队长把这个任务传给下面,之后打开页面进入到加载状态。页面加载后需要判断当前页面是否完全,比如有时候某些网页服务器网络性差,或是遇到GS报错、网站超时某些资源显示不全,这时候可以通过下图标注的三个状态来确定整个网页的结构是否加载完成,整个页面是否打开完成。
完成后把整个浏览器page页面锁定不做任何动作,让它打开另外一个新网页,或者跳转其他网页上去。
当整个网页加载好之后,把整个网页跳转锁定后就可以进入到函数劫持阶段。随后开始注入一个监听器,监听所有事件的变动和事件触发的信息。当文件加载、函数劫持、监听都完成之后,可以编译出任何输入框绑定的事件,对某个输入参数值进行常规判断的一些信息。
当我们发现页面存在表单的时候,可以通过分析表单的输入类型以及表单名称,进行一些参数填充。上面所有流程结束后,会得到当前页面所有信息的结果题。此时可以通过去虫过滤之后,返回给事件管理器,重复执行整个流程。
确定总体流程之后回到刚才的第一步,页面加载,录入实现。
当一个页面加载完成之后,应该在什么时候注入我们的劫持代码,这里边有状态可以选择。第一个在page load之后;第二个是等待页面加载完成之后,也就是当前网络状态全部空闲的时候,整个爬虫执行流再继续执行;或者判断整个网页的DOM树是否被加载并解析完成。
再看请求连接部分,下图三个问题是Web2.0爬虫界和Web1.0都受到关注的问题。当你爬取一个网页之后,某些代码就把你的页面跳走了,甚至可能规则还没有加载完成页面就被人转走了。
大家针对这个问题给出的解法不同,有的人建议自己把原码重新编译。其实除此之外还有一个解法,就是插件机制,能够实现在另外一层对浏览器的控制。如下图,为每个浏览器插件提供一个对象,当整个浏览器发起请求之前,可以在事件触发一瞬间,网页开启前在这里添加一个函数进去。
比如当上面的123要发生时,可以通过增加一个监听事件,把当前所有页面Web请求从逆向到链接上实现网页锁定,当爬取一个页面的时候就再也没有任何函数把页面跳转走,这样可以确定整个页面的完整性。我猜测那些屏蔽视频广告的插件,也是利用了这个函数实现的这一功能。
另一个困扰我们的问题是各种不断弹出的弹窗,甚至会遇到一些极端的开发,在网页中加一些参数和地址刷新的函数。如果要确保我们创造的爬虫能够流畅的爬取整个页面不被浏览器奇奇怪怪坑住,需要直接将已知的能够制造网页阻塞的函数进行劫持。
页面加载的时候,可以监听所有弹窗的事件,只要弹出一个窗,之后结束把这些都改掉。关于超时函数,我们制定一个原生函数,在调用这一函数时候把时间永久设置成是0,后面执行也是通过此方法,调用对时间控制的任何函数,都把生命周期设成0,这样就不会因为开发的一些代码导致整个网页被框住。
还有一个爬虫界非常关心的是如何获取AJAX请求信息。
有两种方法,一个使用拦截的功能,类似于被动扫描器的代理,浏览器提供这个API所有的资源,只要网络请求信息都可以通过这一方法拦截记录下来。
第二种简单粗暴的方法是直接可以用自己的函数把原生函数劫持起来,把请求信息记录下来,这里只需要劫持这些方法可以扫描器爬虫所需要的所有功能。
当函数劫持过程完成后,开始分析整个网页下面所有节点信息以及表单信息,具体的实践方式有两种。比如可以通过使用循环DOM所有节点信息。另外我们可以使用DOM提供的强大工具,通过自定义规则过滤文档中节点,来生成新的节点信息。我们可以提前定义好想要捕获节点信息的相关规则,比如说我们把SRC只要是DOM任意节点上,跟所有相关的信息监听起来,只要网页上任何一个连接信息,或者一个图片的地址发生改变,都能够通过这个方法来捕捉到。
当通过DOM获取所有信息之后,并不是所有事件信息都需要触发一遍,我们往往建议针对特定的场景,去匹配执行。比如在浏览一些新闻网站时候,需要通过滚动屏幕刷新刷出更多的新闻,背后用到的技术就是监听翻页的方法实现。比如使用一些模态框的时候,需要在一个网页中点一个按纽,这是已绑定好的事件,点一下会弹出模态框输入信息。比如像社区型知乎和雪球网站,他们为了实现消息的实时配送,背后有历史任务在运行。
当拿到整个节点信息和绑定信息之后,可以选择触发这些事件信息。触发事件信息有两种,如下图代码,上面有一个事件,事件的名称是click,可以直接通过代码声明一个事件直接触发,这两行代码执行时浏览器会弹出一个click的弹窗。另外一种简单粗暴的方法是找到事件背后的值,事件绑定背后的值就是一个代码,可以调用EVAL直接执行。
当然我们可以模拟任何事件,我们设计爬虫的目的是为了做安全测试,在安全测试过程中,发现攻击面的多少决定整个安全测试效果。在Web场景中表单十分重要。比如我登录页面,搜索页面在整个开发过程中,涉及数据库的增加修改查询都和表单有关。遍历表单的方式也有非常多,但这里还有另一个更加方便的方法,直接使用原生的对象,通过循环把整个当前表单登录框里边有哪些内容进行查找。
建立完表单之后,参数类型自动获取到表单里边输入框的字符长度,为每个参数生成合适的值,同时可以调用节点的方法,给表单设计一个值,或者可以通过这个方法帮助按纽点上选项。当我们有表单的时候,就可以实现自动填充。比如爬虫发现一个页面是一个登录接口可以通过判断它的输入框的名称,是不是包含这些内容,如果是的话就通过下面定义好的规则,直接从这里边挑一个名,填充过去。当我们发现一个表单里边是跟它相关的,我们就可以通过同我们规则里边拿到英文的名,然后在再等等一个@,然后再把下来DOM的列表随机挑一下得到一个邮箱就自动填充。
整个流程介绍完后来看一个爬虫DEMO,主要爬取一个网页,把网页中所有的信息图片、动态摄入和元素都爬出来。
demo下载地址:https://github.com/ring04h/papers/blob/master/xianzhi_crawler_demo.mov
最后是总结的四个观点。
当我们发现URL中孤立出现的数字,90%的情况是动态参数。
在爬取到一个页面结果时,发现非常多链接在pass,里边存在长度相似的一致性,且生成方式是通过其他方式生成的。我们可以判断一下存在多少长度一致的链接,如果这个数大于5或者10,应该小心这里边是一个动态的参数。
我们解决伪静态问题上,伪静态百分之七八十情况下通过横杠和反横杠分析这个。比如第一个连接就是反斜杠伪静态,下面就是横杠的伪静态。我们将整个部分进行分割,分割出来的值是什么类型,如果是整形就命中了第一个只要孤立数字出现在某个路径下都可能是动态参数。
另外我们通过HASH化去做去虫,比如有同样的链接他们在123456789,我们只需要把这个连接每个参数切割成括号进行切割,最后看他们的出现的频次,如果出现的次数非常多,代表着这个参数是一个常量,它是固定挟持的。如果背后的参数出现的次数非常散漫,只有1和2,那个路径后面的参数有可能是动态的参数。
以上内容来自阿里先知大会,雷锋网编辑整理。
雷峰网原创文章,未经授权禁止转载。详情见转载须知。