密码是对服务、系统和数据的访问权限进行授权的数字身份凭证,常见的密码有API密钥、非对称私钥、访问Token等。硬编码密码(Hardcoded Secret),或称嵌入式密码(Embedded Secret),是指将密码以明文方式直接写入代码中。这种处理方式极大地提高了攻击者命中密码的概率,使服务或系统暴露在风险中,容易造成严重损失。针对此问题,本文详细讨论了硬编码密码的成因、危害及治理方法;另外,本文从安全人员角度出发,对现有的硬编码密码检测工具的算法进行了深入调研,并提出了我们的自动化检测工具。

01硬编码密码的成因及类型

随着互联网组织转向云架构、SaaS 平台和微服务,密码等数字身份验证凭证的数量和多样性正在快速增长。与此同时,企业也不断推动更短的发布周期,开发人员面临巨大时间压力的同时,需要处理的密码量比以往任何时候都多。许多开发人员采取捷径,选择使用硬编码的方式处理密码。

在企业的代码仓库中普遍存在大量的硬编码密码问题。据GitGuardian统计,在公共Git存储库上每天会泄露数以千计的密码,其中仅2020年就有超过200万个密码被上传至Git存储库中[1],而2021年该组织发现的密码数量超过600万,同比增长近2倍[2],而私人存储库的密码泄露事件存在可能性比公共库高4倍。

根据统计[1][2][6],硬编码密码包括API密钥、访问Token、非对称私钥、认证ID、安全证书、口令、特权用户账户等类型。硬编码密码所涉及的平台十分广泛,包括如下领域:开发工具,如Django、Rapid API;数据存储,如MySQL、Mongo;金融服务,如PayPal、Amazon MWS;消息通讯系统,如Gmail、Telegram;云提供商,如AWS、Azure、Google;私钥;社交媒体,如Twitter、Facebook;版本控制平台,如Github、Gitlab;等等。

除了程序代码中,这些硬编码还容易出现在基础设施配置文件、监控日志、运行日志、堆栈调试track记录、git历史中。所有类别的硬编码密码都使企业暴露在攻击之下。

02硬编码密码的危害

硬编码密码主要对安全和研发两方面具有危害:

1. 削弱系统安全性 

攻击者常通过公共代码库或反编译分析获得硬编码密码字符串,利用密码访问敏感数据或获取敏感操作权限。攻击者还可以进一步扩大攻击范围,进行数据勒索、帐户操纵、帐户创建、通过用户数据进行利用等,使得企业和用户都遭受严重损失。在以下案例中,攻击均是从密码的泄露开始的:2014年,Uber数据库被未经授权访问,导致数千名Uber司机私人信息的数据被泄露[7];2016年,Uber又因外部的未授权访问导致5700万用户的个人信息被泄露;2018年,Github和Twitter[10]在内部日志系统中以明文方式存储密码,分别涉及2700万和3.3亿用户数据泄露;2020年,用户在Github仓库中发现了星巴克的API密钥,涉及重大信息泄露[8];2021年,黑客组织 Sakura Samurai 在一次重大数据泄露事件中获得了访问联合国 (UN) 员工私人数据和系统的权限[9]……由硬编码密码导致的安全事故层出不穷,也不断有相关CVE和CWE被披露。

硬编码密码对特定设备、固件、服务、应用程序本身,对其连接的IT生态系统其他部分,甚至使用服务的第三方都存在风险,使其同样暴露在风险中。

2. 不易于程序维护 

硬编码密码的修复较为困难,密码一旦被利用无法轻易被修正。对于正在线上运行的服务或系统,修复硬编码密码问题需要停服重新发布。大型企业的服务流量较大,服务间还存在依赖,则需要灰度发布,修复流程更长,其间可能持续受到攻击者威胁。

密码的蔓延也使维护变得困难。与传统凭证不同,密码旨在分发给开发人员、应用程序和基础设施系统,这将不可避免地使开发中使用的密码数量增加,一个密码可能出现在代码中多处位置,这进一步增加了修复的难度。

此外,开源的代码造成密码泄露,即使在源码中删除硬编码密码,也会残留在git历史里。

03如何治理硬编码密码

企业代码中的硬编码密码问题日益严重,只有通过安全人员和研发人员的共同协作才能解决。源代码中的密码泄露很难彻底避免,但与其他漏洞一样,它完全由内生因素决定:开发人员需要访问更多的资源,以更快的速度构建和部署。这意味着只要有足够的纪律和教育,再加上正确的工具,就有可能大幅改善这种情况。

从开发人员角度,需要注意尽量避免将密码以明文形式写入代码中。代码中需要对密码进行校验时,对入站身份验证可使用强单向散列函数进行密码模糊化,并将这些散列结果存储在具有适当访问控制的配置文件或数据库中;对出站身份验证,可将密码存储在代码之外的一个经过严格保护的、加密的配置文件或数据库中,该配置文件或数据库不会被所有外部人员访问,包括同一系统上的其他本地用户[13];大型企业可以使用KMS服务进行一站式密码管理。

从安全人员角度,应尽量做到风险左移,尽早发现密码泄露,帮助开发人员降低修复成本。可通过代码检测扫描,将硬编码密码检测集成到开发工作流程中,提前发现硬编码密码问题。

04硬编码密码检测算法

由于硬编码密码有如此的危险性,学术界和工业界都有许多组织针对此问题研发了代码扫描工具。我们对开源工具和学术文章进行了一系列调研,总结了目前的硬编码密码扫描工具常用的检测算法,并对其优缺点进行了讨论。

4.1 正则表达式匹配

正则表达式通常被用来检索符合某种模式的字符串。对于检测具有固定结构或特征的密码,正则表达式可能很有效。常用于密码检测的正则表达式可分为(1)针对各种特定平台密码的表达式和(2)不针对任何平台的通用表达式。

(1)针对各种特定平台密码的表达式 

许多平台的API密钥、访问Token、认证ID等具有平台独有的特征,例如亚马逊AWS密钥均以“AKIA”字符串开头;常用于非对称加密的私钥如RSA、EC、PGP及通用私钥等,常由ssh-keygen、openssl等工具生成,多数情况下私钥以单独的PEM等文件格式存储,其内容也具有一定特征,例如RSA私钥文件由"-----BEGIN RSA PRIVATE KEY-----"字符串作为开头。对于这类密码,可以通过匹配具有其特征的正则表达式进行检测。

下表列举了部分常用平台密码的类型以及正则表达式。本文仅以此表举例,实际上特定平台的密码种类十分丰富,此处不便一一列举。

平台