API签名认证的说明及实现

目录

  • 请思考一个问题
  • 什么是API签名认证
  • 为什么需要API签名认证
  • 如何在后端实现签名认证
  • 签名认证实现
    • 通过 http request header 头传递参数
    • 加密方式
    • 怎么知道这个签名对不对?
    • 怎么防重放?
  • Go 代码实现
    • sign.go
    • service.go
    • client.go

请思考一个问题

请思考一个重要的问题:如果我们为开发者提供了一个接口,却对调用者一无所知。假设我们的服务器只能允许100个人同时调用接口。如果有攻击者疯狂的请求这个接口,那将极其危险。一方面这可能会损害我们的安全性,另一方面也可能耗尽服务器性能,影响正常用户的使用。

因此,我们必须为接口设置保护措施。例如限制每个用户每秒只能调用10次接口,即实施请求频次的限额控制。

现在,我们设计一个方法,来确定谁在调用调用 。在开发后端时,我们会进行一些权限检查。比如:当管理员执行删除操作时,后端需要检查这个用户是否为管理员。那么,是如何获取用户信息的呢?是否直接从后端的session中获取?但问题来了,当前端调用接口的时候,一定有session吗?比如说,是前端直接发起请求,并没有登录操作,没有输入用户名和密码,那怎么去调用呢?因此,一般情况下,会采用一个叫 API签名认证 的机制。

什么是API签名认证

简单的说,如果你想来我家做客,我不可能随便让任何陌生人进来。所以我会提前给你发一个类似请帖的东西,作为授权或许可证。当你来访问我的时候,你需要带上这个许可证。我可能并不认识你,但我认识你的请帖。只要你有这个请帖,我就允许你进来。

所以,API签名认证主要包括两个过程:一是签发签名,二是使用签名或校验签名。

为什么需要API签名认证

  1. 保证安全性,不能让任何人都能调用。
  2. 适用于无需保存登录态的场景。只认签名,不关注用户登录态。

如何在后端实现签名认证

需要两个东西:accessKey 和 secretKey
这和用户名和密码类似,不过每次调用接口都需要带上,实现 无状态的请求 。这样,即使你之前没有来过,只要这次的状态正确,你就可以调用接口。所以需要这两个东西来标识用户。

签名认证实现

在签发的过程中,可以自己编写一个生成 accessKey 和 secretKey 的工具。一般来说,accessKey 和 secretKey 需要尽可能复杂,以防止黑客尝试破解,特别是密码,需要尽可能复杂,无规律。

通过 http request header 头传递参数

  • 参数1:accessKey :调用的标识 userA、userB(复杂、无序、无规律)
  • 参数2:secretKey:秘钥(复杂、无序、无规律)该参数不能放到请求头中
  • 参数3:用户请求参数
  • 参数4:sign

⚠️注意:千万不能把秘钥直接在服务器之间传递,有可能会被拦截。

加密方式

用户参数 + 秘钥 => 签名生成算法(SHA-256、SHA-3等) => 不可解密的值
比如:abc + abdedfgh => sfdasidfhssdfh

怎么知道这个签名对不对?

服务端用一模一样的参数和算法去生成签名,只要和用户传的一致,就表示一致。

怎么防重放?

  • 参数5:加 nonce 随机数,只能用一次(服务端要保存用过的随机数)

    每次请求时,发生一个随机数给后端。后端只接受并认可该随机数一次,一旦随机数被使用过,后端将不再接受相同的随机数。这种方式解决了请求重复的问题,因为即使对方使用之前的时间和随机数进行请求,后端会认识到该请求已经被处理过,不会再次处理。

    但是,这种方法需要后端额外开发来保存已使用的随机数。并且,如果接口的并发量很大,每次请求都需要一个随机数,那么可能会面临处理百万、千万甚至上亿级别请求的情况。因此,除了使用随机数之外,还需要其他机制来定期清理已使用的随机数。

  • 参数6:加 timestamp 时间戳,检验时间戳是否过期。

    每个请求在发生时携带一个时间戳,并且后端会验证该时间戳是否在指定的时间范围内。例如不超过10分钟或5分钟。这可以防止对方使用昨天的请求在今天进行重放。

    通过这种方式,我们可以一定程度上控制随机数的过期时间。因为后端需要同时验证这两个参数,只要时间戳过期 或者 随机数被使用过,后端会拒绝该请求。因此,时间戳可以在一定程度上减轻后端保存随机数的负担。通常情况下,这两张方法可以相互配和使用。

因此,在标准的签名认证算法中,建议至少添加以下五个参数:accessKey、secretKey、sign、nonce、timestamp。此外,建议将用户请求的其他参数,例如接口中的name参数,也添加到签名中,以增加安全性。

API签名认证是一个很灵活的设计,具体要有哪些参数、参数名 一定要根据场景来。(比如:userId、appId、version、固定值等)

📢 类似于HTTPS协议,签名认证的本质是确保密码不在服务器之间传输。因为任何在服务器之间传输的内容都有可能被拦截。所以,请记住密码绝不能在服务器之间传输。

Go 代码实现

源码地址: GitHub-golang版本(有对应的单元测试代码)

sign.go

package utilsimport ("crypto/md5""encoding/hex"
)// 计算API签名
func CalculateSignature(accessKey, secretKey, nonce, timestamp, requestBody string) string {// 将参数拼接成一个字符串concatenatedString := accessKey + nonce + timestamp + requestBody + secretKey// 计算 MD5 值signature := md5.Sum([]byte(concatenatedString))return hex.EncodeToString(signature[:])
}

service.go

package mainimport ("net/http""simple/api-signature/service/utils""github.com/gin-gonic/gin"
)var AccessKey, SecretKey string = "aaa", "123456"func GetNameByGet(c *gin.Context) {name := c.Query("name")headers := c.Request.HeaderaccessKey := headers.Get("accessKey")nonce := headers.Get("nonce")timestamp := headers.Get("timestamp")sign := headers.Get("sign")if accessKey != AccessKey {c.JSON(http.StatusForbidden, gin.H{"error": "用户不存在"})return}// 计算签名signature := utils.CalculateSignature(accessKey, SecretKey, nonce, timestamp, "")// 验证签名if signature != sign {c.JSON(http.StatusForbidden, gin.H{"error": "签名验证失败"})return}c.JSON(http.StatusOK, gin.H{"data": "GET 你的名字是" + name})
}func main() {r := gin.New()r.GET("/api/name", GetNameByGet)r.Run(":8011")
}

client.go

package clientimport ("fmt""io""math/rand""net/http""net/url""simple/api-signature/client/utils""strconv""time"
)/** 生成包含N个随机数字的字符串*/
func GenetateRandomString(length int) string {// 设置随机数种子,以确保每次运行生成的随机数都不同r := rand.New(rand.NewSource(time.Now().UnixNano()))// 定义一个包含数字字符的字符集charset := "0123456789"charsetLength := len(charset)// 生成随机数字并拼接字符串randomString := make([]byte, length)for i := 0; i < length; i++ {randomIndex := r.Intn(charsetLength)randomChar := charset[randomIndex]randomString[i] = randomChar}return string(randomString)
}// 获得请求头
func GetRequestHeaders(accessKey, secretkey, requestBody string) http.Header {headers := make(http.Header)// 生成 nonce : 一个包含100个随机数字的字符串nonce := GenetateRandomString(100)// 当前时间戳(秒级别)timestamp := strconv.FormatInt(time.Now().Unix(), 10)// 计算签名signature := utils.CalculateSignature(accessKey, secretkey, nonce, timestamp, requestBody)// 设置请求头headers.Set("accessKey", accessKey)headers.Set("nonce", nonce)headers.Set("timestamp", timestamp)headers.Set("sign", signature)return headers
}func SendApi(name, accessKey, secretKey string) (statusCode int, contentType string, bodyBytes []byte, err error) {requestURL := "http://localhost:8011/api/name"// 构建查询字符串,将其附加到URL上params := url.Values{}params.Set("name", name)// 构建包含查询参数的URLfullURL := fmt.Sprintf("%s?%s", requestURL, params.Encode())client := &http.Client{}req, err := http.NewRequest("GET", fullURL, nil)if err != nil {fmt.Println("Failed to create request, err=", err)return}// 构建请求头headers := GetRequestHeaders(accessKey, secretKey, "")req.Header = headersresponse, err := client.Do(req)if err != nil {fmt.Println("Failed to make request, err=", err)return}defer response.Body.Close()// 读取响应体,将响应体内容原封不动地返回给前端bodyBytes, err = io.ReadAll(response.Body)if err != nil {fmt.Println("Failed to read response, err=", err)return}statusCode = response.StatusCodecontentType = response.Header.Get("Content-Type")return
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/70850.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【pytorch】数据加载dataset和dataloader的使用

1、dataset加载数据集 dataset_tranform torchvision.transforms.Compose([torchvision.transforms.ToTensor(),])train_set torchvision.datasets.CIFAR10(root"./train_dataset",trainTrue,transformdataset_tranform,downloadTrue) test_set torchvision.data…

企业网络安全:威胁检测和响应 (TDR)

什么是威胁检测和响应 威胁检测和响应&#xff08;TDR&#xff09;是指识别和消除 IT 基础架构中存在的恶意威胁的过程。它涉及主动监控、分析和操作&#xff0c;以降低风险并防止未经授权的访问、恶意活动和数据泄露&#xff0c;以免它们对组织的网络造成任何潜在损害。威胁检…

Origin绘制彩色光谱图

成果图 1、双击线条打开如下窗口 2、选择“图案”-》颜色-》按点-》映射-》Wavelength 3、选择颜色映射 4、单击填充-》选择加载调色板-》Rainbow-》确定 5、单击级别&#xff0c;设置成从370到780&#xff0c;右侧增量选择2&#xff08;越小&#xff0c;颜色渐变越细腻&am…

linux之perf(2)list事件

Linux之perf(2)list事件 Author&#xff1a;Onceday Date&#xff1a;2023年9月3日 漫漫长路&#xff0c;才刚刚开始… 参考文档: Tutorial - Perf Wiki (kernel.org)perf-list(1) - Linux manual page (man7.org) 1. 概述 perf list用于列出可用的性能事件&#xff0c;这…

Elasticsearch:利用向量搜索进行音乐信息检索

作者&#xff1a;Alex Salgado 欢迎来到音乐信息检索的未来&#xff0c;机器学习、向量数据库和音频数据分析融合在一起&#xff0c;带来令人兴奋的新可能性&#xff01; 如果你对音乐数据分析领域感兴趣&#xff0c;或者只是热衷于技术如何彻底改变音乐行业&#xff0c;那么本…

oracle10和11功能说明比较

Oracle 10g/11g的特点和优势 首先&#xff0c;Oracle 10g/11g具有以下几个特点&#xff1a; 1. 可靠性和稳定性&#xff1a;Oracle 10g采用了多种技术来确保数据的可靠性和稳定性&#xff0c;如ACID事务处理和数据备份与恢复机制。它还提供了高可用性的解决方案&#xff0c;如…

记本地新建一个gradle方式springboot项目过程

打算使用gradle在idea新建个springboot项目&#xff0c;然后坑很多&#xff0c;记录一下 原来我的idea应该是社区版&#xff0c;新建项目时候没有可以选择spring相关配置&#xff0c;然后卸载了重装&#xff0c;之前问题是启动是启动起来了&#xff0c;但是状态栏那边一直显示…

手写Spring:第8章-初始化和销毁方法

文章目录 一、目标&#xff1a;初始化和销毁方法二、设计&#xff1a;初始化和销毁方法三、实现&#xff1a;初始化和销毁方法3.1 工程结构3.2 Spring应用上下文和Bean对象扩展初始化和销毁类图3.3 定义初始化和销毁方法的接口3.3.1 定义初始化接口3.3.2 定义销毁接口3.3.3 定义…

机器学习基础算法--回归类型和评价分析

目录 1.数据归一化处理 2.数据标准化处理 3.Lasso回归模型 4.岭回归模型 5.评价指标计算 1.数据归一化处理 """ x的归一化的方法还是比较多的我们就选取最为基本的归一化方法 x(x-x_min)/(x_max-x_min) """ import numpy as np from sklea…

CSS构建基础(二)选择器

在CSS中&#xff0c;选择器用于定位我们想要样式化的网页上的HTML元素。有各种各样的CSS选择器可用&#xff0c;允许在选择要样式化的元素时实现细粒度的精度。在本文及其子文章中&#xff0c;我们将详细介绍不同的类型&#xff0c;了解它们是如何工作的。 1、什么是选择器? …

浏览器跨域

相关问题 什么是跨域为什么会跨域为什么会有跨域的限制怎么解决跨域 回答关键点 CORS和同源策略 跨域问题的来源是浏览器为了请求安全而引入的基于同源策略的安全特性。当页面和请求的协议、主机名或端口不同时&#xff0c;浏览器判定两者不同源&#xff0c;即为跨域请求。需…

Springboot开发时,对前端的请求参数,后端用于接受的实体类有没有必要校验为null?

首先给出结论&#xff1a;不用校验为NULL,如果null,Springboot会直接抛异常而不是返回NUll。只需要对其中的属性判断是否null 问题代码如下&#xff1a; public R<Boolean> addzbsz (RequestBody RequestzbszAdd requestzbszAdd) {if ( requestzbszAddnull){return true…

PMP备考全攻略,看这一份就够了!

免费送备考资料。 Project Management Professional (PMP) - 项目管理专业人士,简称PMP。是项目管理专业人士资格认证由项目管理学会和 PMI 发起&#xff0c;严格评估管理项目人员知识技能是否具有高品质的资格认证考试。 简单来说&#xff0c;PMP是美国PMI发起的评估项目管理…

PyTorch 深度学习实践 第10讲刘二大人

总结&#xff1a; 1.输入通道个数 等于 卷积核通道个数 2.卷积核个数 等于 输出通道个数 1.单通道卷积 以单通道卷积为例&#xff0c;输入为&#xff08;1,5,5&#xff09;&#xff0c;分别表示1个通道&#xff0c;宽为5&#xff0c;高为5。假设卷积核大小为3x3&#xff0c…

在不同操作系统上如何安装符号表提取工具(eu-strip)

前言 C开发的小伙伴都知道符号表在调试和解决崩溃时扮演着非常重要的角色&#xff0c;那么如何提取和保存发布应用程序的符号表就变得非常重要。今天就来聊一下如何在不同的操作系统上使用eu-strip提取应用程序中的符号表信息。 正文 问题 如何在不同操作系统上安装符号表提…

定时任务实现方案总结

一、概述 定时任务的作用是在设定的时间和日期后自动执行任务&#xff0c;执行任务的周期既能是单次也能是周期性。 本文重点说明Timer、ScheduledThreadPoolExecutor、Spring Task、Quartz等几种定时任务技术方案。 二、Timer JDK自带的Timer是最古老的定时任务实现方式了。…

【Vue3-Vite】Vite配置--路径别名配置

路径别名配置 使用 代替 src Vite配置 // vite.config.ts import {defineConfig} from vite import vue from vitejs/plugin-vueimport path from pathexport default defineConfig({plugins: [vue()],resolve: {alias: {"": path.resolve("./src") // …

如何助力金融贷款企业实现精准营销获客

无论是哪个行业&#xff0c;吸引客户都是核心。 许多公司的线下渠道面临着许多障碍&#xff0c;以至于他们不得不采用在线客户获取方法。受影响最大的行业之一是贷款行业。如何获得准确的贷款客户资源&#xff1f;如何赢得客户已经成为企业的一大痛点。 过去&#xff0c;信贷…

adb命令大全

adb命令大全 参考 基本用法 命令语法 adb 命令的基本语法如下&#xff1a; adb [-d|-e|-s ] 如果只有一个设备/模拟器连接时&#xff0c;可以省略掉 [-d|-e|-s ] 这一部分&#xff0c;直接使用 adb 。 为命令指定目标设备 如果有多个设备/模拟器连接&#xff0c;则需要为…

博物馆网上展厅有哪些用途,如何搭建数字时代的文化宝库

引言&#xff1a; 博物馆一直以来都是保存、展示和传承人类文化遗产的地方。然而&#xff0c;随着数字时代的来临&#xff0c;博物馆也逐渐迎来了创新的变革。博物馆网上展厅&#xff0c;作为一种新型的文化传播方式&#xff0c;正逐渐崭露头角。 一.什么是博物馆网上展厅&…