开发安全的 API 所需要核对的清单

2,773 阅读7分钟

以下是当你在设计, 测试以及发布你的 API 的时候所需要核对的重要安全措施。


身份认证

  • 不要使用 Basic Auth 使用标准的认证协议 (如 JWT, OAuth).
  • 不要再造 Authentication, token generating, password storing 这些轮子, 使用标准的.
  • 在登录中使用 Max Retry 和自动封禁功能.
  • 加密所有的敏感数据.

JWT (JSON Web Token)

  • 使用随机复杂的密钥 (JWT Secret) 以增加暴力破解的难度.
  • 不要在请求体中直接提取数据, 要对数据进行加密 (HS256RS256).
  • 使 token 的过期时间尽量的短 (TTL, RTTL).
  • 不要在 JWT 的请求体中存放敏感数据, 它是可破解的.

OAuth 授权或认证协议

  • 始终在后台验证 redirect_uri, 只允许白名单的 URL.
  • 每次交换令牌的时候不要加 token (不允许 response_type=token).
  • 使用 state 参数并填充随机的哈希数来防止跨站请求伪造(CSRF).
  • 对不同的应用分别定义默认的作用域和各自有效的作用域参数.

访问

  • 限制流量来防止 DDoS 攻击和暴力攻击.
  • 在服务端使用 HTTPS 协议来防止 MITM 攻击.
  • 使用 HSTS 协议防止 SSLStrip 攻击.

过滤输入

  • 使用与操作相符的 HTTP 操作函数, GET (读取), POST (创建), PUT (替换/更新) 以及 DELETE (删除记录), 如果请求的方法不适用于请求的资源则返回 405 Method Not Allowed.
  • 在请求头中的 content-type 字段使用内容验证来只允许支持的格式 (如 application/xml, application/json 等等) 并在不满足条件的时候返回 406 Not Acceptable.
  • 验证 content-type 的发布数据和你收到的一样 (如 application/x-www-form-urlencoded, multipart/form-data, application/json 等等).
  • 验证用户输入来避免一些普通的易受攻击缺陷 (如 XSS, SQL-注入, 远程代码执行 等等).
  • 不要在 URL 中使用任何敏感的数据 (credentials, Passwords, security tokens, or API keys), 而是使用标准的认证请求头.
  • 使用一个 API Gateway 服务来启用缓存、访问速率限制 (如 Quota, Spike Arrest, Concurrent Rate Limit) 以及动态地部署 APIs resources.

处理

  • 检查是否所有的终端都在身份认证之后, 以避免被破坏了的认证体系.
  • 避免使用特有的资源 id. 使用 /me/orders 替代 /user/654321/orders
  • 使用 UUID 代替自增长的 id.
  • 如果需要解析 XML 文件, 确保实体解析(entity parsing)是关闭的以避免 XXE 攻击.
  • 如果需要解析 XML 文件, 确保实体扩展(entity expansion)是关闭的以避免通过指数实体扩展攻击实现的 Billion Laughs/XML bomb.
  • 在文件上传中使用 CDN.
  • 如果需要处理大量的数据, 使用 Workers 和 Queues 来快速响应, 从而避免 HTTP 阻塞.
  • 不要忘了把 DEBUG 模式关掉.

输出

  • 发送 X-Content-Type-Options: nosniff 头.
  • 发送 X-Frame-Options: deny 头.
  • 发送 Content-Security-Policy: default-src 'none' 头.
  • 删除指纹头 - X-Powered-By, Server, X-AspNet-Version 等等.
  • 在响应中强制使用 content-type, 如果你的类型是 application/json 那么你的 content-type 就是 application/json.
  • 不要返回敏感的数据, 如 credentials, Passwords, security tokens.
  • 在操作结束时返回恰当的状态码. (如 200 OK, 400 Bad Request, 401 Unauthorized, 405 Method Not Allowed 等等).

持续集成和持续部署

  • 使用单元测试和集成测试来审计你的设计和实现.
  • 引入代码审查流程, 不要自行批准更改.
  • 在推送到生产环境之前确保服务的所有组件都用杀毒软件静态地扫描过, 包括第三方库和其它依赖.
  • 为部署设计一个回滚方案.

权限系统 (注册/注册/二次验证/密码重置)

  • 任何地方都使用 HTTPS.
  • 使用 Bcrypt 存储密码哈希 (没有使用盐的必要 - Bcrypt 干的就是这个事).
  • 登出之后销毁会话 ID .
  • 密码重置后销毁所有活跃的会话.
  • OAuth2 验证必须包含 state 参数.
  • 登陆成功之后不能直接重定向到开放的路径(需要校验,否则容易存在钓鱼攻击).
  • 当解析用户注册/登陆的输入时,过滤 javascript://、 data:// 以及其他 CRLF 字符.
  • 使用 secure/httpOnly cookies.
  • 移动端使用 OTP 验证时,当调用 generate OTP 或者 Resend OTP API 时不能把 OTP(One Time Password) 直接返回。(一般是通过发送手机验证短信,邮箱随机 code 等方式,而不是直接 response)
  • 限制单个用户 LoginVerify OTPResend OTPgenerate OTP 等 API 的调用次数,使用 Captcha 等手段防止暴力破解.
  • 检查邮件或短信里的重置密码的 token,确保随机性(无法猜测)
  • 给重置密码的 token 设置过期时间.
  • 重置密码成功后,将重置使用的 token 失效.

用户数据和权限校验

  • 诸如我的购物车我的浏览历史之类的资源访问,必须检查当前登录的用户是否有这些资源的访问权限.
  • 避免资源 ID 被连续遍历访问,使用 /me/orders 代替 /user/37153/orders 以防你忘了检查权限,导致数据泄露。
  • 修改邮箱/手机号码功能必须首先确认用户已经验证过邮箱/手机是他自己的。
  • 任何上传功能应该过滤用户上传的文件名,另外,为了普适性的原因(而不是安全问题),上传的东西应该存放到例如 S3 之类的云存储上面(用 lambda 处理),而不是存储在自己的服务器,防止代码执行。
  • 个人头像上传 功能应该过滤所有的 EXIF 标签,即便没有这个需求.
  • 用户 ID 或者其他的 ID,应该使用 RFC compliant UUID 而不是整数. 你可以从 github 找到你所用的语言的实现.
  • JWT(JSON Web Token)很棒.当你需要构建一个 单页应用/API 时使用.

安卓和 iOS APP

  • 支付网关的 盐(salt) 不应该被硬编码
  • 来自第三方的 secretauth token 不应该被硬编码
  • 在服务器之间调用的 API 不应该在 app 里面调用
  • 在安卓系统下,要小心评估所有申请的 权限
  • 在 iOS 系统下,使用系统的钥匙串来存储敏感信息(权限 token、api key、 等等) 不要 把这类信息存储在用户配置里面
  • 强烈推荐证书绑定(Certificate pinning)

操作

  • 如果你的业务很小或者你缺乏经验,可以评估一下使用 AWS 或者一个 PaaS 平台来运行代码
  • 在云上使用正规的脚本创建虚拟机
  • 检查所有机器没有必要开放的端口
  • 检查数据库是否没有设置密码或者使用默认密码,特别是 MongoDB 和 Redis
  • 使用 SSH 登录你的机器,不要使用密码,而是通过 SSH key 验证来登录
  • 及时更新系统,防止出现 0day 漏洞,比如 Heartbleed、Shellshock 等
  • 修改服务器配置,HTTPS 使用 TLS1.2,禁用其他的模式。(值得这么做)
  • 不要在线上开启 DEBUG 模式,有些框架,DEBUG 模式会开启很多权限以及后门,或者是暴露一些敏感数据到错误栈信息里面
  • 对坏人和 DDOS 攻击要有所准备,使用那些提供 DDOS 清洗的主机服务
  • 监控你的系统,同时记录到日志里面 (例如使用 New Relic 或者其他 ).
  • 如果是 2B 的业务,坚持顺从需求。如果使用 AWS S3,可以考虑使用 数据加密 功能. 如果使用 AWS EC2,考虑使用磁盘加密功能(现在系统启动盘也能加密了)

关于人

  • 开一个邮件组(例如:security@coolcorp.io)和搜集页面,方便安全研究人员提交漏洞
  • 取决于你的业务,限制用户数据库的访问
  • 对报告 bug、漏洞的人有礼貌
  • 把你的代码给那些有安全编码观念的同伴进行 review (More eyes)
  • 被黑或者数据泄露时,检查数据访问前的日志,通知用户更改密码。你可能需要外部的机构来帮助审计
  • 使用 Netflix Scumblr 及时了解你的组织(公司)在社交网络或者搜索引擎上的一些讨论信息,比如黑客攻击、漏洞等等
出处 Hack-with-Github/Awesome-Hacking Fallible