文|应用漏洞扫描Oteam、PCG安全团队 Martinzhou

I. 背景

当前,各类开放平台、依托云原生技术模式的PaaS/SaaS服务涌现,密钥(Credentials / Secrets)成了跨服务、跨平台调用认证的关键一环。短短几十个字符,背后往往通向上万台CVM或者整个业务数据。好似露出洋面的一角冰山,稍往下深挖,底下可能就是牵动企业安全命脉的“金山银山”。

当前,针对个人用户登录密码的保护技术日臻成熟,基于短信验证码、指纹、人脸或是物理设备的多因子验证获得较为广泛的落地。但用于服务与服务间认证的密钥,往往未获得同等力度的安全保护。

针对上述与应用密钥有关的风险,本文将从研发及数据安全视角,结合近期实践,从四方面探讨可采取的治理思路,以求抛砖引玉,也欢迎大家参与共建,共同探索。阅读本文,你将收获:

有哪些存在风险的敏感密钥?

如何检测敏感密钥泄露?

开发人员如何安全地使用密钥?

业务系统如何安全地设计密钥?

II. 密钥安全四问

2.1 有哪些存在风险的敏感密钥?

知己知彼、百战不殆。在着手扫描清查密钥风险前,可以先对业界各类常见的密钥类型做梳理。否则容易陷入疲于应对已暴露密钥,case by case添加规则。基于我们的实践,分享可参考分类思路如下:

值得一提的是,各企业内部可能也建设了一系列PaaS、SaaS平台,可根据自身实际情况酌情梳理、纳入风险评估。

接着,就需要评估已梳理各类密钥关联的风险(如,会导致数据被匿名访问)及检测特征(如,密钥自身存在的显著特征,详参见2.2.1部分讨论)。梳理思路可以表格形式记录,参考如下:

2.2 如何检测敏感密钥泄露?

2.2.1 敏感密钥概况

场景一、匹配密钥本身的特定格式

密钥本身有很强的特定格式,可以直接用正则匹配。例如,

    腾讯云appid会以AKID开头,例如:AKIDxxxxGithub服务间相互调用的密钥以ghs开头,例如:ghs_tVGHE4***666222

    匹配方式简单直白 —— 写正则匹配密钥本身。例如,针对在代码中硬编码腾讯云密钥的风险,使用开源静态代码检查工具semgrep,不难快速编写出扫描规则:

      pattern-regex: (AKID)(?i)[a-zA-Z0-9]{32}\\\\bpattern-not-regex: q-ak.+(AKID)(?i)[a-zA-Z0-9]{32}

      场景二、匹配密钥及所处的代码结构

      现实场景中我们会发现,绝大部分密钥本身没有很强的特征,例如:大部分数据库的账密可以是任意ascii可见字符,但随代码硬编码却比较常见。

      以数据库账密泄露排查为例,根据经验,我们得出三类大规模匹配检索思路:

      1)匹配含密钥的数据源声明链接

        Go语言中的DNS链接,如:redis://:@127.0.0.1:6380/test?is_proxy=trueJava JDBC链接,如:jdbc:mysql://127.0.0.1:3306/db_xxx?user=&password=&useUnicode=true&characterEncoding=UTF8

        2)与密钥关联的特性API/域名、IP+端口特征

          内部以名字服务形式声明的数据库地址,如:db.foo.com:3306

          3)代码结构中有明确的sink点特征,通过追踪回溯source点,可判断变量值是否是字符串或常量等硬编码形式。例如,Python声明mysql连接的方法

            db = pymysql.connect(host="localhost", user="testuser", password="test123", database="TESTDB")

            场景三、密钥的模糊泛匹配

            除上述两类有较明显规律可循的场景外,不少硬编码密钥的代码结构更为松散,这时候还可以尝试编写一些模糊泛匹配规则,以增强清查效果。

            根据前期实践经验,敏感密钥通常会分布于三类场景中:

            各类源代码文件,如:go、java等

            配置文件,如:yaml、toml等

            其他类文件,如:markdown、csv、Dockerfile等

            编写敏感密钥的规则时,同样拆分成三大部分:

            键(Key),通常匹配是否包含特定关键词,如token、psw、password等;

            分隔符,通常匹配不同编程语言中的分隔符,如:=>、:、=等;

            值(Value),通常匹配特定的密钥字符集范围及长度

            2.2.2 检测手段及工具

            结合上述对密钥的分析,我们将可以选用的手段及工具概括如下:

            业界可供参考的敏感密钥扫描工具分类推荐如下:

            1)trufflehog

            项目地址:

            https://github.com/trufflesecurity/truffleHog

            检测思路:取长度大于20的魔术字符串,再匹配规则

            支持范围:多语言

            2)whispers

            项目地址:

            https://github.com/Skyscanner/whispers

            检测思路:正则

            支持范围:多语言

            3)credential-digger

            项目地址:

            https://github.com/SAP/credential-digger

            检测思路:机器学习

            支持范围:多语言

            4)hardcores

            项目地址:

            https://github.com/s0md3v/hardcodes

            检测思路:正则

            支持范围:多语言

            5)gitleaks

            项目地址:

            https://github.com/zricethezav/gitleaks

            检测思路:正则

            支持范围:多语言

            2.2.3 DevOps流程嵌入

            基于对历史安全事件的复盘,我们发现密钥有可能在研发流程的任一环节泄漏并产生风险。因此,比较合适采用“洋葱式”层层检查设防、运营收敛:

            密钥异常行为检测

            除在软件研发生命周期的各环节匹配检测各类密钥外,还可以结合密钥的HTTP访问日志建立调用请求行为的基线特征,识别异常的密钥调用。

            例如:如果发现某类云平台的密钥调用来源IP的城市分布超过特定数值,则可以推测可能被错误地硬编码在APP/小程序客户端对外发布,存在安全风险。

            2.3 开发人员如何安全地使用密钥?

            2.3.1 综述

            简单来说,安全地在应用中使用密钥有两大原则:一是安全地使用密钥;二是当生产环境应用代码中涉及多个密钥时,应考虑使用KMS类方案集中托管并定期轮换。

            其中,安全使用密钥遵循以下原则:

            1)权限最小化,缩小关联的权限、缩短有效期、专钥专用,例如:部分云平台提供的STS密钥(Security Token Service)

            2)为密钥设置IP/PMS调用白名单

            3)为密钥传输启用TLS,防止中间人劫持窃取

            4)密钥定期轮换并保持资产负责人准确

            5)使用密钥托管平台托管系统(KMS)

            下面将以腾讯业务生态下两种最常见的密钥为例,介绍相关安全开发方式。

            2.3.2 安全开发示例分析

            * 以下仅为举例说明,非真实案例。

            1)微信开放平台密钥

            最常见风险场景是,为了实现用户微信登录的功能,将微信开放平台的secret直接硬编码在APP、HTML5页面及小程序等源代码可被直接接触的代码环境中。

            在此场景下,安全的开发方式为:

            1、客户端仅携带appid,由应用在服务器侧保存appsecret;

            2、应用发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到我们自己的第三方应用,并且带上授权临时票据code参数;

            3、服务器将appid + appsecret + 临时票据code发往微信开放平台,换取当前用户的access_token;

            4、微信开放平台返回access_token给服务器,该凭据应由第三方应用服务器代用户保管与当前用户的登录态绑定。

            值得一提的是,如果开发者已经使用了上述不安全的编码方式,或应用下架密钥已无需使用,应及时登录微信开放平台重置并替换或注销密钥。

            * 以下仅为举例说明,非真实案例。

            2)腾讯云密钥

            最常见风险场景是,为了在小程序、客户端中调用云产品的功能,开发者直接将常规云密钥AK/SK硬编码在产品中。此类密钥往往绑定的不止一类云资源,甚至关联了CVM、CLB等关键资产。云场景下两类常见密钥的区别概括如下:

            其常见的风险是误将高权限的常规密钥,包含在APP、网页或小程序中,可被外部攻击者窃取。

            安全的开发方式,以在前端或小程序向COS存储桶直传文件开发场景为例,可概述为:创建STS临时密钥(临时访问凭证)。其核心在于:1⃣️限制可操作的对象;2⃣️限制对存储桶允许执行的操作

              // 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径// 列举几种典型的前缀授权场景:// 1、允许访问所有对象:"*"// 2、允许访问指定的对象:"a/a1.txt", "b/b1.txt"// 3、允许访问指定前缀的对象:"a*", "a/*", "b/*"// 如果填写了“*”,将允许用户访问所有资源;除非业务需要,否则请按照最小权限原则授予用户相应的访问权限范围。config.put("allowPrefixes",new String[] { "exampleobject", "exampleobject2"});// 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。// 简单上传、表单上传和分块上传需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923String[] allowActions =new String[] { // 简单上传 "name/cos:PutObject", // 表单上传、小程序上传 "name/cos:PostObject", // 分块上传 "name/cos:InitiateMultipartUpload", "name/cos:ListMultipartUploads", "name/cos:ListParts", "name/cos:UploadPart", "name/cos:CompleteMultipartUpload"};config.put("allowActions", allowActions);

              2.4 平台系统如何安全地设计密钥?

              如果你正运营着开放平台,自身就是密钥的提供方,则需要注意以下几点:

              1)密钥的appid或secret在格式上必须具备明显、可区分的特征

              2)遵循“权限最小化”原则,平台应为开发者提供密钥安全加固功能。包括但不限于:允许开发者重置密钥、为密钥设置IP调用来源、允许设置密钥关联的接口权限等

              3)除明文账密外,为服务端应用密钥启用引入MFA机制

              2.4.1 密钥自身的设计

              2021年Github工程团队在其技术博客中宣布重构其开放API关联的密钥结构。由于旧密钥仅为一串特定长度的字母数字组合,容易与其他哈希值混淆产生误报,增加了密钥扫描的难度。

              通过引入gh等一系列前缀,按功能从密钥本身设计区分出不同功能场景,使安全扫描排查更简单。其差异对比如下:

              2.4.2 密钥管理功能设计

              同时,如果平台系统提供的API要带密钥,应至少具备以下安全能力,供开发者自行配置使用:

              1)允许设置调用来源IP白名单

              2)调用频控限制

              3)禁用或重置密钥能力

              2.4.3 提供MFA机制

              除上述围绕密钥自身安全设计、密钥安全加固功能外,也可以考虑为服务端应用密钥引入MFA机制。业界也不乏已落地机制参考,例如:MySQL企业版提供的LDAP、FIDO认证插件,参见《LDAP Pluggable Authentication》,https://dev.mysql.com/doc/refman/8.0/en/ldap-pluggable-authentication.html

              III. 总结

              密钥虽不起眼,但应用背后的应用资产和数据的安全往往悬于短短几十个字符间。本文尝试从密钥使用和提供两方视角入手,探讨各环节和场景下的密钥安全综合治理。整体可概括为:

              平台系统作为密钥提供方

              1)密钥的appid或secret在格式上必须具备明显、可区分的特征

              2)平台为开发者提供了密钥调用提供加固机制,包括但不限于:允许开发者重置密钥、为密钥设置IP调用来源等

              平台系统作为密钥使用方

              1)已引入安全工具对扫描代码仓库/制品/Web接口等渠道,进行密钥泄露检查

              2)已遵循第三方开放平台提供的最佳安全实践在系统中使用密钥;或使用配置中心或KMS密钥托管系统,单独存储密钥并定期轮换

              过程中诸多事宜乍看轻松,实践中却会有诸多考量点,应用漏洞扫描Oteam、PCG安全团队、腾讯安全朱雀实验室等团队也在持续探索密钥安全治理的落地方案,欢迎大家留言交流。

              # 参考资料

              [1] Access Keys Will Kill You: Before You Kill The Password,

              https://www.blackhat.com/docs/us-16/materials/us-16-Simon-Access-Keys-Will-Kill-You-Before-You-Kill-The-Password.pdf

              [2] Behind GitHub’s new authentication token formats

              https://github.blog/2021-04-05-behind-githubs-new-authentication-token-formats/

              [3] Detecting Credential Compromise in AWS,

              https://i.blackhat.com/us-18/Wed-August-8/us-18-Bengtson-Detecting-Credential-Compromise-In-AWS.pdf

              # 团队介绍

              应用漏洞扫描Oteam,由公司各BG安全团队联合组成,专注于构建自动化安全系统为腾讯业务保驾护航。目前,运营有Web漏洞、高危服务、代码漏洞、客户端安全、云PaaS服务及制品相关的系列大型自动化安全系统。

              PCG技术安全团队,隶属于平台与内容事业群的技术平台线,主要负责为事业群下属社交、视频、信息流服务等重点业务产品提供一对一的应用及数据安全保障,以及DevSecOps和纵深防御体系的探索实践。同时,也致力于与公司内部其他安全团队一起协同建设安全能力及系统,并将相关经验与业界交流分享。

              声明:本文来自腾讯安全应急响应中心,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。