Nodejs进阶:crypto模块中你需要掌握的安全基础
一、 文章概述
互联网时代,网络上的数据量每天都在以惊人的速度增长。同时,各类网络安全问题层出不穷。在信息安全重要性日益凸显的今天,作为一名开发者,需要加强对安全的认识,并通过技术手段增强服务的安全性。
crypto模块是nodejs的核心模块之一,它提供了安全相关的功能,如摘要运算、加密、电子签名等。很多初学者对着长长的API列表,不知如何上手,因此它背后涉及了大量安全领域的知识。
本文重点讲解API背后的理论知识,主要包括如下内容:
- 摘要(hash)、基于摘要的消息验证码(HMAC)
- 对称加密、非对称加密、电子签名
- 分组加密模式
二、摘要(hash)
摘要(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、散列 这几个词经常会混用,导致不少初学者看了一脸懵逼,其实大部分时候指的都是一回事,记住上面对摘要的定义就好了。
三、MAC、HMAC
MAC(Message Authentication Code):消息认证码,用以保证数据的完整性。运算结果取决于消息本身、秘钥。
MAC可以有多种不同的实现方式,比如HMAC。
HMAC(Hash-based Message Authentication Code):可以粗略地理解为带秘钥的hash函数。
nodejs例子如下:
const crypto = require('crypto');
// 参数一:摘要函数
// 参数二:秘钥
let hmac = crypto.createHmac('md5', '123456');
let ret = hmac.update('hello').digest('hex');
console.log(ret);
// 9c699d7af73a49247a239cb0dd2f8139
四、对称加密、非对称加密
加密/解密:给定明文,通过一定的算法,产生加密后的密文,这个过程叫加密。反过来就是解密。
encryptedText = encrypt( plainText )
plainText = decrypt( encryptedText )
秘钥:为了进一步增强加/解密算法的安全性,在加/解密的过程中引入了秘钥。秘钥可以视为加/解密算法的参数,在已知密文的情况下,如果不知道解密所用的秘钥,则无法将密文解开。
encryptedText = encrypt(plainText, encryptKey)
plainText = decrypt(encryptedText, decryptKey)
根据加密、解密所用的秘钥是否相同,可以将加密算法分为对称加密、非对称加密。
1、对称加密
加密、解密所用的秘钥是相同的,即encryptKey === decryptKey。
常见的对称加密算法:DES、3DES、AES、Blowfish、RC5、IDEA。
加、解密伪代码:
encryptedText = encrypt(plainText, key); // 加密
plainText = decrypt(encryptedText, key); // 解密
2、非对称加密
又称公开秘钥加密。加密、解密所用的秘钥是不同的,即encryptKey !== decryptKey。
加密秘钥公开,称为公钥。解密秘钥保密,称为秘钥。
常见的非对称加密算法:RSA、DSA、ElGamal。
加、解密伪代码:
encryptedText = encrypt(plainText, publicKey); // 加密
plainText = decrypt(encryptedText, priviteKey); // 解密
3、对比与应用
除了秘钥的差异,还有运算速度上的差异。通常来说:
- 对称加密速度要快于非对称加密。
- 非对称加密通常用于加密短文本,对称加密通常用于加密长文本。
两者可以结合起来使用,比如HTTPS协议,可以在握手阶段,通过RSA来交换生成对称秘钥。在之后的通讯阶段,可以使用对称加密算法对数据进行加密,秘钥则是握手阶段生成的。
备注:对称秘钥交换不一定通过RSA,还可以通过类似DH来完成,这里不展开。
五、数字签名
从签名大致可以猜到数字签名的用途。主要作用如下:
- 确认信息来源于特定的主体。
- 确认信息完整、未被篡改。
为了达到上述目的,需要有两个过程:
- 发送方:生成签名。
- 接收方:验证签名。
1、发送方生成签名
- 计算原始信息的摘要。
- 通过私钥对摘要进行签名,得到电子签名。
- 将原始信息、电子签名,发送给接收方。
附:签名伪代码
digest = hash(message); // 计算摘要
digitalSignature = sign(digest, priviteKey); // 计算数字签名
2、接收方验证签名
- 通过公钥解开电子签名,得到摘要D1。(如果解不开,信息来源主体校验失败)
- 计算原始信息的摘要D2。
- 对比D1、D2,如果D1等于D2,说明原始信息完整、未被篡改。
附:签名验证伪代码
digest1 = verify(digitalSignature, publicKey); // 获取摘要
digest2 = hash(message); // 计算原始信息的摘要
digest1 === digest2 // 验证是否相等
3、对比非对称加密
由于RSA算法的特殊性,加密/解密、签名/验证 看上去特别像,很多同学都很容易混淆。先记住下面结论,后面有时间再详细介绍。
- 加密/解密:公钥加密,私钥解密。
- 签名/验证:私钥签名,公钥验证。
六、分组加密模式、填充、初始化向量
常见的对称加密算法,如AES、DES都采用了分组加密模式。这其中,有三个关键的概念需要掌握:模式、填充、初始化向量。
搞清楚这三点,才会知道crypto模块对称加密API的参数代表什么含义,出了错知道如何去排查。
1、分组加密模式
所谓的分组加密,就是将(较长的)明文拆分成固定长度的块,然后对拆分的块按照特定的模式进行加密。
常见的分组加密模式有:ECB(不安全)、CBC(最常用)、CFB、OFB、CTR等。
以最简单的ECB为例,先将消息拆分成等分的模块,然后利用秘钥进行加密。

图片来源:这里,更多关于分组加密模式的介绍可以参考 wiki。
后面假设每个块的长度为128位
2、初始化向量:IV
为了增强算法的安全性,部分分组加密模式(CFB、OFB、CTR)中引入了初始化向量(IV),使得加密的结果随机化。也就是说,对于同一段明文,IV不同,加密的结果不同。
以CBC为例,每一个数据块,都与前一个加密块进行亦或运算后,再进行加密。对于第一个数据块,则是与IV进行亦或。
IV的大小跟数据块的大小有关(128位),跟秘钥的长度无关。
如图所示,图片来源 这里

3、填充:padding
分组加密模式需要对长度固定的块进行加密。分组拆分完后,最后一个数据块长度可能小于128位,此时需要进行填充以满足长度要求。
填充方式有多重。常见的填充方式有PKCS7。
假设分组长度为k字节,最后一个分组长度为k-last,可以看到:
- 不管明文长度是多少,加密之前都会会对明文进行填充 (不然解密函数无法区分最后一个分组是否被填充了,因为存在最后一个分组长度刚好等于k的情况)
- 如果最后一个分组长度等于k-last === k,那么填充内容为一个完整的分组 k k k ... k (k个字节)
- 如果最后一个分组长度小于k-last < k,那么填充内容为 k-last mod k
01 -- if lth mod k = k-1
02 02 -- if lth mod k = k-2
.
.
.
k k ... k k -- if lth mod k = 0
概括来说
- 分组加密:先将明文切分成固定长度的块(128位),再进行加密。
- 分组加密的几种模式:ECB(不安全)、CBC(最常用)、CFB、OFB、CTR。
- 填充(padding):部分加密模式,当最后一个块的长度小于128位时,需要通过特定的方式进行填充。(ECB、CBC需要填充,CFB、OFB、CTR不需要填充)
- 初始化向量(IV):部分加密模式(CFB、OFB、CTR)会将 明文块 与 前一个密文块进行亦或操作。对于第一个明文块,不存在前一个密文块,因此需要提供初始化向量IV(把IV当做第一个明文块 之前的 密文块)。此外,IV也可以让加密结果随机化。
七、写在后面
crypto模块涉及的安全知识较多,篇幅所限,这里没办法一一展开。为了讲解方便,部分内容可能不够严谨,如有错漏敬请指出。
有疑问或感兴趣的同学欢迎留言交流,也可留意我的github关注最新内容更新《nodejs-learning-guide》。
八、相关链接
Hash-based message authentication code
What is the difference between MAC and HMAC?
Block cipher mode of operation
RSA的公钥和私钥到底哪个才是用来加密和哪个用来解密? - 刘巍然-学酥的回答 - 知乎
Nodejs进阶:crypto模块中你需要掌握的安全基础的更多相关文章
- nodeJS之crypto模块md5和Hmac加密
nodeJS之crypto模块md5和Hmac加密 原文地址:https://www.cnblogs.com/tugenhua0707/p/9128690.html 在nodejs中,可以使用cryp ...
- nodeJS之crypto模块公钥加密及解密
nodeJS之crypto模块公钥加密及解密 NodeJS有以下4个与公钥加密相关的类.1. Cipher: 用于加密数据:2. Decipher: 用于解密数据:3. Sign: 用于生成签名:4. ...
- 使用nodeJS的 crypto模块来为你的密码hash加盐
这篇文章将向你解释如何使用Node.js的Crypto模块对你的密码进行加盐hash.在这里,我们将不会对不懂的密码存储方式进行详细的比较.我们将要做的是知道在Node.js中使用加盐hash在进行密 ...
- Crypto模块中的签名算法
因为支付宝当中需要自行实现签名,所以就用到了SHA265和RSA2,将拼接好的信息用私钥进行签名,并进行Base64编码,然后解密就用支付宝回传给用户的公钥解密就ok了,所以我就使用Crypto模块, ...
- nodejs的url模块中的resolve()的用法总结
var url = require('url'); var a = url.resolve('/one/two/three', 'four') , b = url.resolve('http://ex ...
- NodeJS学习笔记 进阶 (12)Nodejs进阶:crypto模块之理论篇
个人总结:读完这篇文章需要30分钟,这篇文章讲解了使用Node处理加密算法的基础. 摘选自网络 Nodejs进阶:crypto模块之理论篇 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速 ...
- Nodejs进阶:MD5入门介绍及crypto模块的应用
本文摘录自<Nodejs学习笔记>,更多章节及更新,请访问 github主页地址.欢迎加群交流,群号 197339705. 简介 MD5(Message-Digest Algorithm) ...
- 浅析nodeJS中的Crypto模块,包括hash算法,HMAC算法,加密算法知识,SSL协议
node.js的crypto在0.8版本,这个模块的主要功能是加密解密. node利用 OpenSSL库(https://www.openssl.org/source/)来实现它的加密技术, 这是因为 ...
- Nodejs实战系列:数据加密与crypto模块
博客地址:<NodeJS模块研究 - crypto> Github :https://github.com/dongyuanxin/blog nodejs 中的 crypto 模块提供了各 ...
随机推荐
- C#Dictionary键值对取值用法
必须包含名空间System.Collection.Generic Dictionary里面的每一个元素都是一个键值对(由二个元素组成:键和值) 键必须是唯一的,而值不需要唯一的 ...
- 照虎画猫写自己的Spring——自定义注解
Fairy已经实现的功能 读取XML格式配置文件,解析得到Bean 读取JSON格式配置文件,解析得到Bean 基于XML配置的依赖注入 所以,理所当然,今天该实现基于注解的依赖注入了. 基于XML配 ...
- Servlet之会话(Session)以及会话追踪技术(Cookie),(URL重写)和(隐藏表单域)
Session 什么是会话? 会话: Web应用中的会话 指的是一个客户端浏览器与Web服务器之间连续发生的一系列请求和响应的过程 会话状态: Web服务器和浏览器在会话的过程中产生的状态信息 作用: ...
- Ocelot网关
Ocelot是一个.net core框架下的网关的开源项目,下图是官方给出的基础实现图,即把后台的多个服务统一到网关处,前端应用:桌面端,web端,app端都只用访问网关即可. Ocelot的实现原理 ...
- CentOS LNMP环境搭建 各版本
我们先下载系统包. 以下centos6.5 X64系统 进行演示.本环境适应Centos5.x CentOs6.x Centos7.x 32和64版本.如有错误请回复本文主要安装代码汇总 [PH ...
- python3 中encode 和decode的使用方法。
编码: 将文本转换成字节流的过程.即Unicode----------->特定格式的编码方式,产生特定的字节流保存在硬盘中(一般为utf-8格式). 解码: 将硬盘中的字节流转换成文本的过程.即 ...
- java 内部类 嵌套类
.markdown-body { color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI" ...
- R语言与数据分析之八:时间序列--霍尔特指数平滑法
上篇我和小伙伴们分享了简单指数平滑法,简单指数平滑法仅仅能预測那些处于恒定水平和没有季节变动的时间序列,今天和大家分享非恒定水平即有增长或者减少趋势的.没有季节性可相加模型的时间序列预測算法---霍尔 ...
- Struts2学习笔记整理(三)
Struts2的输入校验 之前对请求参数的输入校验一般分为两部分:1.客户端校验,也就是我们写js代码去对客户的误操作进行过滤 2.服务端校验, 这是整个应用组织非法数据的最后防线. Struts2 ...
- 关于UTF8文件带BOM头可能会引起的错误解析
今天在做一个文件上传的项目中碰到了一个十分奇怪的问题,在解析上传上来的csv文件时,总是在解析第一行的第一个标题字段时出错,就是第一个那个字段总是和对应的model字段对应不上,这个坑是真的很深,找了 ...