谈一谈三方接口调用方案设计

 

来源:juejin.cn/post/7268667384440504360

在为第三方系统提供接口的时候,肯定要考虑接口数据的安全问题,比如数据是否被篡改,数据是否已经过时,数据是否可以重复提交等问题。

在设计三方接口调用的方案时,需要考虑到安全性和可用性。以下是一种设计方案的概述,其中包括使用API密钥(Access Key/Secret Key)进行身份验证和设置回调地址。

设计方案概述

1.API密钥生成: 为每个三方应用生成唯一的API密钥对(AK/SK),其中AK用于标识应用,SK用于进行签名和加密。

AK:Access Key Id,用于标示用户。

SK:Secret Access Key,是用户用于加密认证字符串和用来验证认证字符串的密钥,其中SK必须保密。

通过使用Access Key Id / Secret Access Key加密的方法来验证某个请求的发送者身份。

2.接口鉴权: 在进行接口调用时,客户端需要使用AK和请求参数生成签名,并将其放入请求头或参数中以进行身份验证。

3.回调地址设置: 三方应用提供回调地址,用于接收异步通知和回调结果。

4.接口API设计: 设计接口的URL、HTTP方法、请求参数、响应格式等细节。

权限划分

appID:应用的唯一标识

用来标识你的开发者账号的,即:用户id,可以在数据库添加索引,方便快速查找,同一个 appId 可以对应多个 appKey+appSecret,达到权限的

appKey:公匙(相当于账号)

公开的,调用服务所需要的密钥。是用户的身份认证标识,用于调用平台可用服务.,可以简单理解成是账号。

appSecret:私匙(相当于密码)

签名的密钥,是跟appKey配套使用的,可以简单理解成是密码。

token:令牌(过期失效)

使用方法

  • 向第三方服务器请求授权时,带上AppKey和AppSecret(需存在服务器端)

  • 第三方服务器验证appKey和appSecret在数据库、缓存中有没有记录

  • 如果有,生成一串唯一的字符串(token令牌),返回给服务器,服务器再返回给客户端

  • 后续客户端每次请求都需要带上token令牌

为什么 要有appKey + appSecret 这种成对出现的机制呢?

因为要加密, 通常用在首次验证(类似登录场景),用 appKey(标记要申请的权限有哪些) + appSecret(密码, 表示你真的拥有这个权限)来申请一个token,就是我们经常用到的 accessToken(通常拥有失效时间),后续的每次请求都需要提供accessToken 表明验证权限通过。

现在有了统一的appId,此时如果针对同一个业务要划分不同的权限,比如同一功能,某些场景需要只读权限,某些场景需要读写权限。这样提供一个appId和对应的秘钥appSecret就没办法满足需求。 此时就需要根据权限进行账号分配,通常使用appKey和appSecret。

由于 appKey 和 appSecret 是成对出现的账号, 同一个 appId 可以对应多个 appKey+appSecret,这样平台就为不同的appKey+appSecret对分配不一样的权限。

可以生成两对appKey和appSecret。一个用于删除,一个用于读写,达到权限的细粒度划分。如 : appKey1 + appSecect1 只有删除权限 但是 appKey2+appSecret2 有读写权限… 这样你就可以把对应的权限 放给不同的开发者。其中权限的配置都是直接跟appKey 做关联的,appKey 也需要添加数据库索引, 方便快速查找

简化的场景:

第一种场景: 通常用于开放性接口,像地图api,会省去app_idapp_key,此时相当于三者相等,合而为一 appId = appKey = appSecret。这种模式下,带上app_id的目的仅仅是统计某一个用户调用接口的次数而已了。

第二种场景: 当每一个用户有且仅有一套权限配置 可以去掉 appKey,直接将app_id = app_key,每个用户分配一个appId+ appSecret就够了。

也可以采用签名(signature)的方式: 当调用方向服务提供方法发起请求时,带上(appKey、时间戳timeStamp、随机数nonce、签名sign) 签名sign 可以使用 (AppSecret + 时间戳 + 随机数)使用sha1、md5生成,服务提供方收到后,生成本地签名和收到的签名比对,如果一致,校验成功

签名流程

图片

 

签名规则

1.分配appId(开发者标识)和appSecret(密钥),给 不同的调用方

可以直接通过平台线上申请,也可以线下直接颁发。appId是全局唯一的,每个appId将对应一个客户,密钥appSecret需要高度保密。

2.加入timeStamp(时间戳),以服务端当前时间为准,单位为ms ,5分钟内数据有效

时间戳的目的就是为了减轻DOS攻击。防止请求被拦截后一直尝试请求接口。服务器端设置时间戳阀值,如果服务器时间 减 请求时间戳超过阀值,表示签名超时,接口调用失败。

3.加入临时流水号nonce,至少为10位 ,有效期内防重复提交。

随机值nonce 主要是为了增加签名sign的多变性,也可以保护接口的幂等性,相邻的两次请求nonce不允许重复,如果重复则认为是重复提交,接口调用失败。

  • 针对查询接口,流水号只用于日志落地,便于后期日志核查。

  • 针对办理类接口需校验流水号在有效期内的唯一性,以避免重复请求。

通过在接口签名请求参数加上 时间戳timeStamp + 随机数nonce 可以防止 ”重放攻击“

  1. 时间戳(timeStamp):

以服务端当前时间为准,服务端要求客户端发过来的时间戳,必须是最近60秒内(假设值,自己定义)的。

这样,即使这个请求即使被截取了,也只能在60s内进行重放攻击。

  1. 随机数(nonce):

但是,即使设置了时间戳,攻击者还有60s的攻击时间呢!

所以我们需要在客户端请求中再加上一个随机数(中间黑客不可能自己修改随机数,因为有参数签名的校验呢),服务端会对一分钟内请求的随机数进行检查,如果有两个相同的,基本可以判定为重放攻击。

因为正常情况下,在短时间内(比如60s)连续生成两个相同nonce的情况几乎为0

服务端“第一次”在接收到这个nonce的时候做下面行为:

  1. 去redis中查找是否有key为nonce:{ nonce}的数据

  2. 如果没有,则创建这个key,把这个key失效的时间和验证timestamp失效的时间一致,比如是60s。

  3. 如果有,说明这个key在60s内已经被使用了,那么这个请求就可以判断为重放请求。

4.加入签名字段sign,获取调用方传递的签名信息。

通过在接口签名请求参数加上 时间戳appId + sign 解决身份验证和防止 ”参数篡改“

  1. 请求携带参数appId和Sign,只有拥有合法的身份appId和正确的签名Sign才能放行。这样就解决了身份验证和参数篡改问题。

  2. 即使请求参数被劫持,由于获取不到appSecret(仅作本地加密使用,不参与网络传输),也无法伪造合法的请求。

以上字段放在请求头中。

API接口设计

根据你的具体需求和业务场景,以下是一个简单示例的API接口设计:

1. 获取资源列表接口
  • URL: /api/resources

  • HTTP 方法: GET

  • 请求参数:

    • page (可选): 页码

    • limit (可选): 每页限制数量

  • 响应:

    • 成功状态码: 200 OK

    • 响应体: 返回资源列表的JSON数组

2. 创建资源接口
  • URL: /api/resources

  • HTTP 方法: POST

  • 请求参数:

    • name (必填): 资源名称

    • description (可选): 资源描述

  • 响应:

    • 成功状态码: 201 Created

    • 响应体: 返回新创建资源的ID等信息

3. 更新资源接口
  • URL: /api/resources/{resourceId}

  • HTTP 方法: PUT

  • 请求参数:

    • resourceId (路径参数, 必填): 资源ID

    • name (可选): 更新后的资源名称

    • description (可选): 更新后的资源描述

  • 响应:

    • 成功状态码: 200 OK

4. 删除资源接口
  • URL: /api/resources/{resourceId}

  • HTTP 方法: DELETE

  • 请求参数:

  • </

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值