API签名鉴权设计

article/2025/9/19 6:45:20

鉴权作用

在实际的业务中,必然会存在和其他平台系统进行数据传输。这个时候出于对数据的保密要求,都会对接口(API)添加鉴权机制,识别调用方的真实身份,对未通过鉴权的请求不做任何业务处理,以帮助接口更好的识别用户及其调用行为的合法性。

API鉴权的作用:识别调用方身份,控制API的访问权限,进而保护平台数据的安全。

鉴权方案设计

目前鉴权主要分为两种:Token方案和API签名方案。
1、两者最大的不同在于校验信息的适用范围不同,而由此带来的安全方面的差距就比较明显。
Token方案:多个请求(即一段时间内的请求)对应一个Token。若Token信息被窃取后,其他平台是可以据此伪造一系列请求进行攻击的。
API签名方案:一个请求对应一个签名信息;若API签名信息被窃取后,其他平台是无法据此发起更多有效攻击的

2、两者的第二大不同在于,密钥信息的使用不同,由此带来使用场景方面的不同。
Token方案:存在登录交互的过程,用户输入一次密钥,换回票据;后续请求无需密钥参与,使用票据即可。在另一篇博文中有介绍,OAuth 2.0设计(以微信登录为例)
API签名方案:每次请求都需要密钥参与,绝不可能每次请求都让用户输入密钥,那么就要求发起方存储密钥;若是js、app等纯前端场景存储密钥一定安全问题。

总结:API签名方案适用于安全性较高的后端交互场景,其余则考虑Token方案。

API签名方案

数据准备

对一个已存在的API添加签名鉴权,一般需要在接口请求参数处额外增加以下五个签名特有参数。
签名必须参数
ServiceID:第三方平台调用API前,必须向API所在系统申请一个唯一的标识。调用者调用API时在请求中带上该ServiceID,API则。通过SecretID确认调用者身份。(API系统为每个调用者分配一个唯一的ServiceID)

ServiceKey:由于ServiceID是明文,极容易被窃取和伪造;但ServiceID不能隐藏或加密,因为SecretID需要明确告诉API请求方是谁。故,在ServiceID之外,设计了一个和ServiceID绑定的信息ServiceKey。调用者必须保护好ServiceKey,不能在任何地方明文显示,也不要请求过程中传输。它主要是用来生成Sign值。

Nonce:随机字符串,是调用者随机生成的值,通过请求传递给API。其组成和长度没有固定规则,主要是为了增加sign签名的多变性和防止重复请求。

TimeStamp:时间戳,调用请求时间,用来生成Sign和验证请求的时效。

Sign:参数签名,防止参数在传输过程中被非法篡改。一般由 (请求中所有非空参数 + ServiceID + ServiceKey + Nonce + TimeStamp)通过加密算法生成。sign通过请求传递给API确认请求是否合法。

调用方流程

(1)生成请求正常参数。

(2)生成随机数Nonce,TimeStamp;获取ServiceID和ServiceKey;拼接签名内容,加密生成Sign信息。

(3)调用API时,带上ServiceID,Nonce,TimeStamp和Sign等信息。
调用流程

服务API方校验流程

(1)获取请求,校验必须参数是否为空。

(2)校验时间有效性Timestamp;校验Nonce唯一性;根据SecretId获取SecretKey,和其他参数生成Sign;校验请求签名和服务端生产签名是否一致。

(3)校验通过,正常处理请求。

API校验流程
具体代码:

// Auth 接口鉴权
type Auth struct {ServiceID  string // 服务IDServiceKey string // 服务密钥Nonce      string // 随机字符串Timestamp  uint64 // 时间戳Sign       string // 签名Param      string // 请求参数
}// VerifySign 校验权限
func VerifySign(ctx context.Context, auth Auth, param map[string]string) (bool, error) {// 1. 验证时间戳now := time.Now().Unix()diff := uint64(now) - auth.Timestampif diff > 10 {return false, nil}// 2. 验证请求是否重复m := redis.NewModel(ctx)flag, err := m.ExistsKey(auth.Sign)if err != nil {return false, err}if flag {return false, err} else {err = m.SetKey(auth.Sign, 10)if err != nil {return false, err}}// 3. 加密签名keys := make([]string, len(param))for k, _ := range param {keys = append(keys, k)}sort.Strings(keys)for _, key := range keys {auth.Param += key}s := tool.SignElem{ServiceID:  auth.ServiceID,ServiceKey: auth.ServiceKey,Random:     auth.Nonce,TimeStamp:  auth.Timestamp,Param:      auth.Param,}sign := tool.HmacSha512Sign(s)if sign != auth.Sign {return false, nil}return true, nil
}

注意,上述代码都没有携带参数,真实使用时需修改入参携带具体API参数。

签名生产流程

在密码学中,有对称加密算法、非对称加密算法、 希运算消息认证码等等几种方案可以很好保护用户密钥的同时,验证用户的身份。

(1)排除非对称加密算法,理由是耗时长,性能差。通过实测,非对接加密算法(RSA)相对加密算法(AES)和 希运算消息认证码算法(HmacSHA256)的加解密耗时要高2~3个数量级,对于一个服务端来说,性能也是很重要的考虑标准,故一般不选择非对称加密算法。

(2)Hmac和AES似乎都不错,而且AES更优。但考虑到签名的目的,除了明确用户身份外,还要明确调用者的调用行为;也就是说,为了需要保证整个请求的完整性,需要加密整个请求的所有关键内容,这时,Hmac算法的防伪造性(即修改一个字节,签名信息就完全不一样)的优势就突显出来了,在性能差不多的情况下,当然,选择Hmac算法了。

(3)Hmac支持的hash算法非常多,但一般不建议使用MD5和SHA1,因其有哈希长度扩展攻击(Hash Length Extension Attacks)的风险,故一般推荐使用HmacSHA256或HmacSHA512。

若服务端支持多种算法,则请求时,需明确带上使用的签名方法:SignatureMethod。

在这里插入图片描述
注意,上述代码都没有携带参数,真实使用时需修改入参携带具体API参数。

保证请求时效性

客户端调用接口时对应的当前请求的Timestamp, 即某个请求,其请求时间戳Timestamp,和服务端的当前时间在规定时间内(如1分钟内)则为合法请求,反之,则视为无效请求。

防重复提交

对于一些需要防止客户端重复提交的(如非幂等性重要操作),具体是获取第一次请求时将sign作为key保存到redis,并设置超时时间,超时时间和Timestamp中设置的差值相同。当同一个请求第二次访问时会先检测redis是否存在该sign,如果存在则证明重复提交了,接口就不再继续调用了。(也可以存储Nonce)


http://chatgpt.dhexx.cn/article/PwcY8tBZ.shtml

相关文章

ak和sk怎么认证 海康威视_aksk鉴权

简介 鉴权功能的位置处于基础服务的接入网关中。 1. 认证简介 本鉴权方案是在api层面上进行,通过使用Access Key/Secret Key加密的方法来对验证某个请求的调用者身份。 当接入网关接收到业务调用方的请求时,将使用相同的SK和同样的认证机制生成认证字符串,并与用户请求中包含…

Kafka鉴权

1.SecurityProtocol 参见官方介绍 如图第一个是无需加密,无需鉴权的 第二个是使用sasl鉴权,不加密 该参数需要在服务端进行配置,client端也需要进行相应的配置 2.sasl.mechanism 消息收发的机制,默认为PLAIN。具体介绍参见该文档…

后端认证鉴权

之前我们把redis缓存工具模块做好了、下面结合RBAC权限模型,我们来进行用户的认证鉴权设计。关于RBAC权限模型在之前的文章跟网上都有很多很详细的描述,这里就简单说一下、就是通过用户关联角色(多对多)、角色关联权限&#xff08…

Postman鉴权

Ok, 今天我们来学习 一下 鉴权 鉴权(authentication) 是指验证用户是否拥有访问系统的权利。传统的鉴权是通过密码来验证的。这种方式的前提是,每个获得密码的用户都已经被授权。在建立用户时,就为此用户分配一个密码,…

详解 http 鉴权

详解 http 鉴权 【总结分享】10种常用前后端鉴权方法,让你不再迷惘 🌟🌟🌟 前端开发登录鉴权方案完全梳理 🌟🌟🌟 实践出真知,聊聊 HTTP 鉴权那些事 注:此处主要讲的是…

文件服务器鉴权,服务鉴权

使用kmse实现服务的权限校验 通过一个简单的实例说明开发者如何通过kmse进行服务间的权限校验。 一、准备客户端和服务端两个demo 这里演示如何快速实践服务鉴权功能。假如现在有两个微服务 auth-client 和 auth-server,想实现 auth-client 调用 auth-server 时&…

前后端常见的几种鉴权方式

最近在重构公司以前产品的前端代码,摈弃了以前的session-cookie鉴权方式,采用token鉴权,忙里偷闲觉得有必要对几种常见的鉴权方式整理一下。 目前我们常用的鉴权有四种: HTTP Basic Authenticationsession-cookieToken 验证OAuth(开放授权)一.HTTP Basic Authentication 这…

鉴权的4种基本方法

一、基于服务器常出现的问题 Seesions: 每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。 可扩展性: 由于sessions存放在服务器内存中,伴随而来的是可…

什么是鉴权?一篇文章带你了解postman的多种方式

目录 一、什么是鉴权? 二、postman鉴权方式 一、什么是鉴权? 鉴权也就是身份认证,就是验证您是否有权限从服务器访问或操作相关数据。发送请求时,通常必须包含相应的检验参数以确保请求具有访问权限并返回所需数据。通俗的讲就…

10 分钟带你了解鉴权那些事

前言: 鉴权是自动化测试路上的拦路虎,相信大部分同学都深有体会,今天我们就讲一讲这个鉴权到底是怎么回事。 一、什么是鉴权,为什么要鉴权 鉴权:是指是指验证用户是否拥有访问系统的权利。为什么要鉴权:…

常见的鉴权方式简述

一、什么是鉴权,为什么要鉴权 鉴权:是指验证用户是否有访问系统的权利。 为什么要鉴权 :对用户进行鉴权,防止非法用户占用网络资源,非法用户接入网络,被骗取关键信息 二、鉴权方式 Basic Auth basic au…

笔记——什么是鉴权

前言 鉴权是自动化测试路上的拦路虎;故以此记录鉴权到底是怎么回事。 一、什么是鉴权,为什么要鉴权 鉴权:是指验证用户是否有访问系统的权利。为什么要鉴权 :对用户进行鉴权,防止非法用户占用网络资源,非…

ftok()函数解析

ftok 消息队列、信号灯、共享内存常用在Linux服务端编程的进程间通信环境中。而此三类编程函数在实际项目中都是用System V IPC函数实现的。System V IPC函数名称和说明如下表15-1所示。 表15-1 System V IPC函数 消息队列 信号灯 共享内存区 头文件 <sys/msg.h> …

ftok()函数的使用

在上一篇文章中&#xff0c;Mayuyu讲述了共享内存的原理以及使用方法。在创建共享内存之前&#xff0c;必须指定一个ID值&#xff0c;而这个ID值通常是通过现在要讲的ftok()函数得到。ftok()函数原型如下 其中参数fname是指定的文件名&#xff0c;这个文件必须是存在的而且可以…

linux ftok函数的使用

ftok API #include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); ftok根据路径名&#xff0c;提取文件信息&#xff0c;再根据这些文件信息及project ID合成key&#xff0c;该路径可以随便设置。该路径是必须存在的&#x…

ftok与fork

ftok函数编辑 系统建立IPC通讯 &#xff08; 消息队列、 信号量和 共享内存&#xff09; 时必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 2ftok原型编辑 头文件 #include < sys/types.h> #include <sys/ipc.h> 函数原型&#xff1a; key_t f…

Linux下的ftok()函数

linux ftok&#xff08;&#xff09;函数 - 清清飞扬 - 博客园 (cnblogs.com) 系统建立IPC通讯&#xff08;如消息队列、共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 ftok原型如下&#xff1a; key_t ftok( char * fname, int i…

Linux中ftok函数介绍

函数原型&#xff1a; *key_t ftok(const char fname, int id); 功能&#xff1a;系统建立IPC通讯&#xff08;如消息队列&#xff0c;共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到 返回值&#xff1a;成功返回一个key_t值&#xf…

linux ftok()

系统建立IPC通讯&#xff08;如消息队列、共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 ftok原型如下&#xff1a; C代码 key_t ftok( char * fname, int id) key_t ftok( char * fname, int id) fname就时你指定的文件名&a…

Linux中ftok函数详解

在ipc通信中 system V 模式的ipc通信中都需要一个key值来生成对应的ID&#xff0c;那么key是如何生成的呢&#xff1f; 通过函数ftok生成 #include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);参数&#xff1a; pathname: …