对外API接口的安全性设计

前言:直接把API暴露到互联网上给外部系统是存在安全风险的,因此我们要先对接口调用方做一个用户鉴权对API权限划分,如果鉴权通过则允许用户调用API。根据不同的场景,鉴权方案也有很多种。 

一般外部接口需要采取一系列措施来保证接口的安全性

  • 认证(Authentication):即身份验证,确认用户身份是否正确。
  • 授权(Authorization):即权限控制,确认用户是否有操作某个资源的权限。
  • 数据传输安全:即保证数据在传输过程中不被窃取、篡改或伪造。
  • 防止攻击:防止不法分子通过网络攻击的方式进行恶意访问或攻击等。 

API鉴权方式

AccessKey+SecretKey实现鉴权(开放平台

请求身份

为开发者分配AccessKey(开发者标识,确保唯一)和SecretKey(用于接口加密,确保不易被穷举,生成算法不易被猜测) 

防止篡改
数字签名 

请求携带参数AccessKeySign,只有拥有合法的身份AccessKey和正确的签名Sign才能放行。这样就解决了身份验证参数篡改问题,即使请求参数被劫持,由于获取不到SecretKey(仅作本地加密使用,不参与网络传输),无法伪造合法的请求

重放攻击 

虽然解决了请求参数被篡改的隐患,但是还存在着重复使用请求参数伪造二次请求的隐患

timestamp+nonce方案 

nonce指唯一的随机字符串,用来标识每个被签名的请求。通过为每个请求提供一个唯一的标识符,服务器能够防止请求被多次使用(记录所有用过的nonce以阻止它们被二次使用) 

然而,对服务器来说永久存储所有接收到的nonce的代价是非常大的。可以使用timestamp来优化nonce的存储

假设允许客户端和服务端最多能存在15分钟的时间差,同时追踪记录在服务端的nonce集合。当有新的请求进入时,首先检查携带的timestamp是否在15分钟内,如超出时间范围,则拒绝,然后查询携带的nonce,如存在已有集合,则拒绝。否则,记录该nonce,并删除集合内时间戳大于15分钟的nonce(可以使用redis的expire,新增nonce的同时设置它的超时失效时间为15分钟)

PS:该模式适用于大多是的Web API 

具体实现步骤 
客户端

1. 生成当前时间戳timestamp=now和唯一随机字符串nonce=random

2.按照请求参数名的字母升序排列非空请求参数(包含AccessKey)
stringA="AccessKey=access&home=world&name=hello&work=java&timestamp=now&nonce=random";

3.拼接密钥SecretKey

stringSignTemp="AccessKey=access&home=world&name=hello&work=java&timestamp=now&nonce=random&SecretKey=secret";

4.MD5(或)并转换为大写,sign=MD5(stringSignTemp).toUpperCase();

5.最终请求
http://ip/test?AccessKey=access&name=hello&home=world&work=java&timestamp=now&nonce=nonce&sign=sign;

服务端

Token机制&APPKEY实现API鉴权(APP

APP开放API接口的设计中,由于大多数接口涉及到用户的个人信息以及产品的敏感数据,所以要对这些接口进行身份验证,为了安全起见让用户暴露的明文密码次数越少越好,然而客户端与服务器的交互在请求之间是无状态的,也就是说,当涉及到用户状态时,每次请求都要带上身份验证信息

Token身份验证
  1. 用户登录向服务器提供认证信息(如账号和密码),服务器验证成功后返回Token给客户端;
  2. 客户端将Token保存在本地,后续发起请求时,携带此Token
  3. 服务器检查Token的有效性,有效则放行,无效(Token错误或过期)则拒绝。

安全隐患:Token被劫持,伪造请求和篡改参数。

Token+AppKey签名验证

与上面开发平台的验证方式类似,为客户端分配AppKey(密钥,用于接口加密,不参与传输),将AppKey和所有请求参数组合成源串,根据签名算法生成签名值,发送请求时将签名值一起发送给服务器验证。这样,即使Token被劫持,对方不知道AppKey和签名算法,就无法伪造请求和篡改参数。再结合上述的重发攻击解决方案,即使请求参数被劫持也无法伪造二次重复请求。

实现
登录和登出请求


后续请求
客户端

和上述开放平台的客户端行为类似,把AccessKey改为token即可

服务端

Cookie+Session实现API鉴权(Web)

传统的web网站,且同时认证的人数不是足够大(比如只是内部使用)的都可以用这种方式,很多网站依旧采用该方式。

Cookie + Session是最传统的API鉴权方式,比如很多网站的登录模块就是靠这种方式实现会话管理。

服务端会生成一个session来保存会话状态,各个session是通过唯一的session_id来标识的,一次判断请求是哪个客户端发起,session_id存储在客户端的cookie中。

后续的所有请求都会把cookie传到服务器端,服务器端解析cookie后找到对应的session进行判断。

因此这种鉴权方式具有以下特点:

为了使后台应用能识别是哪个用户发出的请求,需要在后台服务器存储一份用户登录信息(即session),这份信息也会在响应前端请求时返回给前端,前端将其保存在cookie
下次请求时前端发送给后端应用,后端应用就可以识别这个请求是来自哪个用户;
cookie内仅包含一个session标识符而诸如用户信息、授权列表等都保存在服务端的session中。

优点
  • 比较传统,对开发来说资料较多,语言支持完善
  • 较易于扩展,外部session存储方案已经非常成熟了(比如Redis)
缺点 
  • 性能相于较低:                                                                                                                          每一个用户经过后端应用认证之后,后端应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大
  • 在一个无状态协议里注入了状态,与REST风格不匹配
  • 因为基于cookie来进行用户识别, cookie如果被截获,用户就会很容易受到CSRF攻击
  • 很难跨平台:在移动应用上 session 和 cookie 很难行通,你无法与移动终端共享服务器创建的 session 和 cookie

API接口的安全措施

数据加密

数据在传输过程中是很容易被抓包的,如果直接传输,比如通过http协议,那么用户传输的数据可以被任何人获取,所以必须对数据加密。 

常见做法:对关键字段加密比如用户密码直接通过md5加密

主流的做法:使用https协议,在http和tcp之间添加一层加密层(SSL层),这一层负责数据的加密和解密

数据签名

数据在传输过程中经过加密,理论上就算被抓包,就无法对数据进行篡改;但是我们一般加密的部分其实只是在外网,现在很多服务在内网中都需要经过很多服务跳转,如果被攻入内网,则可以在任意节点篡改数据,所以这里的加数据签名可以防止内网中数据被篡改。 

添加 时间戳 +nonce

经过如上的加密,加签处理,就算拿到数据也不能看到真实的数据;但是有些攻击者不关心真实的数据,而是直接拿到抓取的数据包做恶意请求,以达到攻击的目的。 

通过时间限制和唯一随机nonce,达到在有限时间内请求不能被重放。超过时间差或nonce已存在都会被视为非法请求 

限流机制

如果有用户出现频繁调用接口的情况;这种情况需要给相关用户做限流处理

常用的限流算法包括:令牌桶限流漏桶限流计数器限流 

黑名单机制

如果此用户进行过很多非法操作,或者说专门有一个中黑系统,经过分析之后直接将此用户列入黑名单,所有请求直接返回错误码。

我们可以给每个用户设置一个状态比如包括:初始化状态,正常状态,中黑状态,关闭状态等等;或者我们直接通过分布式配置中心,直接保存黑名单列表,每次检查是否在列表中即可

数据合法性校验

这应该是每个系统都会有的处理机制,只有在数据是合法的情况下才会进行数据处理,每个系统都有自己的验证规则。

合法性校验包括:

  • 常规性校验:包括签名校验,必填校验,长度校验,类型校验,格式校验等
  • 业务校验:根据实际业务而定,比如车厢长度不能小于0,高铁行驶速度不能小于0等
     
  • 25
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值