距离2019年那场轰动性的事件已经过去了将近十个月,Capital One 数据泄漏事件的许多细节已经渐为人知。是时候让我们放下争论,进行一次冷静的分析,思考一下究竟要如何提升安全管理的水平。
按照众多媒体的报道,在2019年7月,黑客佩奇·汤普森(Paige Thompson)在 GitHub上吹嘘其所盗取的Capital One的数据,于是引发了这一场惊天大案。这次黑客攻击是有史以来金融服务公司遭受的最大数据泄露事件之一,该事件影响的用户数量超过了1亿之多,包括了大量个人信息,例如姓名、地址和出生日期以及财务信息,包括自我报告的收入和信用评分等等。这个数据泄漏的规模与2017年的 Equifax事件 大致处于相同的级别。
据直接了解违规调查的消息人士称,该问题部分源于 Capital One 部署在 AWS 上的开源的 Web 应用程序防火墙(WAF)存在错误的配置。这款名为 “ModSecurity” 的开源 WAF,作为 Apache Web 服务器的模块部署使用,以提供针对对基于 Web 应用程序安全性的几类漏洞的保护。不幸的是,WAF的配置错误使入侵者可以诱骗防火墙将请求中继到 AWS 平台上的关键后端资源。该资源称为 “元数据” ( metadata) ,其中包括从安全服务发送的当前凭证,以访问该服务器被许可访问的云中的任何资源。在AWS的环境中,这些凭证的权限容取决于分配给请求它们的资源的权限 。在 Capital One 的例子中,配置错误的 WAF 被分配了太多的权限,即允许它列出任何 S3 数据桶中的所有文件,并允许读取每个文件的内容。
关于这个事件Capital One 已经发表了一个声明,有兴趣的不妨去读一下。
“ 服务器端请求伪造 ”(SSRF)攻击
有迹象表明,在这个案例中入侵者利用的漏洞类型是一种众所周知的方法,称为服务器端请求伪造 (SSRF)攻击。在这种攻击中,服务器(在本案例中为 Capital One 的 运行在AWS EC2上WAF 服务器)被诱骗连接到它不打算连接的另一台服务器,并且该服务器允许与元数据服务进行通信。当在线应用程序需要外部资源使攻击者能够从易受攻击的 Web 应用程序的后端服务器发送精心设计的请求时,就出现了SSRF 漏洞。
SSRF已成为云计算所面临的最严重的安全挑战。但准确的说 SSRF 并不是一个未知的安全漏洞。它没有引起足够的重视,甚至并没有包含在 OWASP Top 10之中。
什么是元数据服务?
要了解SSRF为何带来如此严重的问题,首先需要了解AWS中“角色”(Role)的工作方式。默认情况下,AWS中的EC2实例并不是运行在独占的硬件之上。这对安全性而言并不是一件坏事,因为每个AWS用户的工作负载都隔离在虚拟机内部(这个话题不会涉及Meltdown 、Spectre,如有兴趣不妨读一下拙作“悬在云计算头上的达摩克利斯之剑 – 对于Meltdown 、Spectre事件的进展与思考”)。这些EC2的实例都有不同的IAM角色,该角色描述分配给每个EC2的工作负载的策略和权限。例如这个名为 SSRF_Role 的 IAM 角色就具有了对于EC2、S3 全部的访问许可。
![bbfbf89371f0454b3ebe45616227349a.png](https://img-blog.csdnimg.cn/img_convert/bbfbf89371f0454b3ebe45616227349a.png)
当运行在EC2上的应用需要访问S3 上的资源时,该应用调用的 AWS SDK 将自动的从元数据服务中获取新的IAM角色凭证。很有意思的一点,元数据服务运行在Hypervisor(虚拟机管理程序)之上,负责在凭证过期之前进行管理协调以获得新的凭证。当向客户可以访问元数据服务的特定IP地址(169.254.169.254)发出请求时,该请求将永远不会离开这一台计算机,所以该请求也不会通过网络传输。这就是元数据服务不需要使用HTTPS而仅仅使用HTTP的原因。
毫不夸张的讲,元数据服务是云计算领域一项非常了不起的创新。它为虚拟机用户提供了一种简单、有效的机制,可以轻松开发出来通过AWS服务进行安全身份验证的软件,而无需任何特殊代码或实际处理IAM密钥的复杂操作。Amazon EC2 实例上的元数据服务我们通常称之为Instance Metadata Service (IMDS)。
元数据服务(IMDS)的安全挑战
元数据服务(IMDS) 虽然带来了很多优点,但是在 SSRF 的攻击面前也暴露了一些不足。具体说来,IMDS 提供了大量的元数据。这些元数据之一是 IMDS 可以被利用来在临时凭证的有效时间内提供的实例级凭证(即与实例关联的 IAM 角色的权限)。如果恶意使用者已经能够执行针对 EC2 实例的 SSRF 攻击,那么就会产生灾难性的后果。我们来展示一下在 EC2 实例上使用 IMDS 提供的凭证来进行操作的过程 –
1、查询当前EC2实例的安全凭据。通过curl 这个常见的命令来查询IMDS,得到了一个名为SSRF_Role 的角色名称。命令 :
curl http://169.254.169.254/latest/meta-data/iam/security-credentials
![807850af372fbb3939e3219a774ea8b0.png](https://img-blog.csdnimg.cn/img_convert/807850af372fbb3939e3219a774ea8b0.png)
2、使用 AWS 命令行工具AWSCLI,我们能够验证出 SSRF_Role 正作用于我们所使用的这个 EC2 实例。命令:
aws ec2 describe-instances --region us-west-1 --query 'Reservations[*].Instances[*].[InstanceId, IamInstanceProfile.Arn]' --output text
![5d793feb97a2c03a645f6140483caa6f.png](https://img-blog.csdnimg.cn/img_convert/5d793feb97a2c03a645f6140483caa6f.png)
3、到目前为止,我们可以看到IMDS正常工作,并且我们能够基于实例的角色执行命令。现在,让我们来得到这个角色的凭证。命令 :
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/SSRF_Role
![3ba8aaef695af890ec386e9e13bbf5f4.png](https://img-blog.csdnimg.cn/img_convert/3ba8aaef695af890ec386e9e13bbf5f4.png)
4、现在,问题已经出现了。一旦攻击者掌握了这些凭证,他就可以在任何地方(甚至从AWS外部)使用它们。让我们看看如何工作 –命令:
aws ec2 describe-instances --region us-west-1 --query 'Reservations[*].Instances[*].{Instance:InstanceId,PublicIp:PublicIpAddress,PrivateIp:PrivateIpAddress}'
![ac4f2d3a8281318fdd735a4649c51c9d.png](https://img-blog.csdnimg.cn/img_convert/ac4f2d3a8281318fdd735a4649c51c9d.png)
这几个简单的步骤已经很好地说明了问题。如这个例子,EC2实例的角色拥有读取S3存储桶的权限,我现在就可以将这些存储桶中的数据直接读取到我的计算机上。尽管通过这种方式获得的凭据是有时间限制的,但是只要我可以访问实例的元数据,我就可以每次都能够获取新的凭据。这就是Capitcal One 事件的一个关键问题。
启用IMDSv2 对抗SSRF 攻击
在上文的例子中,我们所使用的元数据服务(IMDS)现在被称之为IMDSv1。今天,
AWS正在提供v2的EC2实例元数据服务(IMDSv2)。需要强调的是,现有的实例元数据服务(IMDSv1)是完全安全的,AWS将继续支持它。但是IMDSv2为可能用于尝试访问IMDS的四种类型的漏洞添加了新的、更多的保护。这些新的保护措施远远超出了其他类型的缓解措施,同时可以与现有缓解措施相协作,例如限制IAM角色以及使用本地防火墙规则来限制对IMDS的访问。AWS还提供了支持IMDSv2的AWS SDK和CLI的新版本。
使用IMDSv2,每个请求现在都受到会话身份验证的保护。IMDSv2向在EC2实例上运行的软件返回一个安全令牌,该安全令牌将作为密码来向IMDSv2请求元数据和凭据。与传统密码不同,我们不用担心将令牌保存在软件中,因为软件只能通过PUT自行获取。这意味着,令牌永远不会由IMDSv2存储,也永远不会被后续调用检索。使用令牌的过程终止时,会话及其令牌将被有效地销毁。会话最多可以持续六个小时,并且为了提高安全性,只能直接从该会话开始的EC2实例中使用会话令牌。
IMDSv2 的使用方法如下 –命令:
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") && curl -H "X-aws-ec2-metadata-token: $TOKEN" -v http://169.254.169.254/latest/meta-data/iam/security-credentials/SSRF_Role
![30ec4ee6ed7cdd6cd5178060b1a326cc.png](https://img-blog.csdnimg.cn/img_convert/30ec4ee6ed7cdd6cd5178060b1a326cc.png)
注意事项 :
- 特别强调一下,如果不执行任何操作,则IMDSv1和IMDSv2都可用于EC2实例。这就是说,仅使用IMDSv2的方法并不能改善目前的安全状况。我们必须主动禁用IMDSv1!!
- 确保实例上使用的新的AWS SDK,使得运行在EC2上的软件都能够支持IMDSv2。例如 boto3、aws-sdk-java-v2 等
- 对原有使用IMDS的程序、脚本需要进行兼容性测试,尤其是基于AWSCLI 的脚本。需要注意的是,AWSCLI 已经升级为 version 2,需要我们尽快升级为新的版本。安装方法在这里。
- 对于新创建的实例,强烈建议仅仅支持IMDSv2!
- 对于现有的EC2实例,需要使用后面将要介绍的内容,使其支持且仅支持IMDSv2。
如何在EC2实例上启用IMDSv2
将现有的EC2实例设定为仅支持IMDSv2
首先,让我们验证一下EC2实例是否已配置为使用IMDSv2,让我们检查实例的属性:
命令:
aws ec2 describe-instances --region us-west-1 --query 'Reservations[*].Instances[*].[InstanceId, IamInstanceProfile.Arn, MetadataOptions]' --output json
![75c26cb69a5a96724903e462ad778d1b.png](https://img-blog.csdnimg.cn/img_convert/75c26cb69a5a96724903e462ad778d1b.png)
请注意 “ HttpTokens ”:“Optional” 输出的结果意味着针对这个EC2实例 IMDSv2是可选的。现在,让我们强制该实例使用IMDSv2。我将从具有适当EC2权限的管理机上运行以下命令:
命令:
aws ec2 modify-instance-metadata-options --instance-id i-04ca872b64853e154 --http-tokens required --http-endpoint enabled --region us-west-1
![b04e44536423593ee644a873e8e971a8.png](https://img-blog.csdnimg.cn/img_convert/b04e44536423593ee644a873e8e971a8.png)
现在,执行命令后返回的状态为“pending”。我们可以稍后发出一个describe-instances 命令,再来看一下处理的结果 –
![ba3b0f7518dcb02b7033ab4e1bb14e8d.png](https://img-blog.csdnimg.cn/img_convert/ba3b0f7518dcb02b7033ab4e1bb14e8d.png)
如果这时候我们还是使用IMDSv1的方式进行元数据的操作,会发生什么情况?
命令:
curl -v http://169.254.169.254/latest/meta-data/
![04d346cb5fab612c2f96c8efe01a1622.png](https://img-blog.csdnimg.cn/img_convert/04d346cb5fab612c2f96c8efe01a1622.png)
返回的结果存在一个错误的信息401“Unauthorized”。从错误中看得出来,我们现在只能工作于IMDSv2 模式之下。我们再使用IMDSv2的方式操作一下 –
命令:
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") && curl -H "X-aws-ec2-metadata-token: $TOKEN" -s http://169.254.169.254/latest/meta-data/instance-id
![4930c0d18f7fbf3bc45007472fc9c875.png](https://img-blog.csdnimg.cn/img_convert/4930c0d18f7fbf3bc45007472fc9c875.png)
现在,我们得到了EC2实例数据按预期使用IMDSv2返回了我们需要的元数据。
创建新实例时启用IMDSv2
无论是通过管理控制台或者AWSCLI 命令行工具,我们都可以在创建新的EC2实例时启用且仅仅使用IMDSv2。例如使用AWSCLI 来创建实例 –
命令:
aws ec2 run-instances --image-id ami-0abcdef1234567890 --instance-type t2.micro --key-name MyKeyPair --metadata-options "HttpEndpoint=enabled,HttpTokens=required"
但是从实用性以及安全性的角度,我认为自动化的方法更值得推荐。这里有几个值得借鉴的思路:
- 一种更可靠的方法是在CloudWatch Event中使用“ StartInstances” API事件,并将目标指向Lambda函数。我们可以使用以下事件模式:
{“source”: [ “aws.ec2” ],“detail-type”: [ “EC2 Instance State-change Notification”],“detail”: { “state”: [ “running” ] } }
通过触发这个事件,Lambda函数将读取EC2实例的InstanceId,并通过修改元数据选项强制其使用IMDSv2。要记住,CloudWatch和Lambda是区域(Region)性的资源,因此如果使用多个AWS区域就需要按区域进行部署。
- 如果您不介意使用定期检查的机制来强制使用IMDSv2,则可以安排Lambda函数按计划(例如每天)运行。这个Lambda函数可以遍历所有的AWS区域,因此只需要部署一次即可。
- 另一个选择是利用CloudTrail跟踪以及来自所有AWS区域的事件,并将其日志保存到S3存储桶中。然后可以分析这些日志,一旦检测到“ RunInstance”事件,就可以触发Lambda。这种方法适用于全部的AWS区域,不需要在每个区域都部署Lambda函数。这个方法适合已经使用了CloudTrail事件的用户,并且唯一要添加的功能就是写一个Lambda函数。
相信还有许多自动化的方法都可以达成启用IMDSv2的目的,选择适合自己的方式最重要。
监控与侦测
AWS已经为元数据服务创建了专用的CloudWatch指标,称为“ MetadataNoToken”。我们可以通过监视这个指标以检测在没有IMDSv2令牌的情况下调用实例元数据服务的实例。一旦检测到,我们就可以找到发出这些调用的软件,并将其更新为使用IMDSv2。如果已完成过渡阶段,但我们仍想了解是否仍然存在没有使用IMDSv2配置实例,则可以在每个区域中执行DescribeInstances调用,并从结果中检查实例元数据中的这个字段-“ MetadataOptions / HttpTokens”。
还需要介绍一个与之相关的AWS服务就是 GuardDuty。如果用户的实例凭证已被泄露,GuardDuty将检测何时在实例外部使用了发给用户实例的凭据,并发出警报。在这里可以找到关于Guarduty的更多信息。另外,GuardDuty是检测环境中各种安全事件的非常有效的一个服务,因此即使不担心有SSRF漏洞,也强烈建议使用它以增强安全性。
结论
关于安全我还想强调一句曾经写在一篇博客的一句话“You Can Never Be Too Careful””(越小心越好)。在Capitcal One 的事故出现之前,我根本没有想到区区的元数据的安全是如此的重要。希望通过这一篇文章再一次让我们重视起来云上的安全。如果你对此有任何见解,欢迎与我讨论。我的邮箱是lianghon@amazon.com。
本篇作者
![495e307705b98c56dbd17531b75058b7.png](https://img-blog.csdnimg.cn/img_convert/495e307705b98c56dbd17531b75058b7.png)
费良宏
费良宏,AWS Principal Developer Advocate。在过去的20多年一直从事软件架构、程序开发以及技术推广等领域的工作。他经常在各类技术会议上发表演讲进行分享,他还是多个技术社区的热心参与者。他擅长Web领域应用、移动应用以及机器学习等的开发,也从事过多个大型软件项目的设计、开发与项目管理。目前他专注与云计算以及互联网等技术领域,致力于帮助中国的 开发者构建基于云计算的新一代的互联网应用。