当前位置: 首页 > news >正文

nodejs如何实现Digest摘要认证?

文章目录

      • 1.前言
      • 2. 原理
      • 3. 过程
      • 4. node实现摘要认证
      • 5. 前端如何Digest摘要登录认证(下面是海康的设备代码)

1.前言

根据项目需求,海康设备ISAPI协议需要摘要认证,那么什么是摘要认证?估计不少搞到几年的前端连摘要认证都不知道是什么?能解决什么问题?我们平时用的比较多的是Basic基础认证,Digest 摘要认证比 Basic 基础认证的安全级别更高,它可以通过传递用户名、密码等计算出来的摘要来解决明文方式在网络上发送密码的问题,通过服务产生随机数 nonce 的方式可以防止恶意用户捕获并重放认证的握手过程。

2. 原理

1.客户端发出一个没有认证证书的请求,下面示例为用户名密码校验的ISAPI协议命令(GET方法),每次下发新的命令都需要重新认证。

GET /ISAPI/Security/userCheck HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 10.18.37.12
Connection: Keep-Alive

2. 服务器产生一个随机数nonce,并且将该随机数放在WWW-Authenticate响应头,与服务器支持的认 证算法列表,认证的域realm一起发送给客户端,401 Unauthorized表示认证失败、未授权。返回的WWW-Authenticate表示设备支持的认证方式,stale表示nonce值是否过期,如果过期会生成新的随机数。

HTTP/1.1 401 Unauthorized
Date: Wed, 01 February 2023 19:16:52 GMT
Server: App-webs/
Content-Length: 178
Content-Type: text/html
Connection: keep-alive
Keep-Alive: timeout=10, max=99
WWW-Authenticate: Digest qop="auth", realm="IP Camera(12345)", 
nonce="4e5749344e7a4d794e544936596a4933596a51784e44553d", stale="FALSE"

看到上面出现了那么多之前没见过的参数,下面会做出详细解释:

  1. WWW-Authentication:用来定义使用何种方式(Basic、Digest、Bearer等)去进行认证以获取受保护的资源
  2. realm:表示Web服务器中受保护文档的安全域(比如公司财务信息域和公司员工信息域),用来指示需要哪个域的用户名和密码
  3. qop:保护质量,包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略,(可以为空,但是)不推荐为空值
  4. nonce:服务端向客户端发送质询时附带的一个随机数,这个数会经常发生变化。客户端计算密码摘要时将其附加上去,使得多次生成同一用户的密码摘要各不相同,用来防止重放攻击
  5. nc:nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量。例如,在响应的第一个请求中,客户端将发送“nc=00000001”。这个指示值的目的是让服务器保持这个计数器的一个副本,以便检测重复的请求
  6. cnonce:客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
  7. response:这是由用户代理软件计算出的一个字符串,以证明用户知道口令
  8. Authorization-Info:用于返回一些与授权会话相关的附加信息
  9. nextnonce:下一个服务端随机数,使客户端可以预先发送正确的摘要
  10. rspauth:响应摘要,用于客户端对服务端进行认证
  11. stale:当密码摘要使用的随机数过期时,服务器可以返回一个附带有新随机数的401响应,并指定stale=true,表示服务器在告知客户端用新的随机数来重试,而不再要求用户重新输入用户名和密码了

3. 客户端接收到401响应表示需要进行认证,选择一个算法(目前只支持MD5)生成一个消息摘要(message digest,该摘要包含用户名、密码、给定的nonce值、HTTP方法以及所请求的URL),将摘要放到Authorization的请求头中重新发送命令给服务器。如果客户端要对服务器也进行认证,可以同时发送客户端随机数cnonce,客户端是否需要认证,通过报文里面的qop值进行判断。

GET /ISAPI/Security/userCheck HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 10.18.37.12
Connection: Keep-Alive
Authorization: Digest username="admin",realm="IP 
Camera(12345)",nonce="595463314d5755354d7a4936596a49344f475a6a5a44453d",uri="/ISAPI/Security/userCheck",cnonc
e="011e08f6c9d5b3e13acfa810ede73ecc",nc=00000001,response="82091ef5aaf9b54118b4887f8720ae06",qop="auth"

4. 服务接收到摘要,选择算法以及掌握的数据,重新计算新的摘要跟客户端传输的摘要进行比较,验证是否匹配,若客户端反过来用客户端随机数对服务器进行质询,就会创建客户端摘要,服务可以预先将下一个随机数计算出来,提前传递给客户端,通过 Authentication-Info 发送下一个随机数。该步骤选择实现。

HTTP/1.1 200 OK
Date: Wed, 01 February 2023 19:16:52 GMT
Server: App-webs/
Content-Length: 132
Connection: keep-alive
Keep-Alive: timeout=10, max=98
Content-Type: text/xml
<?xml version="1.0" encoding="UTF-8"?>
<userCheck>
<statusValue>200</statusValue>
<statusString>OK</statusString>
</userCheck>

3. 过程

在说明如何计算摘要之前,先说明参加摘要计算的信息块。信息块主要有两种:

  1. 表示与安全相关的数据的A1,A1中的数据时密码和受保护信息的产物,它包括用户名、密码、保护域和随机数等内容,A1只涉及安全信息,与底层报文自身无关.
    若算法是:MD5 A1 = < user >:< realm >:< password>
    若算法是:MD5-sess
    则 A1=MD5( < user > :< realm >:< password >):< nonce >:< cnonce >

在这里插入图片描述

  1. 表示与报文相关的数据的A2,A2表示是与报文自身相关的信息,比如URL,请求反复和报文实体的主体部分,A2加入摘要计算主要目的是有助于防止反复,资源或者报文被篡改。
    若 qop 未定义或者 auth:
    A2=< request-method >:< uri-directive-value >
    若 qop 为 auth:-int
    A2=< request-method >:< uri-directive-value >:MD5(< request-entity-body >)
    注:< uri-directive-value >为完整的协议命令 URI,比如“/ISAPI/ContentMgmt/InputProxy/channels/status”。

    在这里插入图片描述
  2. 最重要的一步,定义摘要的计算规则
    若 qop 没有定义:
    摘要 response=MD5(MD5(A1):< nonce >:MD5(A2))
    若 qop 为 auth:
    摘要 response=MD5(MD5(A1):< nonce >:< nc >:< cnonce >:< qop >:MD5(A2))
    若 qop 为 auth-int:
    摘要 response= MD5(MD5(A1):< nonce >:< nc >:< cnonce >:< qop >:MD5(A2))

4. node实现摘要认证

 const http = require('http');const crypto = require('crypto');const realm = '1e7d1893b17de03ccc122a4f';const users = {'admin': 'Coolyuan5g','admin1': 'kg5g',};const authenticate = (res) => {res.setHeader('WWW-Authenticate',`Digest realm="${realm}", nonce="${Date.now()}", algorithm=MD5, qop="auth"`);res.statusCode = 401;res.end('Unauthorized');};const validate = (auth, password) => {const hash = crypto.createHash('md5');hash.update(`${auth.username}:${realm}:${password}`);return hash.digest('hex') === auth.response;};const parseAuth = (auth) => {const [, parameters] = auth.split(' ');const params = {};parameters.split(', ').forEach((param) => {const [key, value] = param.split('=');params[key] = value.replace(/\"/g, '');});return params;};const server = http.createServer((req, res) => {if (!req.headers.authorization) {return authenticate(res);}const auth = parseAuth(req.headers.authorization);if (!auth || !auth.username || !auth.realm || !auth.nonce || !auth.uri || !auth.response || auth.realm !== realm) {return authenticate(res);}if (!users[auth.username] || !validate(auth, users[auth.username])) {return authenticate(res);}res.end('Authorized');});

5. 前端如何Digest摘要登录认证(下面是海康的设备代码)

const axios = require('axios'),md5 = require('md5-node');function generateCnonce() {let cnonce = '';const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';for (let i = 0; i < 32; i++) {cnonce += possible.charAt(Math.floor(Math.random() * possible.length));}return cnonce;
}//获取超脑设备所有的设备通道信息
router.get('/getChannels', function (req, res, next) {const params = req.query;if (params.ip && params.userName && params.password) {axios.get(`http://${params.ip}/ISAPI/ContentMgmt/InputProxy/channels/status`).then((response) => {console.log(response)}).catch((error) => {//第一次请求401,获取服务请求头返回的数据// WWW - Authentication: 用来定义使用何种方式( Basic、 Digest、 Bearer等) 去进行认证以获取受保护的资源// realm: 表示Web服务器中受保护文档的安全域( 比如公司财务信息域和公司员工信息域), 用来指示需要哪个域的用户名和密码// qop: 保护质量, 包含auth( 默认的) 和auth - int( 增加了报文完整性检测) 两种策略,( 可以为空, 但是) 不推荐为空值// nonce: 服务端向客户端发送质询时附带的一个随机数, 这个数会经常发生变化。 客户端计算密码摘要时将其附加上去, 使得多次生成同一用户的密码摘要各不相同, 用来防止重放攻击// nc: nonce计数器, 是一个16进制的数值, 表示同一nonce下客户端发送出请求的数量。 例如, 在响应的第一个请求中, 客户端将发送“ nc = 00000001”。 这个指示值的目的是让服务器保持这个计数器的一个副本, 以便检测重复的请求// cnonce: 客户端随机数, 这是一个不透明的字符串值, 由客户端提供, 并且客户端和服务器都会使用, 以避免用明文文本。 这使得双方都可以查验对方的身份, 并对消息的完整性提供一些保护// response: 这是由用户代理软件计算出的一个字符串, 以证明用户知道口令// Authorization - Info: 用于返回一些与授权会话相关的附加信息// nextnonce: 下一个服务端随机数, 使客户端可以预先发送正确的摘要// rspauth: 响应摘要, 用于客户端对服务端进行认证// stale: 当密码摘要使用的随机数过期时, 服务器可以返回一个附带有新随机数的401响应, 并指定stale = true, 表示服务器在告知客户端用新的随机数来重试, 而不再要求用户重新输入用户名和密码了// Digest realm="1e7d1893b17de03ccc122a4f", domain="/", qop="auth", nonce="d4cdb906ef173773:1e7d1893b17de03ccc122a4f:1863093aa1e:e", opaque="799d5", algorithm="MD5", stale="FALSE"if (error.response.status == 401) {let info = error.response.headers["www-authenticate"],cnonce = generateCnonce(),nonce = info.match(/\snonce="([^"]+)/)[1],opaque = info.match(/\sopaque="([^"]+)/)[1],qop = info.match(/\sqop="([^"]+)/)[1],realm = info.match(/\srealm="([^"]+)/)[1],uri = `/ISAPI/ContentMgmt/InputProxy/channels/status`,a1Md5 = md5(`admin:${realm}:Coolyuan`),a2Md5 = md5(`GET:${uri}`),//这里的response计算是关键!!!通过md5计算拼接好的字符串response = md5(`${a1Md5 }:${nonce}:${nc}:${cnonce}:auth:${a2Md5 }`),authorization= `Digest username="admin", realm="${realm}", nonce="${nonce}", uri=${uri}, algorithm=MD5, response="${response}", opaque="${opaque}", qop=${qop}, nc=00000001, cnonce="${cnonce}"`//实现第二次请求axios.get(`http://${params.ip}/ISAPI/ContentMgmt/InputProxy/channels/status`, {headers: {'Authorization': authorization}}).then((data) => {res.status(200).send({"code": 200,"message": "成功","result": "success","content": data.data});}).catch((error) => {res.status(500).send({"code": 500,"message": "失败","result": "fail","content": null});})}})} else {res.status(401).send({"message": "失败","result": "fail","content": null});}
});module.exports = router;

以上部分是代码的核心部分,仅供参考!谢谢!

相关文章:

nodejs如何实现Digest摘要认证?

文章目录1.前言2. 原理3. 过程4. node实现摘要认证5. 前端如何Digest摘要登录认证&#xff08;下面是海康的设备代码&#xff09;1.前言 根据项目需求&#xff0c;海康设备ISAPI协议需要摘要认证&#xff0c;那么什么是摘要认证&#xff1f;估计不少搞到几年的前端连摘要认证都…...

【C#项目】图书馆管理系统-WinForm+MySQL

文章目录前言一、业务梳理与需求分析1.功能描述2.实现步骤3.功能逻辑图二、数据库设计1.实体-关系&#xff08;E-R图&#xff09;概念模型设计2.数据表设计三、WinForm界面交互设计1、界面交互逻辑2、项目树3、主界面登录界面4、 图书查询界面5、图书借阅界面6、图书插入界面7、…...

RNN循环神经网络原理理解

一、基础 正常的神经网络 一般情况下&#xff0c;输入层提供数据&#xff0c;全连接进入隐藏层&#xff0c;隐藏层可以是多层&#xff0c;层与层之间是全连接&#xff0c;最后输出到输出层&#xff1b;通过不断的调整权重参数和偏置参数实现训练的效果。深度学习的网络都是水…...

一句话设计模式1: 单例模式

单例模式:全局唯一的对象。 文章目录 单例模式:全局唯一的对象。前言一、为什么要全局唯一?二、如何实现单例1. 注入到spring中2. 饿汉式3. 懒汉式第一种: 静态内部类第二种: synchronized 关键字第二种: 双重锁检查总结前言 单例可以说是设计模式中很常用的模式了,但也可以说…...

新版国家标准GB/T 28181—2022将于2023年7月1日正式实施,与GB/T 28181—2016差别有哪些?

新版国家标准GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》已于2022年12月30日发布&#xff0c;将于2023年7月1日正式实施。与GB/T 28181—2016相比&#xff0c;除结构调整和编辑性改动外&#xff0c;主要技术变化如下。——更改了标准范围&#xf…...

剑指 Offer 41. 数据流中的中位数

题目 如何得到一个数据流中的中位数&#xff1f;如果从数据流中读出奇数个数值&#xff0c;那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值&#xff0c;那么中位数就是所有数值排序之后中间两个数的平均值。 例如&#xff0c;[2,3,4] 的中位数是…...

分布式架构下,Session共享有什么方案?

分布式架构下&#xff0c;Session共享有什么方案&#xff1f; 1.不要有Session&#xff1a;但是确实在某些场景下&#xff0c;是可以没有session的&#xff0c;其实在很多借口类系统当中&#xff0c;都提倡【API无状态服务】&#xff1b; 也就是每一次的接口访问&#xff0c;都…...

瀚博半导体载天VA1 加速卡安装过程

背景&#xff1a; 想用 瀚博半导体载天VA1 加速卡 代替 NVIDIA 显卡跑深度学习模型 感谢瀚博的周工帮助解答。 正文&#xff1a; 小心拔出 NVIDIA 显卡&#xff0c;在PCIe 接口插上瀚博半导体载天VA1加速卡&#xff0c;如图&#xff1a; 这时显示屏连接主板的集成显卡 卸载…...

服务降级和熔断机制

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;服务降级和熔断机制 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪闪…...

史上最全最详细的Instagram 欢迎消息引流及示例

史上最全最详细的Instagram 欢迎消息引流及示例&#xff01;关键词&#xff1a; Instagram 欢迎消息SaleSmartly&#xff08;ss客服&#xff09; 寻找 Instagram 欢迎消息示例&#xff0c;您可以用于您的业务。在本文中&#xff0c;我们将介绍Instagram欢迎消息的基础知识和好处…...

MDB 5 UI-KIT Bootstrap 5 最新版放送

顶级开源 UI 套件&#xff0c;Bootstrap v5 和 v4 的材料设计&#xff0c;jQuery 版本&#xff0c;数百个优质组件和模板&#xff0c;所有一致的&#xff0c;有据可查的&#xff0c;可靠的超级简单&#xff0c;1分钟安装简单的主题和定制 受到超过 3,000,000 名开发人员和设计师…...

做专家型服务者,尚博信助力企业数字化转型跑出“加速度” | 爱分析调研

01 从技术应用到业务重构&#xff0c;数字化市场呼唤专家型厂商 企业数字化转型是一个长期且系统性的变革过程。伴随着企业从信息化建设转向业务的数字化重构&#xff0c;市场对数字化厂商的能力要求也在升级。 早期的信息化建设主要是从技术视角切入&#xff0c;采用局部需求…...

CSS 重新认识 !important 肯定有你不知道的

重新认识 !important 影响级联规则 与 animation 和 transition 的关系级联层cascade layer内联样式!important 与权重 !important 与简写属性!important 与自定义变量!important 最佳实践 在开始之前, 先来规范一下文中的用于, 首先看 W3C 中关于 CSS 的一些术语定义吧. 下图…...

android 12添加系统字体并且设置为默认字体

需求&#xff1a;在11.0 12.0系统定制化开发中&#xff0c;在产品定制中&#xff0c;有产品需求对于系统字体风格不太满意&#xff0c;所以想要更换系统的默认字体&#xff0c;对于系统字体的修改也是常有的功能&#xff0c;而系统默认也支持增加字体&#xff0c;所以就来添加楷…...

LeetCode刷题系列 -- 1094. 拼车

车上最初有 capacity 个空座位。车 只能 向一个方向行驶&#xff08;也就是说&#xff0c;不允许掉头或改变方向&#xff09;给定整数 capacity 和一个数组 trips , trip[i] [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客&#xff0c;接他们和放他们的…...

二叉查找树的应用 —— K模型和KV模型

文章目录前言1. K模型2. KV模型&#x1f351; 构建KV模型的树&#x1f351; 英汉词典&#x1f351; 统计水果出现的次数3. 总结前言 在上一篇文章中&#xff0c;我们进行了二叉查找树的实现&#xff08;文章链接&#xff09;&#xff0c;那么今天主要探讨一下二叉查找树的应用…...

深度学习实战(11):使用多层感知器分类器对手写数字进行分类

使用多层感知器分类器对手写数字进行分类 1.简介 1.1 什么是多层感知器&#xff08;MLP&#xff09;&#xff1f; MLP 是一种监督机器学习 (ML) 算法&#xff0c;属于前馈人工神经网络 [1] 类。该算法本质上是在数据上进行训练以学习函数。给定一组特征和一个目标变量&#x…...

ThingsBoard-警报

1、使用 IoT 设备警报 ThingsBoard 提供了创建和管理与您的实体相关的警报的能力:设备、资产、客户等。例如,您可以将 ThingsBoard 配置为在温度传感器读数高于某个阈值时自动创建警报。当然,这是一个非常简化的案例,实际场景可能要复杂得多。 2、主要概念 下面让我们回…...

如何去阅读源码,我总结了18条心法

在聊如何去阅读源码之前&#xff0c;先来简单说一下为什么要去阅读源码&#xff0c;大致可分为以下几点原因&#xff1a;最直接的原因&#xff0c;就是面试需要&#xff0c;面试喜欢问源码&#xff0c;读完源码才可以跟面试官battle提升自己的编程水平&#xff0c;学习编程思想…...

排序:归并排序

一、归并 li[2,4,5,7,//1,3,6,8]#归并的前提是必须两部分排好序 def merge(li,low,mid,high):ilowjmid1ltmp[]while i<mid and j<high: #只要左右两边都有数if li[i]<li[j]:ltmp.append(li[i])i1else:ltmp.append(li[j])j1#while执行完&#xff0c;肯定有一部分没数…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...