我是火线安全的曾垚,今天分享的议题是Serverless应用安全浅谈,我们发现近年来主流的云厂商,或者是像K8S、CNCF生态出现了非常多的Serverless Faas的相关技术,像backend也是非常流行的。

整个Serverless产生或者是容器的产生,都是为了大幅度提高软件的开发效率和降低后续的维护成本。

希望可以通过这次分享,可以让相关Serverless开发者了解在Serverless应用开发过程中的安全风险。


整个议题分三个部分:

  • Serverless相关的技术、简要

  • Serverless带来的新工具场景

  • Serverless需注意的安全事项



Serverless 简介


什么是Serverless?不得不谈到应用整体的技术架构变迁,最早开始要开发上线一个软件,需要厂家提供硬件的服务器,需要运维对上面安装的虚拟机或者操作系统,进行后续的维护和软件部署,最后才是程序开发人员需要开发一个应用,在应用里面写非常多不同的业务函数,再去做后续的部署。

在整个传统环境,我们需要有各个不同职能的角色参与到软件开发的过程中,再到后来的Vmware等等虚拟机,我们抛弃相关硬件上的东西,包括后续产生的虚拟机、ECS,我们不需要再去维护硬件上的事情,我们只需要选择一个操作系统,在操作系统部署上我们的应用就可以了。

到现在像K8S,容器云的发展,在操作系统选择上,是不需要自己选择,我们给予Dockerfile或者是容器化的技术,我们只需要部署自己的应用,再用函数,后续只需要维护应用的稳定性和安全性就可以了。

目前我们已经进入到一个容器云的时代,大量的开发或者运维,都是以开发为优先,以Infrastructure as Code的方式去描述基础架构或者网络环境,或者应用部署的环境。

再下一个阶段是Serverless新型技术,整个开发需要维护的事情就变得更少了,但我们现在还需要维护框架和软件,后续在Serverless里面,我们只需要去维护我们真正的业务逻辑就可以了,有非常多的新型输入源,或者是新型后端的技术函数,为我们Serverless生态提供非常多的便利。

整体技术变迁,我们可以看到软件架构需要维护的程序是变得越来越少,但是我们整体的架构变得越复杂,总体来说都是为了软件开发和后续的运维成本。



Serverless整个的运行机制也发生了变化,传统的我们作为一个用户终端,是直接通过各种方式访问我们的ECS或者容器,通过容器或者ECS把流量传递到应用,再传递到框架组件,再传到有业务属性的函数,最终存储到我们的数据库,或者中间态的消息队列。

在Serverless的整个架构上,我们把Serverless的应用分为两部分,一部分是Function as Service,函数即服务,还有一部分是Backend as Service,后端即服务。

这里面有什么区别呢?Faas里面更多是通过一个函数块去定义整个业务的运行流程,Backend as Service更多的是封装好的标准控件,我们直接去调用它,这里面涉及到很多的技术,包括存储技术、包括可以使用OSS或者S3 Bucket的服务,或者使用RDS原生的存储数据库,或者是我们可以调用API Getway去做事情,甚至我们可以调用非业务处理逻辑上的,像AI算法、数据分析,甚至像区块链相关链技术,也提供相对的API接口,可以使我们直接调用下面的接口在区块链上产生运算或者记录。

从传统意义上,我们应用的主要的数据还是来源于外部的HTTP数据引流,或者是RPC应用相关的外部控制变量,在Serverless里面,整个的数据来源变得更多了,我们统计了一下,在腾讯云上,整个Serverless数据来源的Event事件,有上百种的事件,这里面有非常多包括我们可以Serverless的函数,我们可以订阅像Kafka、OSS、APIGetway,哪怕是一个在云平台登录的日志,或者是我们SNS的一个消息,或者是邮件的消息,我们都可以作为Serverless Faas函数的输入。

从开发视角上,整个的软件是变得更简单,我们可以有更多的输入去产生更多复杂的逻辑,但从安全来看,我们整个攻击面变得更多了。



常见的Serverless的服务,最早是AWS推出的 lambda,后续谷歌和微软也推出了自己的Functions函数,国内的话,我们在之前C2隐藏上用过腾讯云函数,阿里也推出了相关Serverless的服务,包括一些开源的生态,也推出了相关开源的Serverless的项目,包括K8s推出的Kubeless的相关服务。

右侧是我们一个Golang写的Serverless的Functions的示例,里面需要订阅两个东西,一个是Context,还有一个Event,基本上所有的函数,都需要传入这两个参数,后续函数里面的业务逻辑就是处理我们所针对的这些事件,再对他进行解包和数据的处理,Event它在AWS里面,是支持更多的Event事件。

阿里云也支持安全扫描的记录,像安骑士的记录等等,它是非常丰富的,跟云厂商的提供的服务有关系,如果是Kubeless,他更多是提供容器层的日志,或者是容器层API网关的Event事件都是它封装好的。

Serverless 攻击面

在Serverless里面可以看到整个业务的处理流程发生了较大变化,整个数据源也增加了非常多种不同协议或不同种类的Event事件的类型,我们的后端也发生了比较大的变化。


这张图总结了Serverless攻击面。

第一部分:看右侧是我们整个函数事件产生的注入攻击,这里面跟传统外部上的攻击是没有太大的差别,主要还是在比如说像SQL注入、命令执行、外部实体注入、XSS等等常见的外部攻击,但它相比于我们的外部应用来看,它触发的源不只是HTTP请求,更多还有它内部云服务或者是LaaS服务自带的事件型或者日志型的服务,所以我们整个插入的源会变得更多。

第二部分:最终毕竟还是应用,虽然我们不需要维护服务器、硬件服务器、操作系统容器,但是对整个应用的开发里面,还是会涉及到非常多的开源软件供应链的组件,里面包括我们提供Serverless Function的函数里面 ,它会自己封装框架,同时我们在写Function的时候,也会依赖很多的开源组件,开源组件的安全性也是非常重要的。

第三部分:权限控制的错误。到Serverless层面,我们可以通过Serverless的yaml文件去描述我们整个Serverless所需要运行的环境,所需要对后端服务的访问权限,大概是怎样的?所以我们整体的权限控制是由yaml文件去控制,很多开发同学在开发过程中,为了方便把权限设置的非常大,我们就可以利用Serverless的权限去对其他的应用进行横向的攻击。

第四部分:敏感信息的泄露。我们可以发现Serverless的应用,很多程序开发比较喜欢从环境变量里面去取东西,包括Serverless本身的框架里面,也会在环境变量存储非常多敏感的AK/SK信息,还有临时的数据也会存在TMP临时目录下的数据,因为Serverless的服务基本上只会允许Serverless用在临时目录下写些东西,我们在临时目录下也会产生非常敏感的数据。

整体的Serverless的服务,相比于传统的企业架构,在日志审计上是缺乏比较完善的日志系统,虽然Serverless里面,服务里面也提供了比较简单的日志的收集和日志log的系统,像Serverless,他整个的生命周期比容器会更短,但经过测试发现,整个Serverless应用最多也就十来分钟的一个生命周期,有可能他会更短,这可以去设置的。

我们整个日志产生也只能产生在log的目录下,对日志收集的难度来说,变得更大的。所以我们在Serverless如果发生攻击之后,我们去回溯整个攻击事件,也是缺乏审计的手段。



从攻击面来看,我们的输入源变得更多,除了传统的HTTP的数据源以外,我们还增加了OSS、Kafka、SNS、RDS,还有互联网的MQ的协议。

从运行环境来看,我们用Serverless都是用公有云的方式函数,或者是用K8S,在一个标准环境运行,它会遇到一些问题,他是个临时的环境,需要接入这些网络,还有一个特权的话,你还需要对我们后端的Backend as Service的数据库,或者是计算服务,有一些数据上的交互,在运行环境上也会存在环境控制不当的问题。

从应用本身来看,也会存在注入攻击、业务逻辑攻击等等应用层的问题,还有软件供应链上的问题。



注入攻击漏洞


这是一个注入攻击的Demo,右侧我们可以看到整个业务逻辑,就是一个函数,我们到时候是部署在AWS上的应用,这个里面是SNS的消息,这个实践为例,这个业务代码逻辑,我们把邮件里面的简历的PDF附件处理,把里面的PDF的内容处理成一个输出文本的内容的函数。

我们可以看到它从event里面去接受一个SNS的一个Message,最后通过Email的一个函数,把邮件里面的附件提取出来,对附件进行调用的一个PDF to text的命令,去对PDF进行处理,但是他整个的过程中,他没有对我们的PDF可控的Filename进行检查,所以导致了一个命令注入的漏洞。

后半部分的原理上, 跟传统的原理是一致的,从但是从输入源上是有比较不同的点,传统输入更多是从HTTP的包里面去做输入,这里面我们可以看到,它是依赖于云服务里面一个邮件服务,他收到邮件之后,产生了Event事件,产生的漏洞攻击。

我们从漏洞攻击上来看,我们如果能找到个他所订阅的收件箱,我们只需要对他的收件箱,发送一个附件,为Payload的一个文件,我们就可以产生攻击。

除了这个邮件Event事件,我们可以看到阿里云里面也有多达100多项的触发器,这里面包括他的Laas的产品,也包括日志审计、登录日志等东西。

整个的在 Serverless Function层面的,我们遇到的攻击面比之前要变的更大,随着公有云提供的服务种类变多,我们的Serverless的整个的Function支持的Event事件种类也会越来越多。

所以这也是后续大家在做Serverless开发的时候也需要关注的一个点,我们需要对所有的不同来源的Event事件的内容也需要做判断。



依赖组件漏洞


Serverless依然会面临依赖组件的漏洞攻击。我们可以看到主流的Serverless,都会提供Java、Python、NodeJS、Golang等主流语言的开发支持。这是我们在腾讯云上创建了一个Function函数,我们可以看到里面也会涉及到requirements包的引入。

据统计,我们在整体应用开发过程中,有80%以上的代码都来源于第三方的开源或者是商业的组件包,但是50%以上的开源组件多少会存在漏洞。

从去年开始,像Log4j2,我们分析完发现影响了整个开源生态四万多个开源项目,影响了全球50%以上的Java应用的在线业务系统;前两天还爆发了Fastjson系统,通过资产测绘的基础,我们发现影响到20万多台在线的生产业务的安全性。

除了开源组件的安全性以外, 我们发现在2018年, aws-lambda官方提供的函数框架里面, 也存在ReDoS漏洞, 可以对整个应用产生拒绝服务攻击。

一个是开源软件,我们自己内部编码所依赖组件包,还有我们所使用的Serverless的方式的框架是否有问题。我们发现aws-lambda、国外提供 Serverless服务的安全厂商基本上也爆出过框架本身漏洞, 影响我们整个应用的安全性。



权限控制不当


可能会存在权限控制不当的问题。我自己从GitHub上对所有的Serverless的配置的yaml文件做了分析,来源于一个真实的样例,这里面可以看到,它在statement这里面有一个Action,Action是对目标资源的一个权限,他设置的是S3:*,用来表示完整的S3所有的控制权限,包括修改、查看、删除等等操作,对Resoure的描述也是用*号来表示,所以我就可以对所有的S3对象进行控制, 整个权限是非常非常大的。

我们可以在开源的项目里面可以看到有非常多这样的案例存在,这会过多的分配Serverless应用对其他的Faas服务的控制权限,我们就可以拿到GetObject、PutObject等,能控制S3的权限。

如果我们通过刚才的注入攻击或者是其他的手法,拿到Serverless的临时控制权限,我们可以通过他的AK/SK对其所依赖的第三方的Faas服务进行横向攻击。



敏感信息泄露


这个是截图了某个云厂商Serverless的一个环境变量,他把非常多生产环境的K8S,这个K8S不是租户的K8S,是Serverless本身提供服务的K8S,一些相关的信息,还有所对应的非常敏感的Key,都写到环境变量里面, 我们很容易就可以拿到这些环境变量进行一些攻击,并且由于Serverless服务他是部署在公网上的,我们只要拿到AK/SK,不需要网络访问权限,我们直接就可以通过API或者是命令终端,直接可以通过AK/SK获得相应服务的控制权。

Serverless环境变量信息,它可以通过几种方式去获取。


开发模式


我们发现也提供Django的框架,我们可以看到Django的服务, 默认是开启了Debug的模式, 我们可以通过一些报错就可以直接拿到环境变量的信息。


异常报错


非常多的程序在业务代码开发中,把过多异常通过信息报道出来,方便程序员去做bug的处理,但程序如果抛出了过多的信息,也会导致信息的泄露。


获取Serverless权限后横向攻击提供便利


我们通过一些漏洞攻击,获取到Serverless一个横向的权限之后,可以通过环境变量里面泄露的AK/SK或者是代码里面硬编码这些AK/SK,对其他依赖的服务进行横向的攻击。

整个Serverless从攻击上来看, 它的生命周期变得更短了,所以我们整个Serverless的攻击, 相比原来的渗透测试会有比较大的区别, 我们一定是自动化的。

因为传统的渗透测试,拿个机器,只要在管理员发现之前,是有无限长的时间对目标进行详细的分析,但Serverless里面,你对Serverless进行请求,本身就有非常短的生命周期,所以一切的攻击都是需要自动化的。

我们发现前年已经有相关的蠕虫的病毒,就是针对Serverless应用进行攻击的,基本上也都是拿到权限之后去读env变量,通过env变量的AK/SK进一步的扩展,去控制其他在线的系统。

从整个的横向,渗透测试的角度来看,攻击面或者攻击手法在新的场景下都发生了比较大的变化。



Serverless有这么多攻击面,在安全检测上也遇到了比较多的挑战。



传统黑白盒技术无法检测


我们发现传统的黑白盒技术已经无法检测Serverless场景漏洞,主要原因有几个原因。

一个是黑盒技术,它是需要应用运行时的一个技术,但在 Serverless里面,应用本身就不会有特别长的生命周期,所以不会让你一直扫描,并且他整个Event事件源也非常多,你无法通过传统的HTTP请求对Serverless应用进行扫描。

白盒也遇到一样的问题,Serverless整个的应用架构,原生是个微服务架构,一个完整的应用它是由几十个或者上百个Serverless函数进行构成的,本来是一个分布式,而且里面支持的协议也不是传统的RPC或者是标准协议,它更多是通过Backend后端服务进行交互,所以在这种场景下,在白盒里面检测非常难的,白盒是无法适配这么多的Event事件的来源,白盒基本上只能做常见的接口、协议或者HTTP协议的 污点追踪,但是白盒到现在也没有解决,跨服务、跨应用、跨语言之间的漏洞检测的问题。


无法部署WAF、防火墙


目前在整个函数应用层面是没有办法部署在线的WAF或者防火墙,但是我们也看到国外已经有相关的技术,可以通过插件的方式,在Serverless运行时部署Serverless临时的WAF、防火墙,但是这个技术相对比较早。



无应用函数架构复杂


整个的Serverless函数架构是无比的复杂的,我们之前攻击的应用,他可能是部署在一起,或者是很容易梳理关系,但在Serverless整个应用里面, 是由非常多无数的函数和无数的后端服务构成的,所以我们很难梳理出整个的架构的情况。



无法进行统一鉴权


在公有云上使用,Serverless服务默认就会生成一个很长的地址,基本上我们很难去对地址进行鉴权,除非我们使用云厂商自己统一的鉴权方式,无法去对每一个函数进行统一鉴权,除非从开发设计一开始就考虑这个问题,如果后续去做的话, 是难度非常大。


Serverless 安全建议



安全编码规范,防止注入攻击


需要注意编码规范,防止外部注入攻击,或者是由于异常导致企业信息泄露。



三方供应链软件检查


我们需要去注重三方的开源组件的安全检查,或者是我们所依赖的商业的SDK,或者是我们所使用的Serverless框架,他本身是不是也会存在问题。



IAM/Baas等最小权限运行


运行环境的问题,我们所运行的Serverless应用,赋值的权限是否是最小的权限,因为我们需要依赖非常多的后端的服务去做业务的处置。



Serverless服务统一鉴权


Serverless默认是没有鉴权的,我们只要拿到地址就可以对这个应用进行攻击, 我们需要做统一的鉴权。



KMS密钥安全管理


我们发现非常多的 Serverless的一种,是整个密钥都非常粗暴的管理,都是在环境变量进行管理,我们可以依赖于像K8S密钥管理的系统,对密钥进行统一的管理。



及时销毁运行时临时敏感数据


Serverless是一个生命周期非常短的服务,所以它会有非常多临时的敏感数据存在我们的临时目录下,我们需要在对数据进行处理完之后,进行及时的销毁。



资源网络隔离


Serverless整个的网络默认如果是你跟VPC连通的话, 是会存在一个被横向的风险。


Serverless技术在国内外都是非常前沿、早期的技术,但相对是比较确定的技术方向,是一个非常好的技术。

大家从技术本身或者是安全上,还是有非常多可做的事情,包括如果你现在使用Serverless,目前对Serverless的安全上的关注还是比较少的。