JFrog的安全扫描器发现了数千个公开暴露的API令牌——它们是活跃的!报告全文
JFrog高级安全系列-秘密检测

注:本报告是之前发表在InfoWorld上
在开发最近宣布的JFrog高级安全时,我们的研究团队决定尝试一下它的新的“秘密探测”功能。我们的目标是在尽可能多的真实世界数据上测试我们的漏洞检测,以确保我们消除误报并捕获代码中的任何错误。
随着我们继续测试,我们意识到确实存在更多已识别的活动访问令牌超过预期。我们将测试扩展到全面的研究,以了解这些代币的来源,使用它们的可行性,并能够私下向其所有者披露它们。在这篇博客文章中,我们将展示我们的研究结果,并分享避免导致这些访问令牌暴露的确切问题的最佳实践。
访问令牌——它们都是关于什么的?
云服务已经成为现代计算的代名词,很难想象在不依赖它们的情况下运行任何可扩展的工作负载。使用这些服务的好处是伴随着将我们的数据委托给外部机器和责任的风险管理为我们的数据和服务提供访问权限的访问令牌。暴露这些访问令牌可能会导致可怕的后果——最近的一个例子是史上最大的数据泄露由于访问令牌泄露,泄露了10亿条包含PII(个人身份信息)的记录。
与存在代码漏洞不同,泄露的访问令牌通常意味着安全团队立即“游戏结束”,因为使用泄露的访问令牌是微不足道的,并且在许多情况下否定了对安全缓解的所有投资。只要密码写在门上保险库的锁再复杂也没用。
云服务有意为其访问令牌添加标识符,以便其服务可以对令牌执行快速有效性检查,这样做的副作用是使检测这些令牌非常容易,即使在扫描非常大量的无组织数据时也是如此。
| 平台 | 例子令牌 |
| AWS | AKIAIOSFODNN7EXAMPLE |
| GitHub | gho_16 c7e42f292c6912e7710c838347ae178b4a |
| GitLab | gplat-234年hcand9q289rba89dghqa892agbd89arg2854 |
| NPM | npm_1234567890 abcdefgh |
| 松弛 | xoxp -123234234235 - 123234234235 - 123234234235 - adedce74748c3844747aed48499bb |
我们扫描了哪些开源存储库?
我们扫描了最常见的开源软件注册表中的工件:NPM, PyPI, RubyGems, crate。io和DockerHub(两者都是)Dockerfiles和小Docker层)。
总之,超过800万件文物被扫描。
在每个工件中,我们使用秘密检测找到易于验证的令牌。
作为我们研究的一部分,我们对每个发现的令牌都做了一个最小的请求
- 检查令牌是否仍处于活动状态(未因任何原因被撤销或公开不可用)
- 理解令牌的权限
- 了解代币的所有者(只要可能),这样我们就可以私下向他们披露这个问题
对于npm和PyPI,我们还扫描了同一个包的多个版本,试图找到曾经可用但在后续版本中删除的令牌。

每个平台分析的工件(以百万计)
“活跃”代币与“非活跃”代币
如上所述,静态检测到的每个令牌也通过动态验证运行。这意味着,例如—尝试访问一个API,它对令牌所属的相关服务不做任何事情(no-op),只是为了查看令牌是否“可用”。通过此测试的令牌(“活动”令牌)可供攻击者使用,没有任何进一步的限制。
我们将动态验证的令牌称为“活动”令牌,而未通过动态验证的令牌称为“非活动”令牌。请注意,令牌显示为“非活动”可能有很多原因
- 令牌被撤销
- 令牌是有效的,但对使用它有额外的限制(例如,必须从特定的源IP范围使用)
- 令牌本身并不是一个真正的令牌,而是一个“看起来像”令牌的表达式(误报)
哪个存储库泄露的令牌最多?
我们想要回答的第一个问题是“是否存在开发人员最可能泄露令牌的特定平台?”
从泄露的秘密的数量来看,开发人员在构建他们的码头工人的图片(请参阅下面的“示例”部分以获得有关此方面的指导)-

所有令牌(活动+非活动)在平台之间的分布
我们假设绝大多数DockerHub泄漏是由平台的封闭性造成的。虽然其他平台允许开发人员设置到源存储库的链接,并从社区获得安全反馈,但进入DockerHub的代价更高——特别是研究人员必须拉出Docker映像并手动探索它,可能要处理二进制文件,而不仅仅是源代码。
DockerHub的另一个问题是,没有公开显示每个图像的联系信息,所以即使白帽研究人员发现了泄露的秘密,也可能不会向图像维护者报告这个问题。因此,我们可以观察到多年来保留暴露的秘密或其他类型安全问题的图像。
下图显示,与所有其他存储库相比,在DockerHub层中发现的令牌处于活动状态的可能性要高得多。

按存储库划分的活动/非活动令牌数量
最后,我们还可以查看按每个平台扫描的工件数量标准化的令牌分布
存储库之间所有令牌的分布,每个令牌都标准化为该存储库扫描的工件数量
忽略每个平台扫描工件的数量,并将重点放在相对泄露的令牌数量,我们可以看到DockerHub层仍然提供了最多的令牌,但第二名现在由PyPI声称(而当查看绝对数据时,PyPI的令牌泄露量排名第四)。
哪些令牌类型泄露最多?
在对秘密检测支持的所有令牌类型进行扫描并动态验证后,前10名的结果为-
每个存储库的活动/非活动令牌分布
我们可以清楚地看到,AWS、GCP和Telegram API令牌是泄露最多的令牌(按此顺序),然而,AWS开发人员似乎对撤销未使用的令牌更加警惕,因为只有47%的AWS令牌被发现是活跃的,而GCP的活跃率为73%!
每个存储库中泄露的机密示例
查看来自每个存储库的一些真实示例非常重要,以便提高对令牌泄露的潜在位置的认识。在本节中,我们将重点关注这些示例,在下一节中,我们将分享如何处理这些示例的技巧。
DockerHub - Docker层
检查Docker层中存在的文件名和包含泄漏凭据的文件名显示,最常见的泄漏源是使用dotenv包将凭据存储在环境变量中。第二个最常见的来源是硬编码的AWS令牌
| 文件名 | 具有活动泄漏令牌的实例数 |
| .env | 214 |
| / aws /凭证 | 111 |
| json | 56 |
| gc_api_file.json | 50 |
| main.py | 47 |
| key.json | 40 |
| config.py | 38 |
| credentials.json | 35 |
| bot.py | 35 |
Docker层中包含泄漏令牌的最常见文件名
可以通过拉取映像并运行它来检查Docker层,但是在某些情况下一个秘密可能已经被中间层删除了(通过“whiteout”文件),在这种情况下,当检查最终的docker映像时,秘密不会显示。可以使用工具单独检查每一层潜水,并在“删除”文件-中找到秘密

Docker层,凭证在潜水层检查员
检查“凭据”文件的内容,可以发现泄露的令牌

AWS凭证通过。/ AWS /credentials泄露
DockerHub - Dockerfiles
DockerHub在我们的研究中处于领先地位,包含超过80%的泄露凭据。
开发人员通常使用Dockerfiles中的秘密来初始化环境变量,并将它们传递给在容器中运行的应用程序。图片发布后,这些秘密就被公开泄露了

AWS凭证通过Dockerfile环境变量泄露
另一个常见的选择是在Dockerfile命令中使用secrets,用于下载设置Docker应用程序所需的内容。下面的示例显示了容器如何使用身份验证密钥将存储库克隆到容器中

通过“git clone”命令通过Dockerfile泄露AWS凭证
crates.io
与crates.io(Rust包管理器),我们高兴地看到了与所有其他存储库不同的结果。尽管x射线检测到近700个包含秘密的包裹,只有一个把这些秘密表现得活跃起来!有趣的是,这个秘密甚至没有在代码中使用,而是作为注释-的一部分被发现

PyPI
在我们的PyPI扫描中,在实际的Python代码中发现了大多数令牌泄漏。
例如,受影响项目中的一个函数包含AWS RDS令牌。如果令牌只允许查询示例RDS数据库的访问,那么这样存储令牌是可以的。然而,当收集令牌的权限时,可以看到令牌可以访问整个AWS账户(在我们向项目维护者披露后,该令牌已被撤销)。

PyPI包源代码中的AWS令牌泄漏

对“示例”AWS RDS令牌的意外完全管理权限(*/*)
npm
除了在Node.js代码中硬编码的令牌之外,npm包还可以在.js中定义自定义脚本脚本块package.json文件。这允许运行由包维护者定义的脚本来响应某些触发器,比如正在构建、安装的包等。
一个反复出现的错误是将令牌存储在脚本在开发期间阻塞,但在包发布时忘记删除令牌。在下面的例子中,我们看到了编译工具使用的泄露的npm和GitHub令牌semantic-release。
NPM " scripts "块中的NPM令牌泄漏(package.json)
通常,dotenv包装应该解决这个问题。它允许开发人员创建一个名为.env在项目的根目录中,并使用它来填充测试环境中的环境变量。以正确的方式使用这个包可以解决秘密泄漏,但不幸的是,我们已经看到了这一点对dotenv包的不当使用成为泄露秘密最常见的原因之一在PyPI包中。尽管包文档明确指出不要将.env文件提交到版本控制,但我们发现许多包中.env文件被发布到npm并包含秘密。
“没有。我们强烈建议不要将.env文件提交到版本控制系统。它应该只包含特定于环境的值,比如数据库密码或API密钥。您的生产数据库应该使用与开发数据库不同的密码。”
Dotenv文档警告发布.env文件
RubyGems
回顾一下RubyGems包中检测到的结果,没有特别的异常值。检测到的秘密可以在Ruby代码中找到,也可以在Gem中的任意配置文件中找到。
例如,在这里我们可以看到一个泄露敏感令牌的AWS配置YAML。该文件应该是AWS配置的占位符,但开发部分使用实时访问/秘密密钥进行了更改

spec/dummy/config/ AWS .yml中的AWS令牌泄漏
存储令牌时最常见的错误
在分析了我们发现的所有活动案例之后,我们可以强调开发人员应该注意的以下错误,并分享一些关于如何以更安全的方式存储令牌的指导方针。
错误#1 -没有使用自动化检查秘密曝光
在很多情况下,活动秘密位于非常意想不到的地方:代码注释、文档文件、示例或测试用例。这些地方很难以一致的方式手工检查。我们建议在DevOps管道中嵌入一个秘密扫描器,并在发布新版本之前对泄漏发出警报。有许多免费的开源工具提供这种功能。我们的OSS建议之一是trufflehog,它支持大量秘密并动态验证发现,从而减少误报。
对于更复杂的管道和广泛的集成支持,我们提供JFrog x光。

一个GitHub令牌在文档中泄露,原本是只读的,但实际上给予了完全的编辑权限
错误#2 -生成具有永远不会过期的广泛权限的令牌
大多数云服务允许在生成访问令牌时设置细粒度的范围和权限

GitHub的个人访问令牌生成屏幕,具有细粒度令牌权限
不幸的是,我们观察到一种非常常见的反模式,即生成具有完全管理权限的单个令牌
具有管理权限与受限权限的AWS令牌
我们发现的活跃AWS令牌中有25%有完整的管理功能!
由于IAM权限模型中可能的权限列表长而复杂,因此为AWS访问令牌设置IAM权限是一项艰巨的任务。在许多情况下,我们观察到使用通配符的令牌,例如-s3: *而不是添乱s3: ListBucket和s3: GetObject单独的权限。对于不需要文档的用户,AWS提供了一组“完全管理”权限,标记为* / *,允许无限制地访问所有可能的功能。
当令牌泄露时,攻击者可以访问用户的整个AWS基础设施,而不是开发人员使用AWS令牌从S3存储桶下载图片。
我们建议使用最少特权原则,只授予执行任务所需的权限。在确定范围和选择匹配的权限上投入时间比在将来进行数据泄露调查更好。
除了赋予令牌的权限之外,还可以设置一个截止日期在令牌上确保令牌的“长期丢失”实例是无用的,即使令牌在将来泄露。
错误#3 -秘密没有访问控制
在许多情况下,开发人员可能会在某个地方使用硬编码令牌,因为他们认为没有其他方法可以调节对该令牌的访问。在更好的例子中,这个令牌具有它需要的确切权限集,因此将它暴露给每个人都不是问题。然而,并不是所有的云服务都支持令牌所需的确切权限集,在这种情况下,公开令牌是一个问题。
例如,将API秘密保存在环境变量。这在本地开发环境中绝对是安全的。但是,当涉及到云服务,特别是那些在公共存储库中发布的云服务时,任何人都可以获得这些秘密

AWS凭证通过Dockerfile环境变量泄露
幸运的是,可以应用一些审核工具,以确保只有经过验证的用户才能访问令牌。下面是一些与基于docker的环境相关的示例
- Kubernetes秘密(适用于基于k8的应用程序)
- 码头工人的秘密(用于Docker Swarm服务)
- 要求用户提供密钥作为码头工人运行论点
- Hashicorp库(外部工具,适用于许多运行时环境)
这些工具的共同点是,秘密是没有硬编码存储在图像中,而秘密是外部获取在运行时,在验证客户端具有使用该密钥的正确授权之后。这意味着当图像本身被曝光时,秘密并没有被曝光。这种间接级别还有助于在秘密旋转之后保持图像平稳运行,因为图像和秘密彼此之间没有紧密耦合。
错误#4 -通过取消发布令牌来修复泄漏
由于令牌泄漏是一个安全漏洞,因此想到的幼稚解决方案是从代码中删除密钥并发布新的“固定”版本,与CVE相同。然而,互联网永远记得。一旦包在存储库中发布,它可以被许多不同的合法和非法参与者自动缓存。这些演员仍然可以访问包即使它没有从原始来源发布。
在现实世界中,当你丢了钥匙,你要做的第一件事就是换锁。通过类比,当您丢失API密钥时,您应该立即撤销并替换它。

在包的1.1.1版本中,秘密令牌在.env文件中泄露。通过在1.1.2版本上取消发布来“修复”
错误5 -公开不必要的资产
我们检测到的许多带有泄露令牌的图像,看起来都不属于公共存储库。内部测试映像、公司开发构建和其他私有软件包到达了知名的公共存储库,并随之暴露了敏感机密。
例如-一个Docker映像包含测试在Docker Hub上发布了一个区块链相关框架

在docker映像中,通过使用硬编码的GitHub访问令牌-@@来提取私有存储库GitHub存储库

这很糟糕,因为这个私有GitHub存储库现在可以被不需要的各方拉出,但它变得更糟-这个GitHub令牌给予完全的管理权限到GitHub帐户,公开所有私有存储库,并提供对框架网站的完整访问权限。
虽然这里有很多错误,但基本的问题是这个内部测试容器不应该被发布在公共DockerHub注册表上。
默认情况下,许多开发工具使用公开可用且易于抓取的集中式存储库。一些公司可能选择依赖这些中央存储库,而不滚动自己的私有实例,这使得公司资产在发布工件时更加暴露。
幸运的是,对于我们扫描的每个存储库,都有OSS解决方案可以轻松部署您自己的私有存储库
- 码头工人,港cncf分级集装箱注册吗
- PyPI -private-pypi允许私下部署PyPI索引
- npm -Verdaccio是一个轻量级的Node.js私有代理注册表
- RubyGems -一个官方指南由RubyGems强调了几个解决方案,如Gemstash
- crates.io–crates.io本身就是一个OSS项目,可以很容易地部署
对于需要支持多种类型的工件的不同环境,我们提供了顶级的DevOps功能JFrog Artifactory。
回馈OSS社区
虽然我们研究的最初目标是在Xray的新秘密检测工具中发现并修复假阳性,但我们偶然发现了比我们最初设想的更多的活跃秘密。为了完成这项研究,我们私下披露所有泄露的秘密都交给各自的所有者(当所有者可以被识别时),以便根据需要替换或撤销这些秘密。
秘密检测-由JFrog x射线供电
这项研究是由新的“秘密检测”功能,包括在最近宣布的JFrog高级安全JFrog Xray的一组功能。该版本将JFrog Xray从熟悉的软件组合分析领域带到了高级软件供应链安全领域。
秘密检测可以发现应用程序代码中暴露的秘密,如明文API密钥、凭据、过期证书或密码,这些秘密通常会被遗忘并在无意中暴露。这些暴露的秘密可能对软件的完整性构成严重威胁,并可能邀请不法分子进入您的应用程序访问机密信息和数据,甚至访问专用网络。
- 扫描代码库以发现这些秘密,并在接近生产环境之前减轻它们。
- 设置可配置的自动策略,当在应用程序代码中发现任何秘密时,将生成违规行为。
- 使用增强的补救数据缓解快速发现的任何秘密,这些数据解释了发现了什么、为什么重要、在生产中暴露该秘密可能产生的影响,以及如何最好地修复它。

