这是我参与「第五届青训营 」伴学笔记创作活动的第 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 仓库里直接看到了认证信息……
虽然这部分属于运维的问题,但是一般来说,
- 认证相关的 token 甚至上面 HMAC 的密钥都应由外界提供(环境变量、配置文件等);
- 开发时存放的存有认证信息的配置文件应该直接放入
.gitignore里,可将实例的配置文件加个.example后缀。