首页 / 专栏 / njs / NJS 中 Crypto 模块实战教程:Hash 与 HMAC 加密详解

NJS 中 Crypto 模块实战教程:Hash 与 HMAC 加密详解

  • 发布时间: 2026-01-10 18:08:34
  • 相关标签: NJS Crypto 实战教程
  • 简介: NJS(NGINX JavaScript)是 NGINX 内置的 JavaScript 运行时,其 `crypto` 模块提供了轻量且高效的加密功能,核心包含 `createHash()` 和 `createHmac()` 两大核心 API,可满足 NGINX 配置中常见的哈希计算、签名验证等需求。本文将结合 NJS 内置 `crypto` 模块的特性,从零讲解 Hash 和 HMAC 的使用方法、核心差异及实战场景。

手机扫码查看

一、前置知识:NJS Crypto 模块基础

1.1 模块引入

NJS 从 0.7.0 版本开始,将 crypto 作为全局对象提供(无需额外安装依赖),也可通过 import 显式引入,两种方式均可:

// 方式1:全局对象直接使用(推荐,NJS 0.7.0+)
const hash = crypto.createHash('sha1');

// 方式2:显式导入(兼容写法)
import crypto from 'crypto';
const hmac = crypto.createHmac('sha1', 'my-secret-key');

1.2 核心概念区分

类型 核心特点 适用场景
Hash(哈希) 单向加密,无密钥,相同输入必出相同输出 数据完整性校验(如文件指纹)、简单数据脱敏
HMAC(哈希消息认证码) 基于 Hash 算法+密钥,需密钥验证,更安全 接口签名、数据防篡改(如 API 请求验签)

二、Hash 算法:无密钥的单向加密

2.1 核心 API 说明

crypto.createHash(algorithm) 是创建 Hash 对象的入口,核心参数和方法如下:

  • algorithm:哈希算法,支持 md5sha1sha256(NJS 内置,无需额外配置);
  • hash.update(data):追加待加密的字符串/数据(可多次调用,数据会拼接);
  • hash.digest([encoding]):计算最终哈希值,支持 hexbase64base64url 编码,无编码参数时返回 Buffer 对象。

2.2 基础使用示例

示例1:单次输入计算 SHA1 哈希(Base64URL 编码)

import crypto from 'crypto';

// 1. 创建 SHA1 Hash 对象
const hash = crypto.createHash('sha1');
// 2. 传入待加密数据
hash.update('A');
// 3. 计算并输出 Base64URL 编码的哈希值
const result = hash.digest('base64url');
console.log(result); // 输出:BtlFlCqiamG-GMPiK_GbvKjdK10

示例2:多次输入拼接计算哈希

update() 可多次调用,数据会按调用顺序拼接,效果等同于单次传入拼接后的字符串:

const hash = crypto.createHash('sha1');
// 多次 update 等价于 update('AB')
hash.update('A').update('B'); 
const result = hash.digest('base64url');
console.log(result); // 输出:BtlFlCqiamG-GMPiK_GbvKjdK10(与单次传入'AB'结果一致)

示例3:不同编码输出对比

const hash = crypto.createHash('md5').update('test');
console.log(hash.digest('hex'));    // 16进制:098f6bcd4621d373cade4e832627b4f6
console.log(hash.digest('base64')); // Base64:CJ7gi1p+z8UYhhyw2bbQhg==
// 注意:digest() 只能调用一次,再次调用会报错,需重新创建 Hash 对象

2.3 NJS 中 Hash 实战:NGINX 响应头添加数据指纹

在 NGINX 配置中,可通过 NJS 计算响应体的 Hash 值并添加到响应头,用于客户端校验数据完整性:

# nginx.conf 配置
http {
    js_import crypto.js; # 导入 NJS 脚本
    
    server {
        listen 80;
        location / {
            # 响应体过滤,计算 Hash 并添加响应头
            js_filter crypto.addHashHeader;
            return 200 "Hello NJS Crypto";
        }
    }
}

# crypto.js 脚本
function addHashHeader(r) {
    const data = r.responseBody; // 获取响应体
    // 计算 SHA256 哈希(Hex 编码)
    const hash = crypto.createHash('sha256').update(data).digest('hex');
    // 添加到响应头
    r.headersOut['X-Data-Hash'] = hash;
}

三、HMAC 算法:带密钥的安全认证

3.1 核心 API 说明

crypto.createHmac(algorithm, secretKey) 是创建 HMAC 对象的入口,相比 Hash 多了密钥参数,核心规则:

  • secretKey:自定义密钥(字符串),是 HMAC 安全的核心,丢失密钥无法验证/破解;
  • hmac.update(data)/hmac.digest(encoding):用法与 Hash 完全一致;
  • 相同输入+不同密钥 → 完全不同的输出(核心优势)。

3.2 基础使用示例

示例1:基础 HMAC 计算(SHA1 + Base64URL)

import crypto from 'crypto';

// 1. 创建 HMAC 对象(算法+密钥)
const hmac = crypto.createHmac('sha1', 'secret.key');
// 2. 传入待加密数据
hmac.update('AB');
// 3. 计算 Base64URL 编码的结果
const result = hmac.digest('base64url');
console.log(result); // 输出:Oglm93xn23_MkiaEq_e9u8zk374

示例2:密钥的重要性(对比测试)

// 密钥1:secret.key
const hmac1 = crypto.createHmac('sha1', 'secret.key').update('AB').digest('hex');
// 密钥2:secret.key1(仅多1个字符)
const hmac2 = crypto.createHmac('sha1', 'secret.key1').update('AB').digest('hex');

console.log(hmac1); // 5e0659fddf19f777f3922684a7f7bdbbcec937ee
console.log(hmac2); // 7a8d9c8b7e6f5a4d3b2a1f0e9d8c7b6a5f4e3d2c1b0a9f8e7d6c5b4a3f2e1d0c
// 结果完全不同,体现密钥的唯一性

3.3 NJS 中 HMAC 实战:API 请求签名验证

在 NGINX 中拦截 API 请求,通过 HMAC 验证请求签名是否合法(防止篡改/伪造请求):

# nginx.conf 配置
http {
    js_import crypto.js;
    server {
        listen 80;
        location /api {
            # 前置校验签名
            js_access crypto.verifyHmacSign;
            proxy_pass http://backend;
        }
    }
}

# crypto.js 脚本
function verifyHmacSign(r) {
    // 1. 获取请求参数:客户端传的签名 + 请求体
    const clientSign = r.headersIn['X-API-Sign'];
    const requestData = r.requestBody;
    // 2. 服务端密钥(与客户端约定)
    const secretKey = 'my-api-secret-2025';
    // 3. 计算服务端签名
    const serverSign = crypto.createHmac('sha256', secretKey)
                             .update(requestData)
                             .digest('base64url');
    // 4. 验证签名
    if (clientSign !== serverSign) {
        r.return(403, 'Invalid sign'); // 签名不匹配,拒绝请求
    }
}

四、注意事项与最佳实践

4.1 版本兼容

  • NJS 0.7.0+:crypto 为全局对象,hash.copy() 从 0.7.12 开始支持;
  • NJS 0.4.4+:digest() 无编码参数时返回 Buffer,0.4.4 之前返回字节字符串(建议升级到 0.7.0+)。

4.2 性能与安全建议

  1. 算法选择:避免使用 md5/sha1(安全性低),优先选择 sha256
  2. 密钥管理:HMAC 密钥避免硬编码在 NJS 脚本中,可通过 NGINX 变量/配置文件注入;
  3. 数据量:NJS 适合轻量数据加密(如请求参数、短字符串),大文件加密建议在后端处理。

4.3 常见错误

  • digest() called twicedigest() 调用后 Hash/HMAC 对象会销毁,需重新创建对象才能再次计算;
  • algorithm not supported:仅支持 md5/sha1/sha256,勿使用其他算法(如 sha512)。

五、总结

  1. NJS 的 crypto 模块无需额外依赖,createHash() 适用于无密钥的单向哈希,createHmac() 基于密钥更适合安全认证;
  2. update() 可多次拼接数据,digest() 是最终计算入口,支持 hex/base64/base64url 三种编码;
  3. 实战中 Hash 用于数据完整性校验,HMAC 用于 API 签名等安全场景,结合 NGINX 配置可实现轻量化加密需求。

上一篇(更新)

深入理解 NJS 全局对象:掌控运行时的核心工具

下一篇

深入解析 @mapbox/mbtiles:Node.js 玩转 MBTiles 瓦片格式

相关文章

NGINX njs 全解析:从基础配置到高级特性实战

njs(NGINX JavaScript)是 NGINX 推出的轻量级 JavaScript 子集,通过 `ngx_http_js_module` 模块可在 NGINX 中实现 location 处理、变量定义、响应过滤等核心能力。相比于传统 NGINX 配置,njs 赋予了 NGINX 更灵活的编程能力,无需依赖第三方模块即可完成复杂的请求/响应处理逻辑。本文将从配置入门、核心指令、实战案例到高级特性,全面讲解 njs 的使用方法。

精通 NJS 文件系统模块(fs):NGINX 网关层的文件操作全指南

NJS(NGINX JavaScript)的 `fs` 模块为 NGINX 网关层提供了完整的文件系统操作能力,支持文件读写、目录管理、权限校验、符号链接处理等核心功能,同时兼容同步 API 和异步 Promise API(0.3.9+)。无论是读取配置文件、记录访问日志,还是处理静态资源元信息,`fs` 模块都是 NJS 实现本地文件交互的核心工具。本文将全面解析 `fs` 模块的核心 API、数据对象及实战场景,结合版本兼容要点讲解最佳实践。

NJS 中的 Base64 编解码:atob() 与 btoa() 全解析

Base64 是一种通用的二进制到文本的编码方式,常用于处理特殊字符传输、加密数据序列化等场景。NJS(NGINX JavaScript)内置了 Web 标准的 `atob()` 和 `btoa()` 方法,无需依赖第三方模块即可实现高效的 Base64 编解码,是 NGINX 网关层处理数据编码的轻量解决方案。本文将详细讲解这两个方法的用法、适用场景及注意事项,结合实战示例展示其在 NJS 中的典型应用。

精通 NJS HTTP 请求对象:全方位掌控 NGINX 请求生命周期

NJS(NGINX JavaScript)的 HTTP 请求对象(通常简写为 `r`)是 `ngx_http_js_module` 模块的核心,封装了客户端请求的所有关键信息(参数、头信息、请求体等),并提供了响应构建、子请求、日志输出等核心能力。从请求解析到响应发送,`r` 对象贯穿整个 NGINX 请求生命周期,是实现网关层逻辑(如参数校验、请求转发、响应改写)的基础。本文将全面解析 `r` 对象的核心属性与方法,结合实战场景讲解其使用技巧与版本兼容要点。

NJS 共享字典(ngx.shared)全解析:跨 Worker 进程的数据共享方案

NJS(NGINX JavaScript)从 0.8.0 版本开始引入 `ngx.shared` 全局对象,提供了基于共享内存的字典(SharedDict)能力,解决了 NGINX 多 Worker 进程间数据隔离的问题。通过 SharedDict,开发者可在 NGINX 网关层实现轻量级缓存、计数器、限流标记等跨进程共享数据的场景,本文将全面讲解 `ngx.shared` 的配置方式、核心 API 及实战应用。

查看njs全部内容

共7篇

返回专栏分类

一级分类总览

相关推荐