乐趣区

Serverless????Nodejs-Puppeteer-渗透测试爬虫实践

本文归纳于微服务与云原生 https://github.com/wx-chevalier/Backend-Series 系列文章,其相关的参考资料声明于 Awesome Serverless List。

Serverless????Node.js Puppeteer 渗透测试爬虫实践

参考 CNCF 的定义,Serverless 是指构建和运行不需要服务器管理的应用程序的概念;而 AWS 官方对于 Serverless 的介绍是:服务器架构是基于互联网的系统,其中应用开发不使用常规的服务进程。相反,它们仅依赖于第三方服务(例如 AWS Lambda 服务),客户端逻辑和服务托管远程过程调用的组合。

Serverless 目前主要的落地形式为 BaaS 与 FaaS。BaaS 后端即服务,即是一些后端云服务,比如云数据库、对象存储、消息队列等。利用 BaaS,可以极大简化我们的应用开发难度。FaaS 函数即服务,则是暂存容器中运行的自定义代码,函数是无服务器架构中抽象语言运行时的最小单位。在 FaaS 中,用户主要为函数的运行时间付费,而不需要关心 CPU 或 RAM 或任何其他资源及其运维的负担。

参考 BaaS 与 FaaS 的定义,我们可以知道 Serverless 的主要特点有:

  • 事件驱动:函数在 FaaS 平台中,需要通过一系列的事件来驱动函数执行。
  • 无状态:因为每次函数执行,可能使用的都是不同的容器,无法进行内存或数据共享。如果要共享数据,则只能通过第三方服务,比如 Redis 等。
  • 无运维:使用 Serverless 我们不需要关心服务器,不需要关心运维。这也是 Serverless 思想的核心。
  • 按实际使用计费:使用 Serverless 成本很低,因为我们只需要为每次函数的运行付费。函数不运行,则不花钱,也不会浪费服务器资源。

这些特征的本质,是用户对于云端应用开发,乃至于所谓云原生应用中的用户友好与低心智负担方向演讲的最直接途径,而这种简单、经济、可信赖的期许,也是云计算的初心。当然 Serverless 并不拘泥于 Function,而是应该多种部署形态并存,譬如以应用方式部署,则是遵循单一职责原则,但是能够触发多个事件;也可以在容器级别部署,能够包含任意语言、任意运行时,譬如 Knative 这样的解法。在微服务与云原生 /Serverless 一节中我们也讨论了更多的 Serverless 落地模式。

前端视角的 Serverless

在现代 Web 开发基础与工程实践 https://github.com/wx-chevalier/Web-Series 系列的前言中,我们也讨论了 Web 技术与生态经历了模板渲染、前后端分离与单页应用,工程化与微前端,大前端与 Serverless 这三个不同的阶段。自然从前端的视角来看,Serverless 也赋予了前端更多的自由与可能性,在服务端渲染,小程序开发的简单服务端支持,包括 BFF 接口聚合等方面都有很多的空间。

BFF 在解决接口协调与聚合问题的同时,也承载了原本后端的并发压力,这也给前端工程师带来了很多的开发与运维压力。Serverless 则是能够缓解这种问题,我们可以使用函数来实现接口的聚合裁剪;前端对于 BFF 的请求被转化为对 FaaS 的 HTTP 触发器的触发,这个函数中来实现针对该请求的业务逻辑,比如调用多个微服务获取数据,然后再将处理结果返回给前端。这样运维的压力,就由以往的 BFF Server 转向了 FaaS 服务,前端再也不用关心服务器了。Serverless 同样也能够应用到服务端渲染中,将以往的每个路由,都拆分为一个个函数,再在 FaaS 上部署对应的函数。这样用户请求的 path,对应的就是每个单独的函数。通过这种方式,就将运维操作转移到了 FaaS 平台,前端做服务端渲染,就不用再关心服务端程序的运维部署了。此外,像微信、支付宝等小程序也提供了符合 Serverless 理念的云开发平台,赋能业务前端迅速迭代。

阿里云的 Fun????cendertron

阿里云的 Serverless 服务为我们提供了函数式计算服务,函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。

Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。

cendertron https://github.com/wx-chevalier/xe-crawler 是基于 Puppeteer 的动态爬虫,其专注于渗透测试的前置接口提取,内置了动作模拟、URL 去重、界面表单与请求提取等特性。

标准的 Docker 化部署方式下,我们需要将其打包到 Docker 容器中:

# build image
$ docker build -t cendertron .

# run as contaner
$ docker run -it --rm -p 3000:3000 --name cendertron-instance cendertron

# run as container, fix with Jessie Frazelle seccomp profile for Chrome.
$ wget https://raw.githubusercontent.com/jfrazelle/dotfiles/master/etc/docker/seccomp/chrome.json -O ~/chrome.json
$ docker run -it -p 3000:3000 --security-opt seccomp=$HOME/chrome.json --name cendertron-instance cendertron

# or
$ docker run -it -p 3000:3000 --cap-add=SYS_ADMIN --name cendertron-instance cendertron

# use network and mapping logs
$ docker run -d -p 5000:3000 --cap-add=SYS_ADMIN --name cendertron-instance --network wsat-network cendertron

而现在利用阿里云的函数式计算,我们可以将其转化为 FC 模式部署,其示例项目参考 cendertron-fc:

# Install fun cli
$ brew tap vangie/formula
$ brew install fun
$ brew install fcli

# Config fun cli
$ fun config

# Install dependences
$ fun instll

# 如果希望运行时动态地从远端拉取 Puppeteer,则在 https://fc-demo-public.oss-cn-hangzhou.aliyuncs.com/fun/examples/headless_shell.tar.gz 下载 headless_shell.tar.gz,或者使用 scripts/buildChrome.sh 构建;然后上传到 oss://${BUCKET}/headless_shell.tar.gz

# Deployment

# 使用 fun 命令部署
$ fun deploy

# 或者本地手动打包上传,同步打包本地的 Chrome 到远端
$ npm run package
# 不打包 Chrome,动态地从远端拉取
$ npm run package-nochrome
# 在相应 Service 目录下发布 Function
$ fcli shell
>>> mkf/upf cendertron-fc/crawl -h index.handler -f package.zip -t nodejs8

: << !
using region: cn-beijing
using accountId: ***********6367
using accessKeyId: ***********5Kd5
using timeout: 10

Waiting for service cendertron-fc to be deployed...
        Waiting for function crawl to be deployed...
                Waiting for packaging function crawl code...
                package function crawl code done
        function crawl deploy success
service cendertron-fc deploy success
!

# Test crawl
# Invoke remote
$ fcli function invoke -s cendertron-fc -f crawl
$ fcli function invoke -s cendertron-fc -f crawl --event-str 'http://www.baidu.com'

# Local debug
$ fun local invoke crawl <<<'http://www.baidu.com'
退出移动版