前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# Nodejs进阶crypto模块之理论篇

30 秒速记

  • crypto 是 Node 的核心安全模块:摘要、HMAC、对称 / 非对称加密、签名、随机数都在里面
  • 先分清目标再选工具:完整性用摘要,防伪造用 HMAC / 签名,保密用加密,存密码用 scrypt / bcrypt
  • MD5、SHA-1 已不适合安全场景,摘要至少 SHA-256
  • 对称加密首选 AES-256-GCM,IV 每次随机、绝不复用;别用 ECB 模式
  • 随机数用 crypto.randomBytes / randomUUID,不要用 Math.random

crypto 模块的 API 很多,但背后就几类工具:摘要防改、HMAC 防伪造、加密防看、签名证明是谁发的。 很多人上来就翻 API 列表不知道选哪个,我的建议是先问自己要解决什么问题。比如存用户密码,既不是加密也不是普通 hash,要用 scrypt 这类故意算得很慢的密码哈希;传敏感数据要用 AES-GCM;接口防篡改用 HMAC。选错了类别,代码写得再规范也白搭。

理解「Nodejs进阶crypto模块之理论篇」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

crypto 里最常用的几类能力,各自一行就能跑起来:

const crypto = require('node:crypto');

// 1. 摘要:校验完整性,不可逆
crypto.createHash('sha256').update('hello').digest('hex');
// '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'

// 2. HMAC:带密钥的摘要,防伪造
crypto.createHmac('sha256', 'key').update('hello').digest('hex');

// 3. 对称加密:AES-256-GCM
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(12); // 每次都要新的
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const enc = Buffer.concat([cipher.update('secret', 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
Buffer.concat([decipher.update(enc), decipher.final()]).toString(); // 'secret'

// 4. 密码哈希:故意慢
const salt = crypto.randomBytes(16);
crypto.scryptSync('p@ssw0rd', salt, 64).toString('hex');

// 5. 安全随机数
crypto.randomUUID();
@前端进阶之旅: 代码已经复制到剪贴板

记住一个判断顺序:要还原原文就用加密;只要证明没被改,没有密钥用摘要、有共享密钥用 HMAC、要让任何人都能验证用非对称签名;存密码永远用密码哈希。MD5、SHA-1 已经能构造碰撞,只能用在非安全场景,比如文件去重或缓存 key。

面试官追问

追问 1存用户密码,用 sha256(password) 行不行?
参考回答

不行。SHA-256 太快了,显卡每秒能算几十亿次,拿字典一跑就破。要用 crypto.scrypt 或 bcrypt / argon2,每个用户单独加随机 salt。

追问 2密码要用 AES 加密存起来,方便以后找回,可以吗?
参考回答

我会直接否掉。能解密就意味着密钥一泄露全部密码明文,而且「找回密码」的正确做法是重置,不是告诉用户原密码。

追问 3生成重置密码的 token,用 Math.random().toString(36) 有什么问题?
参考回答

Math.random 不是密码学安全的,输出可以被预测。用 crypto.randomBytes(32).toString('hex') 或 crypto.randomUUID()。

追问 4用 AES 加密时 IV 写死成一个常量,会怎样?
参考回答

CBC 下相同明文出相同密文,泄露数据规律;GCM 下复用 IV 更严重,攻击者能恢复出认证密钥、伪造密文。IV 每次 randomBytes(12) 生成,和密文一起存。

追问 5createCipher 和 createCipheriv 用哪个?
参考回答

只用 createCipheriv。createCipher 用弱的方式从密码派生密钥、IV 固定,Node 10 起废弃,Node 22 已经移除。

# Nodejs进阶:crypto模块之理论篇

# 一、 文章概述

30 秒速记

  • 这一篇讲 crypto API 背后的理论,不讲 API 罗列
  • 三块内容:摘要和 HMAC / 对称加密、非对称加密和数字签名 / 分组加密模式
  • 摘要、hash、散列基本指同一件事
  • 先懂原理再看 API:知道「为什么要 IV」「为什么要认证模式」,才不会照着示例代码写出不安全的实现

这篇的定位是把 crypto 模块背后的安全概念讲清楚:摘要、HMAC、对称和非对称加密、数字签名、分组加密模式。 API 文档只告诉你参数怎么填,不告诉你为什么要填。比如 createCipheriv 要传 IV,不懂分组模式的人就容易写死一个常量;签名和加密都用到公私钥,不懂原理就容易把它们混着用。把这几个概念理顺,再回头看 API 会轻松很多。

互联网时代,网络上的数据量每天都在以惊人的速度增长。同时,各类网络安全问题层出不穷。在信息安全重要性日益凸显的今天,作为一名开发者,需要加强对安全的认识,并通过技术手段增强服务的安全性。

crypto模块是nodejs的核心模块之一,它提供了安全相关的功能,如摘要运算、加密、电子签名等。很多初学者对着长长的API列表,不知如何上手,因此它背后涉及了大量安全领域的知识。

本文重点讲解API背后的理论知识,主要包括如下内容:

  1. 摘要(hash)、基于摘要的消息验证码(HMAC)
  2. 对称加密、非对称加密、电子签名
  3. 分组加密模式

面试官追问

追问 1摘要、加密、签名,一句话分别解决什么问题?
参考回答

摘要证明数据没被改;加密让没有密钥的人看不懂;签名证明数据是谁发的,同时也没被改。

追问 2数字签名和 HMAC 都能防篡改,区别在哪?
参考回答

HMAC 用一把共享密钥,能验证的人也能伪造,适合服务端自己签自己验;数字签名用私钥签、公钥验,任何人都能验证但只有私钥持有者能签,适合对外发布,比如软件包、JWT 的 RS256。

追问 3分组加密模式为什么值得单独讲?
参考回答

AES 一次只能加密 16 字节,长数据怎么拼就是模式决定的。ECB 每块独立加密,相同明文块出相同密文,加密后的图片还能看出轮廓;现在一般用 GCM,既加密又带完整性校验。

追问 4HTTPS 里这几样东西分别用在哪?
参考回答

握手时用非对称算法(ECDHE)协商密钥、用证书签名确认服务器身份;之后数据用对称加密 AES-GCM 或 ChaCha20-Poly1305 传输,自带完整性校验。基本把这一篇的概念全用上了。

# 二、摘要(hash)

30 秒速记

  • 摘要 = 任意长度输入 → 固定长度输出,同样输入永远同样输出,不能反推
  • 用途:校验完整性(下载文件比对 SHA-256)、做缓存 key、去重
  • 长度:MD5 128 位 / SHA-1 160 位 / SHA-256 256 位 / SHA-512 512 位,hex 输出长度是位数除以 4
  • MD5、SHA-1 已能人为构造碰撞,安全场景至少 SHA-256
  • 不可逆 ≠ 不可破:短输入、常见密码可以查彩虹表,存密码要加 salt 并用慢哈希

摘要就是给数据算一个固定长度的「指纹」:内容改一个字节,指纹就完全不同,而且从指纹反推不出原文。 最常见的用法是校验完整性,比如下载安装包后对一下官网给的 SHA-256。Node 里一行搞定:crypto.createHash('sha256').update(data).digest('hex')。要注意的是 MD5 和 SHA-1 已经能人为造出两份内容不同、摘要相同的文件,安全相关的场景别再用。另外不可逆不代表安全,md5('123456') 网上一搜就有结果,所以存密码要用专门的慢哈希。

摘要(digest):将长度不固定的消息作为输入,通过运行hash函数,生成固定长度的输出,这段输出就叫做摘要。通常用来验证消息完整、未被篡改。

摘要运算是不可逆的。也就是说,输入固定的情况下,产生固定的输出。但知道输出的情况下,无法反推出输入。

伪代码如下。

digest = Hash(message)

常见的摘要算法 与 对应的输出位数如下:

  • MD5:128位
  • SHA-1:160位
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

Nodejs进阶crypto模块之理论篇|Nodejs专题系列

# Nodejs进阶crypto模块之理论篇

30 秒速记

  • crypto 是 Node 的核心安全模块:摘要、HMAC、对称 / 非对称加密、签名、随机数都在里面
  • 先分清目标再选工具:完整性用摘要,防伪造用 HMAC / 签名,保密用加密,存密码用 scrypt / bcrypt
  • MD5、SHA-1 已不适合安全场景,摘要至少 SHA-256
  • 对称加密首选 AES-256-GCM,IV 每次随机、绝不复用;别用 ECB 模式
  • 随机数用 crypto.randomBytes / randomUUID,不要用 Math.random

crypto 模块的 API 很多,但背后就几类工具:摘要防改、HMAC 防伪造、加密防看、签名证明是谁发的。 很多人上来就翻 API 列表不知道选哪个,我的建议是先问自己要解决什么问题。比如存用户密码,既不是加密也不是普通 hash,要用 scrypt 这类故意算得很慢的密码哈希;传敏感数据要用 AES-GCM;接口防篡改用 HMAC。选错了类别,代码写得再规范也白搭。

理解「Nodejs进阶crypto模块之理论篇」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

crypto 里最常用的几类能力,各自一行就能跑起来:

const crypto = require('node:crypto');

// 1. 摘要:校验完整性,不可逆
crypto.createHash('sha256').update('hello').digest('hex');
// '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'

// 2. HMAC:带密钥的摘要,防伪造
crypto.createHmac('sha256', 'key').update('hello').digest('hex');

// 3. 对称加密:AES-256-GCM
const key = crypto.randomBytes(32);
const iv = crypto.randomBytes(12); // 每次都要新的
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const enc = Buffer.concat([cipher.update('secret', 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
Buffer.concat([decipher.update(enc), decipher.final()]).toString(); // 'secret'

// 4. 密码哈希:故意慢
const salt = crypto.randomBytes(16);
crypto.scryptSync('p@ssw0rd', salt, 64).toString('hex');

// 5. 安全随机数
crypto.randomUUID();
@前端进阶之旅: 代码已经复制到剪贴板

记住一个判断顺序:要还原原文就用加密;只要证明没被改,没有密钥用摘要、有共享密钥用 HMAC、要让任何人都能验证用非对称签名;存密码永远用密码哈希。MD5、SHA-1 已经能构造碰撞,只能用在非安全场景,比如文件去重或缓存 key。

面试官追问

追问 1存用户密码,用 sha256(password) 行不行?
参考回答

不行。SHA-256 太快了,显卡每秒能算几十亿次,拿字典一跑就破。要用 crypto.scrypt 或 bcrypt / argon2,每个用户单独加随机 salt。

追问 2密码要用 AES 加密存起来,方便以后找回,可以吗?
参考回答

我会直接否掉。能解密就意味着密钥一泄露全部密码明文,而且「找回密码」的正确做法是重置,不是告诉用户原密码。

追问 3生成重置密码的 token,用 Math.random().toString(36) 有什么问题?
参考回答

Math.random 不是密码学安全的,输出可以被预测。用 crypto.randomBytes(32).toString('hex') 或 crypto.randomUUID()。

追问 4用 AES 加密时 IV 写死成一个常量,会怎样?
参考回答

CBC 下相同明文出相同密文,泄露数据规律;GCM 下复用 IV 更严重,攻击者能恢复出认证密钥、伪造密文。IV 每次 randomBytes(12) 生成,和密文一起存。

追问 5createCipher 和 createCipheriv 用哪个?
参考回答

只用 createCipheriv。createCipher 用弱的方式从密码派生密钥、IV 固定,Node 10 起废弃,Node 22 已经移除。

# Nodejs进阶:crypto模块之理论篇

# 一、 文章概述

30 秒速记

  • 这一篇讲 crypto API 背后的理论,不讲 API 罗列
  • 三块内容:摘要和 HMAC / 对称加密、非对称加密和数字签名 / 分组加密模式
  • 摘要、hash、散列基本指同一件事
  • 先懂原理再看 API:知道「为什么要 IV」「为什么要认证模式」,才不会照着示例代码写出不安全的实现

这篇的定位是把 crypto 模块背后的安全概念讲清楚:摘要、HMAC、对称和非对称加密、数字签名、分组加密模式。 API 文档只告诉你参数怎么填,不告诉你为什么要填。比如 createCipheriv 要传 IV,不懂分组模式的人就容易写死一个常量;签名和加密都用到公私钥,不懂原理就容易把它们混着用。把这几个概念理顺,再回头看 API 会轻松很多。

互联网时代,网络上的数据量每天都在以惊人的速度增长。同时,各类网络安全问题层出不穷。在信息安全重要性日益凸显的今天,作为一名开发者,需要加强对安全的认识,并通过技术手段增强服务的安全性。

crypto模块是nodejs的核心模块之一,它提供了安全相关的功能,如摘要运算、加密、电子签名等。很多初学者对着长长的API列表,不知如何上手,因此它背后涉及了大量安全领域的知识。

本文重点讲解API背后的理论知识,主要包括如下内容:

  1. 摘要(hash)、基于摘要的消息验证码(HMAC)
  2. 对称加密、非对称加密、电子签名
  3. 分组加密模式

面试官追问

追问 1摘要、加密、签名,一句话分别解决什么问题?
参考回答

摘要证明数据没被改;加密让没有密钥的人看不懂;签名证明数据是谁发的,同时也没被改。

追问 2数字签名和 HMAC 都能防篡改,区别在哪?
参考回答

HMAC 用一把共享密钥,能验证的人也能伪造,适合服务端自己签自己验;数字签名用私钥签、公钥验,任何人都能验证但只有私钥持有者能签,适合对外发布,比如软件包、JWT 的 RS256。

追问 3分组加密模式为什么值得单独讲?
参考回答

AES 一次只能加密 16 字节,长数据怎么拼就是模式决定的。ECB 每块独立加密,相同明文块出相同密文,加密后的图片还能看出轮廓;现在一般用 GCM,既加密又带完整性校验。

追问 4HTTPS 里这几样东西分别用在哪?
参考回答

握手时用非对称算法(ECDHE)协商密钥、用证书签名确认服务器身份;之后数据用对称加密 AES-GCM 或 ChaCha20-Poly1305 传输,自带完整性校验。基本把这一篇的概念全用上了。

# 二、摘要(hash)

30 秒速记

  • 摘要 = 任意长度输入 → 固定长度输出,同样输入永远同样输出,不能反推
  • 用途:校验完整性(下载文件比对 SHA-256)、做缓存 key、去重
  • 长度:MD5 128 位 / SHA-1 160 位 / SHA-256 256 位 / SHA-512 512 位,hex 输出长度是位数除以 4
  • MD5、SHA-1 已能人为构造碰撞,安全场景至少 SHA-256
  • 不可逆 ≠ 不可破:短输入、常见密码可以查彩虹表,存密码要加 salt 并用慢哈希

摘要就是给数据算一个固定长度的「指纹」:内容改一个字节,指纹就完全不同,而且从指纹反推不出原文。 最常见的用法是校验完整性,比如下载安装包后对一下官网给的 SHA-256。Node 里一行搞定:crypto.createHash('sha256').update(data).digest('hex')。要注意的是 MD5 和 SHA-1 已经能人为造出两份内容不同、摘要相同的文件,安全相关的场景别再用。另外不可逆不代表安全,md5('123456') 网上一搜就有结果,所以存密码要用专门的慢哈希。

摘要(digest):将长度不固定的消息作为输入,通过运行hash函数,生成固定长度的输出,这段输出就叫做摘要。通常用来验证消息完整、未被篡改。

摘要运算是不可逆的。也就是说,输入固定的情况下,产生固定的输出。但知道输出的情况下,无法反推出输入。

伪代码如下。

digest = Hash(message)

常见的摘要算法 与 对应的输出位数如下:

  • MD5:128位
  • SHA-1:160位
  • SHA256 :256位
  • SHA512:512位

nodejs中的例子:

var crypto = require('crypto');
var md5 = crypto.createHash('md5');

var message = 'hello';
var digest = md5.update(message, 'utf8').digest('hex');

console.log(digest);
// 输出如下:注意这里是16进制
// 5d41402abc4b2a76b9719d911017c592
@前端进阶之旅: 代码已经复制到剪贴板

备注:在各类文章或文献中,摘要、hash、散列 这几个词经常会混用,导致不少初学者看了一脸懵逼,其实大部分时候指的都是一回事,记住上面对摘要的定义就好了。

← cookie_parser深入express+cookie_parser签名机制深入剖析 →

fe