1、背景
最近在做对外(公司以外)服务(通过http接口实现)。服务实现后,领导说要对服务加一层安全性。这不禁让我想起了前几个月面试过程中被问如何保证对外接口安全的场景。
2、场景复现
当时的面试上下文是说到了内容引入模块,我们给合作方(公司外部)提供了一个对外接口(http接口),合作方通过http接口将数据推入到我们内容引入服务中,通过内容引入服务的校验、清洗、落库,最终变成我们内容社区中的内容。
对话场景复现(丰富下对话场景,当时没有这个滑稽【手动狗头】):
| 面试官 | 我 |
|---|---|
| 你们的接口是直接通过公网对外的吗,有做过什么特殊处理? | |
| 我们的服务接口是通过公司内部的网关服务对外提供 | |
| 嗯嗯,那如何保证服务接口的安全性? | |
| 我问:可以详细再说一下吗,哪种安全性,方便举个场景吗。(内心os:what?这服务也不是我开发的,我是接手的啊。更何况我是内部服务的开发,保证接口安全不是网关服务的事吗,但仔细一想,可能不是问我这个) | |
| 比如,如何防止接口被恶意调用 | |
| 我当时脱口而出加token | |
| 面试官咧嘴一笑(我感觉那笑容像是在说,小子,我就知道你要说这个,接招吧),如果token被截取了,模拟请求怎么办 | |
| 在请求头中加一个版本号(我当时心想,那就记住对方的ip,除了这几个ip的请求,任何接口的请求来了也不行,就是旅长来了也不行【最近在看亮剑】,但最后一想,这不行,万一他要问对面用的是k8s部署咋办,对啦,那就加版本号来保证token的唯一性。) | |
| 最好使用jwt生成token,将版本号加密放入token中,我们拿到token的时候会对消息体进行解析,然后确认版本号是否比之前请求的版本号大,使请求参数一次有效(我刚说完立马觉得不对,这没解决问题啊,还是可以被模拟,诶,将版本号加到token中进行校验,nice) | |
| 如果token被破解了怎么办(面试官面露出笑容) | |
| 那只能让警察叔叔来帮忙了 |
3、解决方案
其实上面说的只有一个问题,那就是如何接口服务的安全性,其实安全性有以下两点
- 保证数据安全性:防止模拟请求参数,对现有数据进行破坏。
- 保证接口服务安全:防止攻击者在短时间内模拟大量请求,导致服务宕机,影响正常用户使用。
了解了问题之后,我们就可以设计对应的解决方法。
- 保证数据安全性:我们可以对请求参数使用密钥进行加密处理,获取到请求的时候对请求参数进行验证,防止攻击者模拟请求对现有数据造成破坏。
- 保证接口安全性:常用的办法是增加时间戳参数,然后时间戳在固定时间范围内有效,过期后,需要重新生成时间戳。(安全要求较高情况下,可以将时间戳作为版本号,下一次请求的版本号要比本次请求的版本号高)。
因此对上面解决方法进行总结便是我们的整体解决方案:
- 双方共有一个密钥用于加密、解密数据
- 服务调用方对请求参数及时间戳进行加密生成签名放入请求头中。
- 服务方提供拿到请求后使用签名进行参数验证,确认参数是否被修改
- 验证时间戳是否有效,防止同一请求参数请求次数过多(在安全要求较高的情况下,可以将时间戳作为版本号,下一次请求的版本号要比本次请求的版本号高)
- 对每一个调用方设置qps限制,增加接口的安全性。
- 可以增加黑名单处理,同一ip地址或同一调用方签名验证不通过超过固定次数后,将ip地址加入黑名单,直接禁止访问接口。