Node.js 指南(迁移到安全的Buffer构造函数)
迁移到安全的Buffer构造函数
移植到Buffer.from()
/Buffer.alloc()
API.
概述
本指南介绍了如何迁移到安全的Buffer
构造函数方法,迁移修复了以下弃用警告:
由于安全性和可用性问题,不建议使用
Buffer()
和new Buffer()
构造函数,请改用new Buffer.alloc()
、Buffer.allocUnsafe()
或Buffer.from()
构造方法。
- 变式1:放弃对Node.js ≤4.4.x和5.0.0 - 5.9.x的支持(推荐)。
- 变式2:使用polyfill。
- 变式3:手动检测,带有安全措施。
使用grep查找有问题的代码位
只需运行grep -nrE '[^a-zA-Z](Slow)?Buffer\s*\(' --exclude-dir node_modules
。
它会在你自己的代码中找到所有可能不安全的地方(有一些不太常见的例外)。
使用Node.js 8查找有问题的代码位
如果你使用的是Node.js ≥ 8.0.0(推荐使用),Node.js会公开多个选项,以帮助你找到相关的代码片段:
--trace-warnings
将使Node.js显示此警告的堆栈跟踪以及Node.js打印的其他警告。--trace-deprecation
执行相同的操作,但仅适用于弃用警告。--pending-deprecation
将显示更多类型的弃用警告,特别是,它也会显示Buffer()
弃用警告,即使在Node.js 8上。
你可以使用环境变量设置这些标志:
$ export NODE_OPTIONS='--trace-warnings --pending-deprecation'
$ cat example.js
'use strict';
const foo = new Buffer('foo');
$ node example.js
(node:7147) [DEP0005] DeprecationWarning: The Buffer() and new Buffer() constructors are not recommended for use due to security and usability concerns. Please use the new Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() construction methods instead.
at showFlaggedDeprecation (buffer.js:127:13)
at new Buffer (buffer.js:148:3)
at Object.<anonymous> (/path/to/example.js:2:13)
[... more stack trace lines ...]
使用linters查找有问题的代码位
ESLint规则no-buffer-constructor或node/no-deprecated-api也查找对不推荐使用的Buffer()
API的调用,这些规则包含在一些预设中。
但是有一个缺点,当Buffer
被重写时,它并不总是正确工作,例如使用polyfill,因此建议将此与上述其他方法结合使用。
变式1:放弃对Node.js ≤4.4.x和5.0.0 - 5.9.x的支持
这是目前推荐的解决方案,仅意味着最小的开销。
自2016年7月以来,Node.js 5.x版本系列一直未得到支持,并且Node.js 4.x版本系列在2018年4月达到其生命周期结束(→计划)。
这意味着即使出现安全问题,这些版本的Node.js也不会收到任何更新,因此如果可能的话,应该避免使用这些版本线。
在这种情况下,你要做的是将所有new Buffer()
或Buffer()
调用转换为使用Buffer.alloc()
或Buffer.from()
,方法如下:
对于
new Buffer(number)
,将其替换为Buffer.alloc(number)
。- 对于
new Buffer(string)
(或new Buffer(string, encoding)
),将其替换为Buffer.from(string)
(或Buffer.from(string, encoding)
)。 - 对于所有其他参数组合(这些更为罕见),还要用
Buffer.from(...arguments)
替换new Buffer(...arguments)
。
- 对于
请注意,Buffer.alloc()
在当前Node.js版本上的速度也比new Buffer(size).fill(0)
快,这是你需要确保零填充的原因。
建议启用ESLint规则no-buffer-constructor或node/no-deprecated-api以避免意外的不安全Buffer
API使用。
还有一个JSCodeshift codemod,用于自动将Buffer
构造函数迁移到Buffer.alloc()
或Buffer.from()
,请注意,它目前仅适用于参数为文字或使用两个参数调用构造函数的情况。
如果你当前支持那些较旧的Node.js版本并且无法删除对它们的支持,或者如果你支持包的旧分支,考虑在较旧的分支上使用变式2或变式3,因此使用这些旧分支的人也将收到修复。这样,你将消除由不谨慎的Buffer
API使用引起的潜在问题,并且在Node.js 10上运行代码时,你的用户将不会观察到运行时弃用警告。
变式2:使用polyfill
有三种不同的polyfill可用:
- safer-buffer是整个
Buffer
API的替代品,在使用new Buffer()
时会抛出。你将采用与变式1完全相同的步骤,但是在使用新的
Buffer
API的所有文件中都使用polyfillconst Buffer = require('safer-buffer').Buffer
。
不要使用旧的new Buffer()
API,在添加上面一行的任何文件中,使用旧的new Buffer()
API将抛出。 - buffer-from和/或buffer-alloc是
Buffer
API各自部分的ponyfill,你只需添加与你正在使用的API相对应的包。你可以使用适当的名称导入所需的模块,例如
const bufferFrom = require('buffer-from')
然后使用它而不是调用new Buffer()
,例如:new Buffer('test')
变为bufferFrom('test')
。使用这种方法的一个缺点是从它们迁移出来的代码更改略多(因为你将使用不同名称下的
Buffer.from()
)。 - safe-buffer也是整个
Buffer
API的替代品,但使用new Buffer()
仍然可以像以前一样工作。这种方法的缺点是它允许你在代码中使用较旧的
new Buffer()
API,这是有问题的,因为它可能会导致代码中出现问题,并将从Node.js 10开始发出运行时弃用警告(在此处阅读更多内容)。
请注意,在任何一种情况下,你还必须手动删除对旧Buffer
API的所有调用,只是投入safe-buffer
本身并不能解决问题,它只是为新API提供了一个polyfill,我看到有人犯了这个错误。
建议启用ESLint规则no-buffer-constructor或node/no-deprecated-api。
放弃对Node.js <4.5.0的支持后,不要忘记删除polyfill使用。
变式3 - 手动检测,带有安全措施
如果你只在几个地方(例如一个)创建Buffer
实例,或者你有自己的包装器,这将非常有用。
Buffer(0)
这个用于创建空缓冲区的特殊情况可以安全地替换为Buffer.concat([])
,它返回相同的结果一直到Node.js 0.8.x。
Buffer(notNumber)
之前:
const buf = new Buffer(notNumber, encoding);
以后:
let buf;
if (Buffer.from && Buffer.from !== Uint8Array.from) {
buf = Buffer.from(notNumber, encoding);
} else {
if (typeof notNumber === 'number') {
throw new Error('The "size" argument must be not of type number.');
}
buf = new Buffer(notNumber, encoding);
}
encoding
是可选的。
请注意,typeof notNumber
必须在new Buffer()
之前,(对于notNumber
参数未进行硬编码的情况)并且不是由Buffer
构造函数的弃用引起的 - 这正是不推荐使用Buffer
构造函数的原因。缺乏此类型检查的生态系统包导致了许多安全问题 - 当未经过处理的用户输入可能最终出现在Buffer(arg)
中时,会出现从DoS到从进程内存向攻击者泄漏敏感信息等问题。
当notNumber
参数被硬编码时(例如文字"abc"
或[0,1,2]
),可以省略typeof
检查。
另请注意,使用TypeScript
不能解决此问题 - 当从JS中使用用TypeScript
编写的库时,或者当用户输入结束时 - 它的行为与纯JS一样,因为所有类型检查只是转换时间,并且不存在于TS编译的实际JS代码中。
Buffer(number)
对于Node.js 0.10.x(及以下)支持:
var buf;
if (Buffer.alloc) {
buf = Buffer.alloc(number);
} else {
buf = new Buffer(number);
buf.fill(0);
}
否则(Node.js ≥ 0.12.x):
const buf = Buffer.alloc ? Buffer.alloc(number) : new Buffer(number).fill(0);
关于Buffer.allocUnsafe()
使用Buffer.allocUnsafe()
时要格外小心:
如果你没有充分的理由,请不要使用它。
- 例如你可能永远不会看到小缓冲区的性能差异,事实上,使用
Buffer.alloc()
可能会更快。 - 如果你的代码不在热代码路径中 - 你也可能不会注意到差异。
- 请记住,零填充可以最大限度地降低潜在风险。
- 例如你可能永远不会看到小缓冲区的性能差异,事实上,使用
如果使用它,请确保永远不会以部分填充状态返回buffer。
- 如果你按顺序写它 - 总是将它截断为实际的书写长度。
处理使用Buffer.allocUnsafe()
分配的缓冲区中的错误可能会导致各种问题,包括代码的未定义行为,以及泄露给远程攻击者的敏感数据(用户输入、密码、证书)。
请注意,这同样适用于没有零填充的new Buffer()
用法,具体取决于Node.js版本(缺少类型检查也会将DoS添加到潜在问题列表中)。
常问问题
Buffer
构造函数有什么问题?
Buffer
构造函数可用于以多种不同方式创建缓冲区:
new Buffer(42)
创建一个42字节的Buffer
,在Node.js 8之前,由于性能原因,此缓冲区包含任意内存,其中可能包括从程序源代码到密码和加密密钥的任何内容。new Buffer('abc')
创建一个Buffer
,其中包含字符串'abc'
的UTF-8编码版本,第二个参数可以指定另一个编码:例如,可以使用new Buffer(string, 'base64')
将Base64字符串转换为它所代表的原始字节序列。- 还有其他几种参数组合。
这意味着在像var buffer = new Buffer(foo);
这样的代码中,在不知道foo
类型的情况下,无法确定生成的缓冲区的确切内容。
有时,foo
的值来自外部来源,例如,此函数可以作为Web服务器上的服务公开,将UTF-8字符串转换为其Base64格式:
function stringToBase64(req, res) {
// The request body should have the format of `{ string: 'foobar' }`.
const rawBytes = new Buffer(req.body.string);
const encoded = rawBytes.toString('base64');
res.end({ encoded });
}
请注意,此代码不验证req.body.string
的类型:
req.body.string
应该是一个字符串,如果是这种情况,一切顺利。req.body.string
由发送请求的客户端控制。如果
req.body.string
是数字50
,则rawBytes
将是50
个字节:- 在Node.js 8之前,内容将是未初始化的。
- 在Node.js 8之后,内容将是
50
个字节,值为0
。
由于缺少类型检查,攻击者可以故意发送一个号码作为请求的一部分,使用它,他们可以:
- 读取未初始化的内存,这将泄露密码、加密密钥和其他类型的敏感信息(信息泄露)。
- 强制程序分配大量内存,例如,当指定
500000000
作为输入值时,每个请求将分配500MB的内存,这可以用来完全耗尽程序可用的内存并使其崩溃,或者显着减慢程序速度(拒绝服务)。
在现实世界的Web服务器环境中,这两种情况都被认为是严重的安全问题。
当使用Buffer.from(req.body.string)
时,传递一个数字将总是抛出一个异常,提供可由程序始终处理的受控行为。
Buffer()
构造函数已被弃用了一段时间,这真的是一个问题吗?
npm
生态系统中的代码调查表明,Buffer()
构造函数仍然被广泛使用,这包括新代码,并且此类代码的总体使用实际上已经增加。
上一篇:Docker化Node.js Web应用程序
原文地址:https://segmentfault.com/a/1190000016989236
Node.js 指南(迁移到安全的Buffer构造函数)的更多相关文章
- 《深入浅出Node.js》第6章 理解 Buffer
@by Ruth92(转载请注明出处) 第6章 理解 Buffer ✁ 为什么需要 Buffer? 在 Node 中,应用需要处理网络协议.操作数据库.处理图片.接收上传文件等,在网络流和文件的操作中 ...
- 完全面向于初学者的Node.js指南
新的上班时间是周二至周六,工作之余当然要坚持学习啦. 希望这篇文章能解决你这样一个问题:“我现在已经下载好Node.Js了,该做些什么呢?” 原文URL:http://blog.modulus.io/ ...
- node.js官方文档解析 02—buffer 缓冲器
Buffer 类的实例类似于整数数组,但 Buffer 的大小是固定的.且在 V8 堆外分配物理内存.Buffer 的大小在被创建时确定,且无法调整. Buffer 类在 Node.js 中是一个全局 ...
- Node.js处理I/O数据之Buffer模块缓冲数据
一.前传 在之前做web时也经常用到js对象转json和json转js对象.既然是Node.js处理I/O数据,也把这个记下来. Json转Js对象:JSON.parse(jsonstr); //可以 ...
- 【转】使用VS开发 Node.js指南
参考:https://www.visualstudio.com/features/node-js-vs 这篇文章主要介绍了使用VS开发 Node.js的方法,主要是使用NTVS(Node.js Too ...
- Node.js实战7:你了解buffer吗?
Buffer是NodeJS的重要数据类型,很有广泛的应用. Buffer是代表原始堆的分配额的数据类型.在NodeJS中以类数组的方式使用. 比如,用法示例: var buf = new Buffer ...
- Node.js小白开路(一)-- Buffer篇
Buffer是nodeJS中的二进制缓存操作模块内容.先来看一段简短的代码. // 创建一个长度为 10.且用 0 填充的 Buffer. const buf1 = Buffer.alloc(10); ...
- 11慕课网《进击Node.js基础(一)》Buffer和Stream
Buffer 用来保存原始数据 (logo.png) 以下代码读取logo.png为buffer类型 然后将buffer转化为string,新建png 可以将字符串配置: data:image/png ...
- Node.js学习 - Buffer
JavaScript 语言自身只有字符串数据类型,没有二进制数据类型.但在处理像TCP流或文件流时,必须使用到二进制数据. 因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门 ...
随机推荐
- springmvc中配置拦截器
-------------------------------------------- 登陆controller方法 @Controller public class LoginController ...
- 编译打包部署 Dubbo Admin
1.下载,Dubbo地址: https://github.com/alibaba/dubbo/tree/2.5.x ,直接ZIP下载 2.解压并打开项目,mvn package 得到war包,如下图: ...
- Spring 让 LOB 数据操作变得简单易行
概述 LOB 代表大对象数据,包括 BLOB 和 CLOB 两种类型,前者用于存储大块的二进制数据,如图片数据,视频数据等,而后者用于存储长文本数据,如论坛的帖子内容,产品的详细描述等.值得注意的是: ...
- Spring使用HibernateDaoSupport操作数据
spring提供了一个数据訪问层的类:org.springframework.orm.hibernate3.support.HibernateDaoSupport.一般是让 dao继承该类,然后在da ...
- linux下jenkins安装
在安装jenkins之前.首先确认jdk和tomcat,maven已经配置好 详细配置方法,请看的我博客. jdk:jdk的安装与配置 tomcat:tomcat的安装与配置 maven:maven的 ...
- POJ训练计划3422_Kaka's Matrix Travels(网络流/费用流)
解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次仅仅能向右和向下走,走到一个格子上加上格子的数,能够走k次.问最大的和是多少. 思路: 建图:每一个格子掰成两个点,分别叫" ...
- 用opencv实现的PCA算法,非API调用
理论參考文献:但此文没有代码实现.这里自己实现一下,让理解更为深刻 问题:如果在IR中我们建立的文档-词项矩阵中,有两个词项为"learn"和"study",在 ...
- 微软ASP.NET网站部署指南(3):使用Web.Config文件的Transformations
1. 综述 大多数程序里都会在Web.config里设置參数,而且在部署的时候须要更改. 每次都手工更改这些配置非常乏味,也easy出错. 该章节将会告诉你假设通过自己主动化更新Web.config文 ...
- Ubuntu下的用户和权限(三)
七.增删群组相关的命令 相同的我们要先介绍两个重要的设定档:/etc/group和/etc/gshadow,前面那个事实上和/etc/passwd一样.而后者就是群组的password表了.先看看长啥 ...
- 编译Redis系统提示缺少gcc,可以使用yum进行安装:
yum -y install gcc yum -y install gcc-c++ yum install make -- 或者 yum groupinstall "Development ...