青训营项目的可能安全考量 | 青训营笔记

123 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天。

本文以 CC-BY-SA 4.0 发布。

大项目是(迷你)抖音所以让我们严肃点考虑一下安全问题?

SQL 注入

青训营项目的考核标准之一便是服务的安全性。

官方给的一个安全性考量的例子是应用能否预防 SQL 注入。 我最初的想法是只要开发的人合理使用市面上任何一个 ORM 库,那么 SQL 注入肯定不是问题, 因为诸如 ?:named_param 这种的参数绑定都会经过 ORM 的转译处理,不可能出现 SQL 注入。

直到,我无意翻到了一个把数据库操作独立分为一个“微服务”的项目, 其中一个类 UPSERT 的操作是直接通过 SQL 字符串拼接实现的。 这实在是打破了我对 SQL 注入只能出现在 PHP 7 前的时代的想象。 (啊啊啊虽然严格来说没有这样的微服务的。 微服务的思想是每个微服务的数据存储相互独立,而不是独立出来一个数据库服务……)

总之,要预防 SQL 注入的最好方法就是使用库自身的参数绑定,永远不要试图去自己拼接参数。

用户密码储存

凑热闹去看别人家项目的实现时,看到有一个小组的密码储存使用的是 SHA + salt。 这个的确有心了,但是更用点心的话可以查到这种方案不被推荐的原因(security.stackexchange.com/questions/9… SHA 这种通用型 hash 算起来相对快,而密码专用的 hash 都会特意设计成时间、内存开销大的样子以防止暴力破解。 尤其是现在 GPU 算力大幅膨胀的现在, SHA + salt 还有暴力破解的可能,而例如 Argon2 则可以基本把这条路封上。

密钥轮转

很多小组都用了 JWT 进行用户 token 的分发。 这方面当然涉及到 JWT 所用到的签名算法的安全性, 例如是 HMAC 还是其它的,HMAC 用的是 S256 还是 384 还是 512 等等。

但密钥管理之中很重要而又时常被忽略的一点便是密钥的轮转——定期更换密钥。 JWT 的 header 中有 kid 可以用于辨别不同的密钥生成的 token。 (但是查到 HMAC 似乎相对安全,所以不轮转也可以。)

服务密码安全

我们小组并没有用 S3 等第三方服务,但是用到的小组也一定会面临相关认证信息的存放问题。 在围观某几组的项目时,我有幸在其 GitHub 仓库里直接看到了认证信息……

虽然这部分属于运维的问题,但是一般来说,

  1. 认证相关的 token 甚至上面 HMAC 的密钥都应由外界提供(环境变量、配置文件等);
  2. 开发时存放的存有认证信息的配置文件应该直接放入 .gitignore 里,可将实例的配置文件加个 .example 后缀。