防拖库的最佳实践

“拖库”,就是数据库被黑客整个拖下来。脸红的说,这个事射手也遇到过。

我信奉不能被同样的招数打败两次。所以最近再做项目时,我又仔细研究了一下,如何防止开发人员把数据库密码写在代码中,以免数据被拖库的方案。

先分析华住的拖库事件,这类安全风险背后的关键因素主要来自:

  • 开发人员需要在开发过程中进行测试,这些测试会需要连接数据库
  • 开发人员会有连接到生产数据库进行调试的需求
  • 使用的版本管理工具,会将所有代码历史修改都记录并保留

与上述因素相对应的,在传统开发模式下,产生的安全渗透点就会很多:

  • 当开发人员需要调试数据库时,会将数据库密码写入代码,甚至生产环境也是这样
  • 特别是在 PHP 这类很方便修改的脚本语言中,在线修改生产环境的代码,是一些团队的常见行为
  • 当开发人员调试过程中使用版本管理工具提交,就会将各种密码在代码仓库中记录下来。而这些记录在以 Git 为代表的分布式代码仓库中,不会消失

在这种传统的开发模式下,唯一的技术性安全措施,只能是通过数据仓库私有化,来保护代码和代码中的密码秘钥。

但是,墨菲定律说,如果一件事有可能会发生,就一定会发生。我们很难保证在每台个人开发设备上都留存了副本的分布式代码仓库永远不会被泄露。所以,将数据库等密码写在代码中,是不可取且安全风险极大的。


近代的开发模式,会通过配置文件保存数据库密码到配置文件,再利用 .gitignore 将配置文件排除在代码仓库之外,避免开发人员将含有密码的配置文件提交到代码仓库。

但是,这种模式也有它的问题:

  • 开发人员还是可以轻易拿到数据库密码
  • 密码以文件形式存储在本地和服务器
  • 结构上仍很难避免开发人员将数据库密码直接写到代码中以方便调试
  • 如果配置文件排除在代码仓库管理之外,那么配置文件的格式升级,就比较难管理。如果有配置文件没被排除在代码仓库之外,那么安全风险接近将密码写入代码

而且,现代开发方法中倡导CI/CD(持续集成/持续部署),也会带来一些不尽方便的地方:

  • 配置文件需要另外设法更新到 CI/CD 配置中
  • 配置文件的修改依赖额外的工作人员管理
  • 一些运维人员会习惯性将配置文件也纳入版本管理

开发流程中的秘钥安全管理就此崩塌。


还有一种方案,是使用环境变量来存储秘钥的。这种管理方法,因为敏感密码不以文件形式存在,所以安全性略好。但是这也有问题:

  • 环境变量对整个操作环境暴露,如果 CI 或生产环境被入侵,获得秘钥的门槛很低
  • 没有操作记录,无法追溯
  • 如果项目比较大,涉及多种数据库密码、秘钥,API凭据等等。使用众多环境变量会变得很难管理

况且,现在的大型项目,不光是数据库密码,还有 OSS/S3 秘钥,各种 API 凭据 Token,TLS证书、公钥、私钥等等。对于传统项目的安全管理挑战非常大。

那么,现在已经2018年了,什么才是开发流程安全的最佳实践? 正好最近借重写射手 API 服务端的机会,对一些新方案仔细调研了一番。

先说结论:现代开发项目应该启用某种专业化的秘钥管理系统(secret management solution),包括 AWS 的 KMS,谷歌的Cloud KMS,HashiCorp 的 Vault,K8S 的 Secret,swarm 的 secret 等等都可以。不过在这些选择中,我个人目前会更推荐使用 HashiCorp 的 Vault 。

vault-logo.png

秘钥管理服务和 Vault 的优点:

  • 秘钥管理服务简单的说,可以看做后端领域的 1Password。首先它会保证秘钥存储安全。不管用哪个黑客,拿到秘钥管理服务的落地数据文件,在没有秘钥的情况下还是不可能解密的。以 Vault 为例,一个 Vault 系统启动时,要使用 5 个 root token 中的至少 3 个对数据进行 Unseal,之后 Vault 才能将秘钥从存储层解密出来提供项目使用
  • 另外从 Vault 获取之前配置的密码、秘钥等关键数据,会需要由管理员分配 Token,对这些分配的 Token,管理员可以制定包括过期、撤销、更新和权限管理等等各种安全策略
  • Vault 的安全级别可以提供面向公网开放的服务,所以可以为开发环境提供一个开发人员的 Vault ,在家或者异地开发也可以很方便
  • 管理员可以随时通过 Vault 更新各个数据服务的安全密码或密钥,也可以随时收回或修改特定 Token 的权限。这在 Rolling out 更新时很有用
  • 使用 Vault 会强制代码通过 Vault 接口来获取各种数据连接密码或秘钥。避免开发人员无意获得和在代码中使用秘钥密码。而且因为 Vault 的管理方式允许,虽然代码只有一份,我们还是可以将不同开发阶段的 Vault 分别管理。甚至可以做到生产环境中只有 1 人有 Vault 管理权限,也不会觉得维护起来很吃力
  • 所有秘钥存取和修改都有日志记录。可以作为事后证据成为被入侵的线索
  • 数据库和API秘钥不再散落在代码各处
  • Vault 服务如果部署正确,可以实现高可用 (HA)

使用秘钥管理方案,为开发带来一个极大的好处。就是项目代码中就只剩一个 Token 是安全敏感的,只要内部开发人员不是怀有恶意的话,是不会接触到密码或秘钥等敏感信息。而这一个 Token 又是可以定时过期和更换的。这样即使 Token 被泄露,也可以做到让黑客没有足够的时间拖库。


2018年了,已经有了很多新工具和新方法,祝我们的项目都不会再因为数据泄露而上新闻。