亚马逊AWS官方博客

如何保护 EC2 上元数据以对抗 SSRF 攻击

可以说数据安全是我们每个人关心的话题,云计算时代更是如此。以往,我们了解的安全事故大多都是由安全漏洞引起的,但是各种层出不穷的的攻击手段花样频出, 在魔与道的对抗中不断的提醒我们-保护好我们的数据。曾经有过的一个案例中, 部署在 AWS 上的开源的 Web 应用程序防火墙(WAF)存在错误的配置。这款名为 “ModSecurity” 的开源 WAF,作为 Apache  Web 服务器的模块部署使用,以提供针对对基于 Web 应用程序安全性的几类漏洞的保护。不幸的是,WAF的配置错误使入侵者可以诱骗防火墙将请求中继到 AWS 平台上的关键后端资源。该资源称为 “元数据” ( metadata) ,其中包括从安全服务发送的当前凭证,以访问该服务器被许可访问的云中的任何资源。在AWS的环境中,这些凭证的权限容取决于分配给请求它们的资源的权限  。在这个案子中,配置错误的 WAF 被分配了太多的权限,即允许它列出任何 S3 数据桶中的所有文件,并允许读取每个文件的内容。感兴趣的可以了解一下这个案例的前因后果。

“ 服务器端请求伪造 ”(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 全部的访问许可。

当运行在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

2、使用 AWS 命令行工具AWSCLI,我们能够验证出 SSRF_Role 正作用于我们所使用的这个 EC2 实例。
命令:

aws ec2 describe-instances --region us-west-1 --query 'Reservations[*].Instances[*].[InstanceId, IamInstanceProfile.Arn]' --output text

3、到目前为止,我们可以看到IMDS正常工作,并且我们能够基于实例的角色执行命令。现在,让我们来得到这个角色的凭证。
命令 :

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/SSRF_Role

4、现在,问题已经出现了。一旦攻击者掌握了这些凭证,他就可以在任何地方(甚至从AWS外部)使用它们。让我们看看如何工作 –
命令:

aws ec2 describe-instances --region us-west-1 --query 'Reservations[*].Instances[*].{Instance:InstanceId,PublicIp:PublicIpAddress,PrivateIp:PrivateIpAddress}'

这几个简单的步骤已经很好地说明了问题。如这个例子,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

注意事项 :

  • 特别强调一下,如果不执行任何操作,则IMDSv1和IMDSv2都可用于EC2实例。这就是说,仅使用IMDSv2的方法并不能改善目前的安全状况。我们必须主动禁用IMDSv1!!
  • 确保实例上使用的新的AWS SDK,使得运行在EC2上的软件都能够支持IMDSv2。例如 boto3aws-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

请注意  “ 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

现在,执行命令后返回的状态为“pending”。我们可以稍后发出一个describe-instances 命令,再来看一下处理的结果 –

如果这时候我们还是使用IMDSv1的方式进行元数据的操作,会发生什么情况?

命令:

curl -v http://169.254.169.254/latest/meta-data/

返回的结果存在一个错误的信息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 

现在,我们得到了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

本篇作者

费良宏

费良宏,AWS Principal Developer Advocate。在过去的20多年一直从事软件架构、程序开发以及技术推广等领域的工作。他经常在各类技术会议上发表演讲进行分享,他还是多个技术社区的热心参与者。他擅长Web领域应用、移动应用以及机器学习等的开发,也从事过多个大型软件项目的设计、开发与项目管理。目前他专注与云计算以及互联网等技术领域,致力于帮助中国的 开发者构建基于云计算的新一代的互联网应用。