11cb0ef41Sopenharmony_ci# Porting to the Buffer.from/Buffer.alloc API 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_ci<a id="overview"></a> 41cb0ef41Sopenharmony_ci## Overview 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci- [Variant 1: Drop support for Node.js ≤ 4.4.x and 5.0.0 — 5.9.x.](#variant-1) (*recommended*) 71cb0ef41Sopenharmony_ci- [Variant 2: Use a polyfill](#variant-2) 81cb0ef41Sopenharmony_ci- [Variant 3: manual detection, with safeguards](#variant-3) 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci### Finding problematic bits of code using grep 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ciJust run `grep -nrE '[^a-zA-Z](Slow)?Buffer\s*\(' --exclude-dir node_modules`. 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciIt will find all the potentially unsafe places in your own code (with some considerably unlikely 151cb0ef41Sopenharmony_ciexceptions). 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci### Finding problematic bits of code using Node.js 8 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciIf you’re using Node.js ≥ 8.0.0 (which is recommended), Node.js exposes multiple options that help with finding the relevant pieces of code: 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci- `--trace-warnings` will make Node.js show a stack trace for this warning and other warnings that are printed by Node.js. 221cb0ef41Sopenharmony_ci- `--trace-deprecation` does the same thing, but only for deprecation warnings. 231cb0ef41Sopenharmony_ci- `--pending-deprecation` will show more types of deprecation warnings. In particular, it will show the `Buffer()` deprecation warning, even on Node.js 8. 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ciYou can set these flags using an environment variable: 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci```console 281cb0ef41Sopenharmony_ci$ export NODE_OPTIONS='--trace-warnings --pending-deprecation' 291cb0ef41Sopenharmony_ci$ cat example.js 301cb0ef41Sopenharmony_ci'use strict'; 311cb0ef41Sopenharmony_ciconst foo = new Buffer('foo'); 321cb0ef41Sopenharmony_ci$ node example.js 331cb0ef41Sopenharmony_ci(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. 341cb0ef41Sopenharmony_ci at showFlaggedDeprecation (buffer.js:127:13) 351cb0ef41Sopenharmony_ci at new Buffer (buffer.js:148:3) 361cb0ef41Sopenharmony_ci at Object.<anonymous> (/path/to/example.js:2:13) 371cb0ef41Sopenharmony_ci [... more stack trace lines ...] 381cb0ef41Sopenharmony_ci``` 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci### Finding problematic bits of code using linters 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciEslint rules [no-buffer-constructor](https://eslint.org/docs/rules/no-buffer-constructor) 431cb0ef41Sopenharmony_cior 441cb0ef41Sopenharmony_ci[node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) 451cb0ef41Sopenharmony_cialso find calls to deprecated `Buffer()` API. Those rules are included in some pre-sets. 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ciThere is a drawback, though, that it doesn't always 481cb0ef41Sopenharmony_ci[work correctly](https://github.com/chalker/safer-buffer#why-not-safe-buffer) when `Buffer` is 491cb0ef41Sopenharmony_cioverriden e.g. with a polyfill, so recommended is a combination of this and some other method 501cb0ef41Sopenharmony_cidescribed above. 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci<a id="variant-1"></a> 531cb0ef41Sopenharmony_ci## Variant 1: Drop support for Node.js ≤ 4.4.x and 5.0.0 — 5.9.x. 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ciThis is the recommended solution nowadays that would imply only minimal overhead. 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ciThe Node.js 5.x release line has been unsupported since July 2016, and the Node.js 4.x release line reaches its End of Life in April 2018 (→ [Schedule](https://github.com/nodejs/Release#release-schedule)). This means that these versions of Node.js will *not* receive any updates, even in case of security issues, so using these release lines should be avoided, if at all possible. 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciWhat you would do in this case is to convert all `new Buffer()` or `Buffer()` calls to use `Buffer.alloc()` or `Buffer.from()`, in the following way: 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci- For `new Buffer(number)`, replace it with `Buffer.alloc(number)`. 621cb0ef41Sopenharmony_ci- For `new Buffer(string)` (or `new Buffer(string, encoding)`), replace it with `Buffer.from(string)` (or `Buffer.from(string, encoding)`). 631cb0ef41Sopenharmony_ci- For all other combinations of arguments (these are much rarer), also replace `new Buffer(...arguments)` with `Buffer.from(...arguments)`. 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ciNote that `Buffer.alloc()` is also _faster_ on the current Node.js versions than 661cb0ef41Sopenharmony_ci`new Buffer(size).fill(0)`, which is what you would otherwise need to ensure zero-filling. 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ciEnabling eslint rule [no-buffer-constructor](https://eslint.org/docs/rules/no-buffer-constructor) 691cb0ef41Sopenharmony_cior 701cb0ef41Sopenharmony_ci[node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) 711cb0ef41Sopenharmony_ciis recommended to avoid accidential unsafe Buffer API usage. 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ciThere is also a [JSCodeshift codemod](https://github.com/joyeecheung/node-dep-codemod#dep005) 741cb0ef41Sopenharmony_cifor automatically migrating Buffer constructors to `Buffer.alloc()` or `Buffer.from()`. 751cb0ef41Sopenharmony_ciNote that it currently only works with cases where the arguments are literals or where the 761cb0ef41Sopenharmony_ciconstructor is invoked with two arguments. 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci_If you currently support those older Node.js versions and dropping them would be a semver-major change 791cb0ef41Sopenharmony_cifor you, or if you support older branches of your packages, consider using [Variant 2](#variant-2) 801cb0ef41Sopenharmony_cior [Variant 3](#variant-3) on older branches, so people using those older branches will also receive 811cb0ef41Sopenharmony_cithe fix. That way, you will eradicate potential issues caused by unguarded Buffer API usage and 821cb0ef41Sopenharmony_ciyour users will not observe a runtime deprecation warning when running your code on Node.js 10._ 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ci<a id="variant-2"></a> 851cb0ef41Sopenharmony_ci## Variant 2: Use a polyfill 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ciUtilize [safer-buffer](https://www.npmjs.com/package/safer-buffer) as a polyfill to support older 881cb0ef41Sopenharmony_ciNode.js versions. 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ciYou would take exacly the same steps as in [Variant 1](#variant-1), but with a polyfill 911cb0ef41Sopenharmony_ci`const Buffer = require('safer-buffer').Buffer` in all files where you use the new `Buffer` api. 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ciMake sure that you do not use old `new Buffer` API — in any files where the line above is added, 941cb0ef41Sopenharmony_ciusing old `new Buffer()` API will _throw_. It will be easy to notice that in CI, though. 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ciAlternatively, you could use [buffer-from](https://www.npmjs.com/package/buffer-from) and/or 971cb0ef41Sopenharmony_ci[buffer-alloc](https://www.npmjs.com/package/buffer-alloc) [ponyfills](https://ponyfill.com/) — 981cb0ef41Sopenharmony_cithose are great, the only downsides being 4 deps in the tree and slightly more code changes to 991cb0ef41Sopenharmony_cimigrate off them (as you would be using e.g. `Buffer.from` under a different name). If you need only 1001cb0ef41Sopenharmony_ci`Buffer.from` polyfilled — `buffer-from` alone which comes with no extra dependencies. 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci_Alternatively, you could use [safe-buffer](https://www.npmjs.com/package/safe-buffer) — it also 1031cb0ef41Sopenharmony_ciprovides a polyfill, but takes a different approach which has 1041cb0ef41Sopenharmony_ci[it's drawbacks](https://github.com/chalker/safer-buffer#why-not-safe-buffer). It will allow you 1051cb0ef41Sopenharmony_cito also use the older `new Buffer()` API in your code, though — but that's arguably a benefit, as 1061cb0ef41Sopenharmony_ciit is problematic, can cause issues in your code, and will start emitting runtime deprecation 1071cb0ef41Sopenharmony_ciwarnings starting with Node.js 10._ 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ciNote that in either case, it is important that you also remove all calls to the old Buffer 1101cb0ef41Sopenharmony_ciAPI manually — just throwing in `safe-buffer` doesn't fix the problem by itself, it just provides 1111cb0ef41Sopenharmony_cia polyfill for the new API. I have seen people doing that mistake. 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ciEnabling eslint rule [no-buffer-constructor](https://eslint.org/docs/rules/no-buffer-constructor) 1141cb0ef41Sopenharmony_cior 1151cb0ef41Sopenharmony_ci[node/no-deprecated-api](https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-deprecated-api.md) 1161cb0ef41Sopenharmony_ciis recommended. 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci_Don't forget to drop the polyfill usage once you drop support for Node.js < 4.5.0._ 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci<a id="variant-3"></a> 1211cb0ef41Sopenharmony_ci## Variant 3 — manual detection, with safeguards 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ciThis is useful if you create Buffer instances in only a few places (e.g. one), or you have your own 1241cb0ef41Sopenharmony_ciwrapper around them. 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_ci### Buffer(0) 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ciThis special case for creating empty buffers can be safely replaced with `Buffer.concat([])`, which 1291cb0ef41Sopenharmony_cireturns the same result all the way down to Node.js 0.8.x. 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci### Buffer(notNumber) 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ciBefore: 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci```js 1361cb0ef41Sopenharmony_civar buf = new Buffer(notNumber, encoding); 1371cb0ef41Sopenharmony_ci``` 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ciAfter: 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci```js 1421cb0ef41Sopenharmony_civar buf; 1431cb0ef41Sopenharmony_ciif (Buffer.from && Buffer.from !== Uint8Array.from) { 1441cb0ef41Sopenharmony_ci buf = Buffer.from(notNumber, encoding); 1451cb0ef41Sopenharmony_ci} else { 1461cb0ef41Sopenharmony_ci if (typeof notNumber === 'number') 1471cb0ef41Sopenharmony_ci throw new Error('The "size" argument must be of type number.'); 1481cb0ef41Sopenharmony_ci buf = new Buffer(notNumber, encoding); 1491cb0ef41Sopenharmony_ci} 1501cb0ef41Sopenharmony_ci``` 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci`encoding` is optional. 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ciNote that the `typeof notNumber` before `new Buffer` is required (for cases when `notNumber` argument is not 1551cb0ef41Sopenharmony_cihard-coded) and _is not caused by the deprecation of Buffer constructor_ — it's exactly _why_ the 1561cb0ef41Sopenharmony_ciBuffer constructor is deprecated. Ecosystem packages lacking this type-check caused numereous 1571cb0ef41Sopenharmony_cisecurity issues — situations when unsanitized user input could end up in the `Buffer(arg)` create 1581cb0ef41Sopenharmony_ciproblems ranging from DoS to leaking sensitive information to the attacker from the process memory. 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_ciWhen `notNumber` argument is hardcoded (e.g. literal `"abc"` or `[0,1,2]`), the `typeof` check can 1611cb0ef41Sopenharmony_cibe omitted. 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ciAlso note that using TypeScript does not fix this problem for you — when libs written in 1641cb0ef41Sopenharmony_ci`TypeScript` are used from JS, or when user input ends up there — it behaves exactly as pure JS, as 1651cb0ef41Sopenharmony_ciall type checks are translation-time only and are not present in the actual JS code which TS 1661cb0ef41Sopenharmony_cicompiles to. 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_ci### Buffer(number) 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ciFor Node.js 0.10.x (and below) support: 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci```js 1731cb0ef41Sopenharmony_civar buf; 1741cb0ef41Sopenharmony_ciif (Buffer.alloc) { 1751cb0ef41Sopenharmony_ci buf = Buffer.alloc(number); 1761cb0ef41Sopenharmony_ci} else { 1771cb0ef41Sopenharmony_ci buf = new Buffer(number); 1781cb0ef41Sopenharmony_ci buf.fill(0); 1791cb0ef41Sopenharmony_ci} 1801cb0ef41Sopenharmony_ci``` 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ciOtherwise (Node.js ≥ 0.12.x): 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci```js 1851cb0ef41Sopenharmony_ciconst buf = Buffer.alloc ? Buffer.alloc(number) : new Buffer(number).fill(0); 1861cb0ef41Sopenharmony_ci``` 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci## Regarding Buffer.allocUnsafe 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ciBe extra cautious when using `Buffer.allocUnsafe`: 1911cb0ef41Sopenharmony_ci * Don't use it if you don't have a good reason to 1921cb0ef41Sopenharmony_ci * e.g. you probably won't ever see a performance difference for small buffers, in fact, those 1931cb0ef41Sopenharmony_ci might be even faster with `Buffer.alloc()`, 1941cb0ef41Sopenharmony_ci * if your code is not in the hot code path — you also probably won't notice a difference, 1951cb0ef41Sopenharmony_ci * keep in mind that zero-filling minimizes the potential risks. 1961cb0ef41Sopenharmony_ci * If you use it, make sure that you never return the buffer in a partially-filled state, 1971cb0ef41Sopenharmony_ci * if you are writing to it sequentially — always truncate it to the actuall written length 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ciErrors in handling buffers allocated with `Buffer.allocUnsafe` could result in various issues, 2001cb0ef41Sopenharmony_ciranged from undefined behaviour of your code to sensitive data (user input, passwords, certs) 2011cb0ef41Sopenharmony_cileaking to the remote attacker. 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci_Note that the same applies to `new Buffer` usage without zero-filling, depending on the Node.js 2041cb0ef41Sopenharmony_civersion (and lacking type checks also adds DoS to the list of potential problems)._ 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci<a id="faq"></a> 2071cb0ef41Sopenharmony_ci## FAQ 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci<a id="design-flaws"></a> 2101cb0ef41Sopenharmony_ci### What is wrong with the `Buffer` constructor? 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ciThe `Buffer` constructor could be used to create a buffer in many different ways: 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci- `new Buffer(42)` creates a `Buffer` of 42 bytes. Before Node.js 8, this buffer contained 2151cb0ef41Sopenharmony_ci *arbitrary memory* for performance reasons, which could include anything ranging from 2161cb0ef41Sopenharmony_ci program source code to passwords and encryption keys. 2171cb0ef41Sopenharmony_ci- `new Buffer('abc')` creates a `Buffer` that contains the UTF-8-encoded version of 2181cb0ef41Sopenharmony_ci the string `'abc'`. A second argument could specify another encoding: For example, 2191cb0ef41Sopenharmony_ci `new Buffer(string, 'base64')` could be used to convert a Base64 string into the original 2201cb0ef41Sopenharmony_ci sequence of bytes that it represents. 2211cb0ef41Sopenharmony_ci- There are several other combinations of arguments. 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ciThis meant that, in code like `var buffer = new Buffer(foo);`, *it is not possible to tell 2241cb0ef41Sopenharmony_ciwhat exactly the contents of the generated buffer are* without knowing the type of `foo`. 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ciSometimes, the value of `foo` comes from an external source. For example, this function 2271cb0ef41Sopenharmony_cicould be exposed as a service on a web server, converting a UTF-8 string into its Base64 form: 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci``` 2301cb0ef41Sopenharmony_cifunction stringToBase64(req, res) { 2311cb0ef41Sopenharmony_ci // The request body should have the format of `{ string: 'foobar' }` 2321cb0ef41Sopenharmony_ci const rawBytes = new Buffer(req.body.string) 2331cb0ef41Sopenharmony_ci const encoded = rawBytes.toString('base64') 2341cb0ef41Sopenharmony_ci res.end({ encoded: encoded }) 2351cb0ef41Sopenharmony_ci} 2361cb0ef41Sopenharmony_ci``` 2371cb0ef41Sopenharmony_ci 2381cb0ef41Sopenharmony_ciNote that this code does *not* validate the type of `req.body.string`: 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci- `req.body.string` is expected to be a string. If this is the case, all goes well. 2411cb0ef41Sopenharmony_ci- `req.body.string` is controlled by the client that sends the request. 2421cb0ef41Sopenharmony_ci- If `req.body.string` is the *number* `50`, the `rawBytes` would be 50 bytes: 2431cb0ef41Sopenharmony_ci - Before Node.js 8, the content would be uninitialized 2441cb0ef41Sopenharmony_ci - After Node.js 8, the content would be `50` bytes with the value `0` 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ciBecause of the missing type check, an attacker could intentionally send a number 2471cb0ef41Sopenharmony_cias part of the request. Using this, they can either: 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci- Read uninitialized memory. This **will** leak passwords, encryption keys and other 2501cb0ef41Sopenharmony_ci kinds of sensitive information. (Information leak) 2511cb0ef41Sopenharmony_ci- Force the program to allocate a large amount of memory. For example, when specifying 2521cb0ef41Sopenharmony_ci `500000000` as the input value, each request will allocate 500MB of memory. 2531cb0ef41Sopenharmony_ci This can be used to either exhaust the memory available of a program completely 2541cb0ef41Sopenharmony_ci and make it crash, or slow it down significantly. (Denial of Service) 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_ciBoth of these scenarios are considered serious security issues in a real-world 2571cb0ef41Sopenharmony_ciweb server context. 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ciwhen using `Buffer.from(req.body.string)` instead, passing a number will always 2601cb0ef41Sopenharmony_cithrow an exception instead, giving a controlled behaviour that can always be 2611cb0ef41Sopenharmony_cihandled by the program. 2621cb0ef41Sopenharmony_ci 2631cb0ef41Sopenharmony_ci<a id="ecosystem-usage"></a> 2641cb0ef41Sopenharmony_ci### The `Buffer()` constructor has been deprecated for a while. Is this really an issue? 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ciSurveys of code in the `npm` ecosystem have shown that the `Buffer()` constructor is still 2671cb0ef41Sopenharmony_ciwidely used. This includes new code, and overall usage of such code has actually been 2681cb0ef41Sopenharmony_ci*increasing*. 269