什么是 API 鉴权
公司、个人开发的系统上线后,系统中
API
暴露到互联网上会存在一定的安全风险,eg: 爬虫、恶意访问等。因此我们要先对接口调用方做一个用户鉴权,对访问 API 权限进行限制,如果鉴权通过则允许用户调用 API。根据不同的场景鉴权方案也有很多种。
常用 API 接口安全措施🔐
数据加密
数据在互联网传输过程很容易被抓包,如果直接传输,那么用户数据可能被其他人获取,导致系统安全性等问题,所以必须对数据加密。常见的做法是对关键字段加密,比如用户密码直接通过
md5
加密。
数据签名
数据在传输过程中经过加密,理论上就算被抓包,也无法对数据进行篡改,但是我们一般加密的部分其实只是在外网,现在很多服务在内网中都需要经过很多服务跳转,如果被攻入内网,则可以在任意节点篡改数据,所以这里的加数据签名可以防止内网中数据被篡改。数据签名就是由发送者产生一段无法伪造的一段数字串,来保证数据在传输过程中不被篡改。
md5算法是常用的数据签名算法,其原理是将需要提交的数据通过某种方式组合成一个字符串,然后通过md5算法生成一段加密字符串,这段加密字符串就是数据包的签名。为保证安全性,最后的密钥会在客户端和服务端各备一份。
添加时间戳
经过如上的加密,加签处理,就算拿到数据也不能看到真实的数据;但是有些攻击者不关心真实的数据,而是直接拿到抓取的数据包做恶意请求,以达到攻击的目的。我们可以使用时间戳机制,在每次请求的时候加入当前的时间,服务器端会拿到当前时间和消息中的时间相减,看看是否在一个固定的时间范围内,超过时间差的请求就视为非法请求。
限流机制
如果有用户出现频繁调用接口的情况;这种情况需要给相关用户做限流处理,常用的限流算法包括:令牌桶限流,漏桶限流,计数器限流。
- 令牌桶限流:系统以一定速率向桶中放入令牌,填满了就丢弃令牌;请求来时会先从桶中取出令牌,如果能取到令牌,则可以继续完成请求,否则等待或者拒绝服务。令牌桶允许一定程度突发流量,只要有令牌就可以处理,支持一次拿多个令牌;
- 漏桶限流:按照固定常量速率流出请求,流入请求速率任意,当请求数超过桶的容量时,新的请求等待或者拒绝服务,因此漏桶算法可以强制限制数据的传输速度;
- 计数器限流:这是一种比较简单粗暴的算法,主要用来限制总并发数,比如数据库连接池、线程池、秒杀的并发数;计数器限流只要一定时间内的总请求数超过设定的阀值则进行限流。
黑名单限流
如果此用户进行过很多非法操作,或者说专门有一个中黑系统,经过分析之后直接将此用户列入黑名单,所有请求直接返回错误码。
我们可以给每个用户设置一个状态比如包括:初始化状态,正常状态,中黑状态,关闭状态等等;或者我们直接通过分布式配置中心,直接保存黑名单列表,每次检查是否在列表中即可。
常用 API 鉴权方式
数据在互联网中传输是不安全的,所有处于开放环境的数据传输都可以被截取、篡改,因此数据传输必须签名加密。
签名核心解决的以下问题:
- 请求是否合法:请求数据的是否是我规定的那部分人
- 请求是否被篡改:请求的数据是否是原始数据,是否被篡改过
- 防止重复请求(防重放):是否重复请求
Cookie + Session 实现 API 鉴权
Cookie + Session
是最传统的
API
鉴权方式,比如很多网站的登录模块就是靠这种方式实现用户会话管理。在服务端会生成一个
session
来保持会话状态,各个
session
是通过唯一的
session_id
来标识,以次来判断请求是那个客户端发起的,
session_id
存储在客户端的
cookie
中,后续所有的请求都会把
cookie
传到服务端,服务端解析
cookie
后找到对应的
session
进行判断。
特点:
- 为了使后台应用识别是那个用户发出的请求,需要在服务端存储一份用户登录信息(session),这份信息也会在相应前端请求时返回给客户端,客户端将其保存在
cookie
中 - 客户端下次请求时发送给服务端,服务端根据这个标识来识别具体时那个用户
cookie
内仅包含一个session
标识符,其他用户信息还是存储在服务端中
缺点:
- 性能相对较低:每一个用户经过服务端认证后服务端都要做一次记录,以方便下次请求的鉴别,通常
session
都是保存在内存中,而随着用户认证增多,服务端开销会越来越大 - 在一个无状态协议里注入状态,与 REST 风格不匹配
- 因为改方案是基于
cookie
来进行识别,cookie
如果被获取用户很容易受到CSRF
攻击 - 很难跨平台,在移动端应用
session
和cookie
很难行通,你无法与移动终端共享服务端创建的session
和cookie
API Key + API Secret
这种方式是指当请求的资源、
API Key
和
API Secret
匹配时,用户才可以访问对应的资源,一般还会加上时间戳等方式来进行请求的时效控制。
实现方法:
- 服务器生成一对
Key/Secret
保存,并下发给客户端,Key
和Secret
均是按照某种规则随你生成,互相无法推算 - 在客户端发起请求时,需要将包含
API Key
在内的所有请求参数排序(一般都是使用字典序),然后跟API Secret
(相当于加盐)一起做hash
生成一个sign
参数,服务器只需要按照约定的规则做一次签名计算,然后和请求的签名做比较,如果一致则验证通过,如果验证不通过则拒绝
这种模式并不是
RBAC
(角色权限控制),而是
ACL
(Access Control List: 访问控制列表) 访问控制。这种方式实现简单,占用的计算资源和网络资源都较少,安全性也可以。但是一般来说每一个 api 都需要分配一对
Key
和
Secret
,因此当
Key
和
Secret
比较多的时候,服务器会有一定的存储成本,而且服务端只能通过
API Key
来区别调用者,
API Secret
一旦泄露将造成较大的安全风险。这种模式一般适用于
Web API
。
有时为了避免重放攻击,会加上时间戳参数,服务单验证时如果时间超过允许范围则验证失败。
注意:加时间戳这种方式一般是在和地方系统对接中使用,一般客户端访问不要求携带时间戳,因为客户端获取的时间是用户电脑的时间,可能不准确导致无法和服务的的时间保持一致。
token 机制实现 API 鉴权
token
令牌机制是用来代替
session
的鉴权方式,
token
机制是服务端根据特定的规则生成的一串加密字符串下发给客户端,客户端请求服务端所有资源时都会携带上这个
Token
(一般设置在 header 中)。服务端来校验这个
token
的合法性,这种方式具有无状态、适合分布式、扩展性好、性能和安全性好更好等优点
常见 Token 实现有以下几种:
- 自定义实现 token:应用开发者根据 token 机制原理自行实现
- JWT:即 json web token,是一种主流的 token 规范
- Oauth:Oauth 虽然时授权规范,但其中也用到 TOken
- HTTP Basic Authentication 认证机制
- Web API 是基于 HTTP 协议,而 HTTP 协议本身就带有认证机制
第三方系统对接鉴权(重放攻击)
虽然上方的鉴权方式可以屏蔽大部分非法请求,可事实上,如果仿冒者监听并截取到了请求片段,然后把签名单独截取出来模仿正式请求方欺骗服务器进行重复请求,这也会造成安全问题,这攻击方式就叫重放攻击(replay 攻击)。这种方式我们就可以通过加入
timestamp + nonce
两个参数来控制请求有效性,防止重放攻击。
- timestamp
客户端:
timestamp
由客户端生成,标识请求时间(客户端需要先检验是否和服务端时间是否一致,且双方使用统一时区计数系统)随请求一并发出,并将 timestamp 作为一个参数加入 sign 加密计算
服务端:服务端接收到请求后对比系统当前时间,设定不超过某个时间段即认为请求正常,反之则为非法请求,但这还不够,仿冒者仍然可以在这个规定的时间段内模拟请求进行重放攻击。所以更近一步可以为 sign 加上一个随机码(盐值),我们这里定义为
nonce
- nonce
请求端:nonce 是由请求方生成的随机数(在规定时间内保证有充足的随机数产生,且重复率为0)也作为参数之一加入 sign 签名
服务端:服务器接受到请求先判定
nonce
是否被请求过(一般会放到
redis
中),如果发现
nonce
参数在规定时间是全新的则正常返回结果,反之,则判定是重放攻击。而由于以上2个参数也写入了签名当中,攻击方刻意增加或伪造
timestamp
和
nonce
企图逃过重放判定都会导致签名不通过而失败。
签名过程实例:
// 拼接待签名字符串
StringToSign = URL + "\n" +
Query + "\n" +
Content-MD5 + "\n" +
Timestamp + "\n" +
nonce
// 计算签名
Sign = Base64(HMAC-SHA256(ClientSecret, UTF-8-Encofing-of(stringToSign)));
- URL: 指所访问的资源路径,如 /api/users/1
- Query: 指请求中的 Query 参数,对参数 key 进行字典序升序排序,所有参数以 key=value 方式拼接,如 age=12&name=alex,若无此参数则设为空字符串
- Content-MD5: body 数据的 md5sum,采用大写字符串,若无此参数则设为空字符串
- ClientSecret:密匙
版权归原作者 流浮生 所有, 如有侵权,请联系我们删除。