HTTP API 认证技术详解(二):Digest Access Authentication

目录

什么是 Digest Access Authentication 认证

Digest Access Authentication 认证的原理

Digest Access Authentication 认证的安全性

使用 Golang 实现 Digest Access Authentication

使用建议

小结


HTTP API 认证技术主要用于验证客户端身份,并确保只有经过授权的实体才能访问受保护的资源。随着安全需求的日益增长,API 认证技术也在不断发展和演进。本文将详细讲解 Digest Access Authentication 认证技术。

什么是 Digest Access Authentication 认证

Digest Access Authentication 是一种基于 HTTP 协议的身份验证机制,通过数字摘要来验证用户的身份,相较于基本认证(Basic Authentication)使用用户名密码的方式,提供了更高的安全性和灵活性。在 Digest 认证中,不会直接发送密码,而是发送摘要信息,这样即使在非安全的通道上也不会因被截获数据而泄露密码。

Digest Access Authentication 认证的原理

Digest Access Authentication 认证使用一种挑战-响应机制来进行身份验证。当用户尝试访问受保护的资源时,服务器会向客户端发送一个挑战(challenge),要求客户端提供有效的身份验证信息。客户端收到挑战后,使用用户的凭证和约定的摘要算法生成摘要信息。客户端将摘要信息随请求内容发送给服务器,服务器使用相同的密钥对响应进行验证。Digest 认证的流程通常如下:

  1. 客户端请求: 客户端发起请求到服务器。
  2. 服务器返回一个认证挑战,返回 401 Unauthorized 状态码及 WWW-Authenticate 头,其中包含认证类型("Digest")、随机生成的 nonce 值以及其他必要参数如 realm 等。WWW-Authenticate 的值示例如下:
Digest realm="myrealm", qop="auth", nonce="unique-nonce", opaque="0000000000000000"
  1. 客户端响应: 客户端收到对应的相应信息后,使用用户名、密码、nonce、请求方法、请求的 URI 和其他参数计算一个摘要,并将其与认证请求一起发送给服务器。header 中 Authorization 的值示例如下:
Digest username="user1", realm="myrealm", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/protected", qop=auth, nc=00000001, cnonce="0a4f113b", response="dd51a70556e6a3342945ef0feac79afb", opaque=""
  1. 服务器验证: 服务器使用存储的密码和客户端发送的参数计算摘要,如果与客户端发送的摘要匹配,则认证成功。

Digest Access Authentication 认证的安全性

Digest Access Authentication 认证方式与 Basic Authentication 认证方式相比安全更高,因为:

  • 不会发送明文密码。
  • 可以使用随机数防止重放攻击。
  • 可以结合使用质询/响应机制进一步提高安全性。

但是 Digest Access Authentication 认证并方式不是完全安全的,依然存在以下缺陷:

  • 如果摘要数据被攻击者截获,密码可能会被离线破解。
  • 不提供消息完整性和机密性保护,因此最好与 HTTPS 结合使用。

使用 Golang 实现 Digest Access Authentication

服务端简单示例代码如下:

package mainimport ("crypto/md5""fmt""io""net/http""strings"
)const (// 为了举例的目的,暂时先写死,实际编码中不要写死Realm    = "myrealm"QOP      = "auth"Nonce    = "dcd98b7102dd2f0e8b11d0f600bfb0c093"Opaque   = "5ccc069c403ebaf9f0171e9517f40e41"User     = "user1"Password = "mypassword"
)func computeMD5Hash(text string) string {hasher := md5.New()io.WriteString(hasher, text)return fmt.Sprintf("%x", hasher.Sum(nil))
}func parseAuthorizationHeader(header string) (username, realm, nonce, uri, qop, nc, cnonce, response string) {fields := strings.Split(header[6:], ", ")parts := make(map[string]string)for _, field := range fields {pair := strings.SplitN(field, "=", 2)if len(pair) == 2 {fmt.Println(strings.TrimSpace(pair[0]))parts[strings.TrimSpace(pair[0])] = strings.Trim(pair[1], `"`)}}return parts["username"], parts["realm"], parts["nonce"], parts["uri"], parts["qop"], parts["nc"], parts["cnonce"], parts["response"]
}func checkAuth(r *http.Request) bool {authHeader := r.Header.Get("Authorization")if authHeader == "" {return false}username, realm, nonce, uri, qop, nc, cnonce, response := parseAuthorizationHeader(authHeader)// HA1 = MD5(username:realm:password)HA1 := computeMD5Hash(fmt.Sprintf("%s:%s:%s", username, realm, Password))// HA2 = MD5(method:digestURI)HA2 := computeMD5Hash(fmt.Sprintf("%s:%s", r.Method, uri))// response = MD5(HA1:nonce:nonceCount:cnonce:qop:HA2)validResponse := computeMD5Hash(fmt.Sprintf("%s:%s:%s:%s:%s:%s", HA1, nonce, nc, cnonce, qop, HA2))return response == validResponse
}func protectedHandler(w http.ResponseWriter, r *http.Request) {if checkAuth(r) {w.Write([]byte("You're in the protected area"))} else {w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Digest realm="%s", qop="%s", nonce="%s", opaque="%s"`, Realm, QOP, Nonce, Opaque))w.WriteHeader(http.StatusUnauthorized)w.Write([]byte("401 Unauthorized\n"))}
}func main() {http.HandleFunc("/protected", protectedHandler)http.ListenAndServe(":8080", nil)
}

使用 Golang 模拟客户端代码如下:

package mainimport ("crypto/md5""fmt""io""net/http"
)const (Username = "user1"Password = "mypassword"Realm    = "myrealm"Nonce    = "dcd98b7102dd2f0e8b11d0f600bfb0c093"NC       = "00000001"CNonce   = "0a4f113b"QOP      = "auth"URI      = "/protected"Method   = "GET"
)func computeMD5Hash(text string) string {hasher := md5.New()io.WriteString(hasher, text)return fmt.Sprintf("%x", hasher.Sum(nil))
}func createDigestAuthorizationHeader() string {// HA1 = MD5(username:realm:password)HA1 := computeMD5Hash(fmt.Sprintf("%s:%s:%s", Username, Realm, Password))// HA2 = MD5(method:URI)HA2 := computeMD5Hash(fmt.Sprintf("%s:%s", Method, URI))// response = MD5(HA1:nonce:NC:cnonce:qop:HA2)response := computeMD5Hash(fmt.Sprintf("%s:%s:%s:%s:%s:%s", HA1, Nonce, NC, CNonce, QOP, HA2))return fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", qop=%s, nc=%s, cnonce="%s", response="%s", opaque=""`,Username, Realm, Nonce, URI, QOP, NC, CNonce, response)
}func main() {client := &http.Client{}req, err := http.NewRequest(Method, "http://localhost:8080"+URI, nil)if err != nil {panic(err)}fmt.Println(createDigestAuthorizationHeader())req.Header.Set("Authorization", createDigestAuthorizationHeader())resp, err := client.Do(req)if err != nil {panic(err)}defer resp.Body.Close()if resp.StatusCode == http.StatusOK {fmt.Println("Successfully authenticated.")} else {fmt.Println("Failed to authenticate.")}
}

先运行服务端代码,在运行客户端代码可以发现验证成功。

使用建议

Digest Access Authentication 认证方式相比 Basic Authentication 认证方式的安全性有一定的增强,但也不建议使用。如果非要使用的话,仅限于以下几种对安全要求不是特别高的场景:

  • 简单的内部应用:如果你正在开发一个只有少数用户使用的内部工具,而这些用户都是可信的,那么 Basic Authentication 可以作为一个简单的解决方案。
  • 快速原型开发:在初期的开发阶段,当需要快速实现认证机制的时候,Basic Authentication 可以作为一种临时措施。
  • 服务端之间的通信:当两个服务端之间需要进行简单的身份验证时,可以使用 Basic Authentication,最好是双方都处于安全的内部网络中。
  • 对于安全性要求不太高的系统,但又想要比基本认证更安全的场景

如果真的采用了 Digest Access Authentication 认证方式,可以考虑添加如下增强措施:

  • 配置服务器支持 HTTPS,提供安全的通信环境。
  • 使用强随机数生成算法来生成 nonce 值,保证 nonce 的随机性。

小结

Digest Access authentication 作为一种安全认证机制,可以有效地提高 Web 应用的安全性。相较于 Basic Authentication 认证方式,虽然安全性有所提高,但实际的安全性依然比较低,仅适用于那些对安全要求不是特别高的场景。

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

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

相关文章

docker应用:搭建uptime-kuma监控站点

简介:Uptime Kuma是一个易于使用的自托管监控工具,它的界面干净简洁,部署和使用都非常方便。 历史攻略: docker:可视化工具portainer docker-compose:搭建自动化运维平台Spug 开源地址: ht…

【NI 国产替代】PXIe‑6378,16路AI(16位,3.5 MS/s/ch),4路AO,48路DIO,PXI多功能I/O模块

PXIe,16路AI(16位,3.5 MS/s/ch),4路AO,48路DIO,PXI多功能I/O模块 PXIe‑6378是一款同步采样的多功能DAQ设备。 该模块提供了模拟 I/O、数字I/O、四个32位计数器和模拟和数字触发。 板载NI‑STC3…

class_3:lambda表达式

1、lambda表达式是c11引入的一种匿名函数的方式&#xff0c;它允许你在需要函数的地方内联的定义函数&#xff0c;而无需单独命名函数&#xff1b; #include <iostream>using namespace std;bool compare(int a,int b) {return a > b; }int getMax(int a,int b,bool (…

算法通关村第十六关—滑动窗口与堆结合(黄金)

滑动窗口与堆结合 堆与滑动窗口问题的结合 LeetCode239给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位&#xff0c;返回滑动窗口中的最大值。  对于最大值、K个最大这种场…

【Docker基础五】Dockerfile指令

Dockerfile 是一个文本文件&#xff0c;它包含了一系列的指令和参数&#xff0c;用来自动化构建 Docker 镜像的过程。每一个指令通常都会创建镜像的一层。下面是一些常用的 Dockerfile 指令。 1、FROM 语法&#xff1a;FROM <image>[:<tag>] [AS <name>]用…

大数据容器化

记录 知乎容器平台演进及与大数据融合实践 http://www.sykv.cn/cat/bigdata/4140.html Building online HBase cluster of Zhihu based on Kubernetes https://blog.csdn.net/mtj66/article/details/78803242

Golang 网络编程

TCP TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议 如何保证连接的可靠性&#xff1f; 三次握手四次挥手 三次握手 TCP 三次握手&#xff08;Three-way Handshake&#xff09;…

Spring MVC中的方法的返回值!!!

参考入门案例的工程代码&#xff1a;Spring MVC入门案例&#xff01;&#xff01;&#xff01;-CSDN博客 1.使用ModelAndView对象并返回 &#xff1a;这里我们在方法内部new了一个ModelAndView对象&#xff0c;通过这个对象&#xff0c;设置你想向jsp页面传达的信息。 modelA…

QT笔记 - 加载带有提升为自定义部件类的“.ui“文件 - 重写QUiLoader::createWidget()函数

说明 如果ui设计中有提升过小部件&#xff0c;则无法直接使用QUiLoader加载。完成加载需要重新实现UiLoader::createWidget()函数。 函数 virtual QWidget * QUiLoader::createWidget(const QString & className, QWidget * parent Q_NULLPTR, const QString & name…

RibbonGroup添加QCheckBox

RibbonGroup添加 QCheckBox&#xff1a; QCheckBox* pCheck new QCheckBox(tr("Check")); pCheck->setToolTip(tr("Check")); groupClipboard->addWidget(pCheck); connect(pCheck, SIGNAL(stateChanged(int)), this, SLOT(checkClick(int))); …

[学习笔记]刘知远团队大模型技术与交叉应用-汇总

参考资料&#xff1a; 视频&#xff1a;【清华NLP】刘知远团队大模型公开课全网首发&#xff5c;带你从入门到实战 课程计划 L1-NLP&Big Model Basics [学习笔记]刘知远团队大模型技术与交叉应用L1-NLP&Big Model Basics L2-Neural Network Basics [学习笔记]刘知…

微调深度学习模型:初级指南

引言 在深度学习领域&#xff0c;微调&#xff08;Fine-tuning&#xff09;是一种常见的实践&#xff0c;旨在优化预训练模型以适应特定任务或数据集。这对于那些希望利用已有模型来解决类似问题的初学者而言&#xff0c;是一个非常有用的技巧。 预训练模型的选择 微调开始于选…

计算机二级Python基本排序题-序号42(补充)

请在屏幕上输出以下杨辉三角形&#xff1a; 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 a [] for i in range(8) :a.append([])for j in range(8) :a[i].append(0) for i in range(8) :a[i][0] 1a[i][i] 1 for i in range(2, 8) :f…

【Java JVM】栈帧

执行引擎是 Java 虚拟机核心的组成部分之一。 在《Java虚拟机规范》中制定了 Java 虚拟机字节码执行引擎的概念模型, 这个概念模型成为各大发行商的 Java 虚拟机执行引擎的统一外观 (Facade)。 不同的虚拟机的实现中, 通常会有 解释执行 (通过解释器执行)编译执行 (通过即时编…

Github Copilot最全的安装与使用教程:一款非常好用的AI编程工具

Github Copilot最全的安装与使用教程 第一章 安装1.安装 GitHub Copilot2.获取资格第二章 使用1.产生建议1.1 键入你想要完成的操作的注释1.2 CtrlI 2. 接受建议3.查看下一个建议3.接受部分建议4.在新选项卡接受建议5.完成多项功能6.聊天 GitHub Copilot 供经过验证的学生、教师…

C++中的23种设计模式精讲

目录 1 单例模式2 工厂方法模式3 抽象工厂模式4参考 1 单例模式 题目链接为&#xff1a;小明的购物车 C代码如下&#xff0c; #include <iostream> #include <string> #include <vector>using namespace std;class ShoppingCart { public:static Shopping…

C语言经典算法之直接排序算法

目录 前言 一、代码实现 二、时空复杂度 时间复杂度&#xff1a; 空间复杂度&#xff1a; 前言 建议&#xff1a;1.学习算法最重要的是理解算法的每一步&#xff0c;而不是记住算法。 2.建议读者学习算法的时候&#xff0c;自己手动一步一步地运行算法。 tips:希尔排序算…

利用反射获取websocket,session字段的值

首先利用反射获取方法字段&#xff0c;然后取得字段的值 private static ConcurrentHashMap<String, Session> map new ConcurrentHashMap<>();OnOpenpublic void onOpen(Session session) throws IllegalAccessException {log.info(session.getId() "开始连…

Flask架构--路由和蓝图

学习视频&#xff1a;第二章&#xff1a;路由和蓝图 1 Flask查询路由的方式_哔哩哔哩_bilibili 参考&#xff1a;Flask框架之路由与蓝图的使用_flask 路由和蓝图-CSDN博客 1.路由的概念&#xff1a; 用于将http请求与特定的python函数相匹配。定义路由后&#xff0c;flask程…

模型索引:QModelIndex

一、为什么要使用模型索引&#xff1f; 从名字可以看出&#xff0c;他是模型的索引&#xff0c;只要对模型实体&#xff08;各种xxxModel的实体&#xff09;施加这个索引&#xff0c;model就会返回数据集中对应的值&#xff0c;或者通过这个索引修改对应数据集中的值。 类比数…