-
Notifications
You must be signed in to change notification settings - Fork 30.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
buffer: add Buffer.harden() method #28439
Conversation
Something like this should only be activated by a command-line flag. Having it changeable during runtime via an API could cause confusion and potential breakage, especially if a third-party module calls it unexpectedly. |
@mscdex, this is deliberately not callable from a third-party module. On the contrary – this API attempts to block modules from meddling with Buffer impl at runtime, which is something that they are currently perfectly able to do. I.e. this API could already be mostly emulated from userland with monkeypatching Buffer. There were concerns voiced about CLI flags being less available in certain setups, and those are generally harder to use. |
I am not fully sure about the behavior it could trigger inb a module using Buffer poorly. Do you have ideas of what could happen in such cases? |
Great feature! I personally prefer a cli flag as well. |
@vdeturckheim Poorly in which way? It now ignores modules attempting to change The point is to make potential malicious code in ecosystem modules more noticable upon review and limit what it can subtly do with |
@ChALkeR I think so to, I can't find any good reason not to have this :D |
@vdeturckheim Ah, and this is an explicit opt-in. @mafintosh About bundles -- that is something that have to be looked at, but I don't expect problems here for two reasons:
That would require testing to at least know what would happen, though. @mafintosh @mscdex About CLI flag, there are several reasons why I decided against that atm:
What could resolve all of that (except for 4) is an additional CLI flag on top of this that would require call to What would solve 4 is introducing that flag in a separate follow-up PR if that is something that everyone would want. |
One more way to enforce the "only top-level code can call this" rule even further would be to make sure that this can be called only before any requires of any third-party code from What does everyone think about that? I can implement that if that sounds like a good idea. Also, perhaps, during only the first tick (that would make sense for enforcement cli flags). |
lib/buffer.js
Outdated
}); | ||
Object.freeze(Buffer); | ||
Object.freeze(Buffer.prototype); | ||
Object.freeze(module.exports); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Frozen object are slower. How much slower in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that's true. It used to be a long time ago, but they should be the same as regular objects these days.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some indirect tests still shows regressions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mcollina I will run benchmarks on this.
But I don't expect that frozen objects would be what would causes the most of performance hit here, Buffer.harden()
also enables zero-filling for allocUnsafe and disables buffer pooling completely, I expect that to me more noticable.
This whole PR comes with an (opt-in) perf hit that would be documented once I get the numbers.
The primary targets for opt-in hardening are not performance-sensitive backend setups, but pretty much everything else.
I don't understand this argument. Users could easily opt-in/out of a specific configuration, even for *aaS. |
IMO, #27645 (comment) doesn't indicate that CLI flags are hard to set from a technical perspective, but that customers are unwilling to be personally responsible for relaxing a security constraint. In this case, the flag tightens security, so I don't see it as relevant. Both CLI/ENV and API are reasonable ways to (simultaneously) expose this capability. |
I'd want to think/talk about the name ( @ChALkeR Are you still working on this? What would help get this out of draft mode? You need to run some benchmarks and look at some other things? (Anything you need/want from other people? More reviews?) |
@Trott I will update this shortly this week, adding some docs. I am also not very sure about freezing the Buffer prototype on the second thought, that will affect child objects and make e.g. $ node
> Object.freeze(Buffer.prototype);
> const x = Buffer.from('hello');
> x.toString = () => 'no';
> x.toString()
'hello' That has a potential of breaking things, investigating how significant is that with Buffer. |
function tryBuffer() {
function Foo(x) {
const buf = Buffer.from(x)
Object.setPrototypeOf(buf, Foo.prototype)
return buf
}
Foo.prototype = Object.create(Buffer.prototype);
Foo.prototype.toString = () => 'bar'
const foo = new Foo('foo')
return foo.toString()
}
console.log(tryBuffer()) // 'bar'
Object.freeze(Buffer.prototype)
console.log(tryBuffer()) // 'foo' |
Changes:
|
8810a3d
to
3539ad3
Compare
@mscdex @sam-github About CLI flag, I would prefer if it would be added in a way that would enforce using
I plan to do that as a follow-up PR once this lands, e.g. in a way of |
Tests are still missing, but I will add them. @mscdex I considered policy files. Once again -- it will hit significantly less adoption and have less effect on the ecosystem, also harder to add callbacks for future harden policies. Also harder to deploy apps. E.g. this would be a one-liner for command-line apps published npm, and adding policy files would be complex enough so approximately zero packages would do that. Policy files would have much less security impact on the ecosystem than I want to achieve. We could support defining this in policy files, but I still think that this API is justified even if we do that, and that we could add policy files support later, if needed. |
I just pushed an update to label this as Experimental in the docs, per the TSC meeting discussion. |
Co-Authored-By: mscdex <mscdex@users.noreply.github.com>
This should not land without tests. I still really don’t like the artificial restrictions on when this method is callable here, and I’d also still prefer being able to set this through a CLI flag (which has another advantage, namely that Workers inherit these options by default, as they should imo). |
8ae28ff
to
2935f72
Compare
Ping @ChALkeR... still want to do this? |
This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open. |
Closing this because it has stalled. Feel free to reopen if this PR is still relevant, or to ping the collaborator who labelled it stalled if you have any questions. |
This is a strawperson currently, targeted at resolving Buffer controversies and providing an alternate safer Buffer API that could be opted in from the top level app code. This should both resolve potential concerns about Buffer unsafety (that are otherwise non-resolvable in general for performance reasons) and give ecosystem another nudge to migrate off unsafe deprecated
Buffer(arg)
API.This adds
Buffer.harden()
method that:Buffer.allocUnsafe()
(similar to--zero-fill-buffers
CLI flag).Buffer(arg)
Buffer
object.That method is callable only from the top-level app, it will throw when called from dependencies (reuses already existing
isInsideNodeModules()
check for that).Example:
Unresolved:
/cc @nodejs/security-wg @nodejs/security @nodejs/buffer @mafintosh -- comments?
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes