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.js4.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.js4.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.js0.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