safer-buffer
Advanced tools
Comparing version 2.0.2 to 2.1.0
{ | ||
"name": "safer-buffer", | ||
"version": "2.0.2", | ||
"version": "2.1.0", | ||
"description": "Modern Buffer API polyfill without footguns", | ||
@@ -5,0 +5,0 @@ "main": "safer.js", |
@@ -62,3 +62,3 @@ # Porting to the Buffer.from/Buffer.alloc API | ||
- For `new Buffer(number)`, replace it with `Buffer.alloc(number)`. | ||
- For `new Buffer(string)` (or `new Buffer(string, encoding)`), replace it with `Buffer.from(string)` (or `new Buffer(string, encoding)`). | ||
- For `new Buffer(string)` (or `new Buffer(string, encoding)`), replace it with `Buffer.from(string)` (or `Buffer.from(string, encoding)`). | ||
- For all other combinations of arguments (these are much rarer), also replace `new Buffer(...arguments)` with `Buffer.from(...arguments)`. | ||
@@ -74,2 +74,7 @@ | ||
There is also a [JSCodeshift codemod](https://github.com/joyeecheung/node-dep-codemod#dep005) | ||
for automatically migrating Buffer constructors to `Buffer.alloc()` or `Buffer.from()`. | ||
Note that it currently only works with cases where the arguments are literals or where the | ||
constructor is invoked with two arguments. | ||
_If you currently support those older Node.js versions and dropping them would be a semver-major change | ||
@@ -194,1 +199,65 @@ for you, or if you support older branches of your packages, consider using [Variant 2](#variant-2) | ||
version (and lacking type checks also adds DoS to the list of potential problems)._ | ||
<a id="faq"></a> | ||
## FAQ | ||
<a id="design-flaws"></a> | ||
### What is wrong with the `Buffer` constructor? | ||
The `Buffer` constructor could be used to create a buffer in many different ways: | ||
- `new Buffer(42)` creates a `Buffer` of 42 bytes. Before Node.js 8, this buffer contained | ||
*arbitrary memory* for performance reasons, which could include anything ranging from | ||
program source code to passwords and encryption keys. | ||
- `new Buffer('abc')` creates a `Buffer` that contains the UTF-8-encoded version of | ||
the string `'abc'`. A second argument could specify another encoding: For example, | ||
`new Buffer(string, 'base64')` could be used to convert a Base64 string into the original | ||
sequence of bytes that it represents. | ||
- There are several other combinations of arguments. | ||
This meant that, in code like `var buffer = new Buffer(foo);`, *it is not possible to tell | ||
what exactly the contents of the generated buffer are* without knowing the type of `foo`. | ||
Sometimes, the value of `foo` comes from an external source. For example, this function | ||
could be exposed as a service on a web server, converting a UTF-8 string into its Base64 form: | ||
``` | ||
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: encoded }) | ||
} | ||
``` | ||
Note that this code does *not* validate the type of `req.body.string`: | ||
- `req.body.string` is expected to be a string. If this is the case, all goes well. | ||
- `req.body.string` is controlled by the client that sends the request. | ||
- If `req.body.string` is the *number* `50`, the `rawBytes` would be 50 bytes: | ||
- Before Node.js 8, the content would be uninitialized | ||
- After Node.js 8, the content would be `50` bytes with the value `0` | ||
Because of the missing type check, an attacker could intentionally send a number | ||
as part of the request. Using this, they can either: | ||
- Read uninitialized memory. This **will** leak passwords, encryption keys and other | ||
kinds of sensitive information. (Information leak) | ||
- Force the program to allocate a large amount of memory. For example, when specifying | ||
`500000000` as the input value, each request will allocate 500MB of memory. | ||
This can be used to either exhaust the memory available of a program completely | ||
and make it crash, or slow it down significantly. (Denial of Service) | ||
Both of these scenarios are considered serious security issues in a real-world | ||
web server context. | ||
when using `Buffer.from(req.body.string)` instead, passing a number will always | ||
throw an exception instead, giving a controlled behaviour that can always be | ||
handled by the program. | ||
<a id="ecosystem-usage"></a> | ||
### The `Buffer()` constructor has been deprecated for a while. Is this really an issue? | ||
Surveys of code in the `npm` ecosystem have shown that the `Buffer()` constructor is still | ||
widely used. This includes new code, and overall usage of such code has actually been | ||
*increasing*. |
@@ -128,2 +128,20 @@ # safer-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![javascript style guide][standard-image]][standard-url] [![Security Responsible Disclosure][secuirty-image]][secuirty-url] | ||
### But I don't want throwing… | ||
That is also fine! | ||
Also, it could be better in some cases when you don't comprehensive enough test coverage. | ||
In that case — just don't override `Buffer` and use | ||
`var SaferBuffer = require('safer-buffer').Buffer` instead. | ||
That way, everything using `Buffer` natively would still work, but there would be two drawbacks: | ||
* `Buffer.from`/`Buffer.alloc` won't be polyfilled — use `SaferBuffer.from` and | ||
`SaferBuffer.alloc` instead. | ||
* You are still open to accidentally using the insecure deprecated API — use a linter to catch that. | ||
Note that using a linter to catch accidential `Buffer` constructor usage in this case is strongly | ||
recommended. `Buffer` is not overriden in this usecase, so linters won't get confused. | ||
## «Without footguns»? | ||
@@ -130,0 +148,0 @@ |
@@ -25,2 +25,4 @@ /* eslint-disable node/no-deprecated-api */ | ||
safer.Buffer.prototype = Buffer.prototype | ||
if (!Safer.from || Safer.from === Uint8Array.from) { | ||
@@ -27,0 +29,0 @@ Safer.from = function (value, encodingOrOffset, length) { |
@@ -100,2 +100,10 @@ /* eslint-disable node/no-deprecated-api */ | ||
test('.prototype property of Buffer is inherited', function (t) { | ||
[index, safer, dangerous].forEach(function (impl) { | ||
t.equal(impl.Buffer.prototype, buffer.Buffer.prototype, 'prototype') | ||
t.notEqual(typeof impl.Buffer.prototype, 'undefined', 'prototype') | ||
}) | ||
t.end() | ||
}) | ||
test('All Safer methods are present in Dangerous', function (t) { | ||
@@ -102,0 +110,0 @@ Object.keys(safer).forEach(function (method) { |
41366
481
157