Description
Permission Model initial issue
Hello everybody!
Following up on the Security Model initiative and the Mini summit (Next-10) in April seems and consensus that Node.js aims to have a security permission system, thus, avoiding third-party libraries to access machine resources without user consent.
This system was previously researched by James Snell and Anna Henningsen[1], which resulted in an excellent material as a starting point.
For context, the material is available through those links:
- Adding a permission system to Node.js blog post
- [WIP] src,lib: policy permissions node#33504
- process: initial impl of feature access control node#22112
Constraints
This security model is not bulletproof, which means, there are constraints we agree on before implementing this system:
- It’s not a sandbox, we assume the user trusts in the running code
- Example: the user sets the flag
--allow-fs-read
without specifying a scope. Any external library can make use of it leading to a potential exploit. In this case, with the user's consent.
- Example: the user sets the flag
- No break-changes are ideal.
- It must add a low/no overhead when disabled and low overhead when enabled.
Points to be discussed
This is a big topic that could lead to several discussions topics. In order to avoid unnecessary discussions at this moment, let's use the following 3 topics as boundaries for this first iteration.
- Should it be
process
or module scoped?
The effort to make it work with modules is worth it? Example:
{
"name": "package-name",
"version": "1.0.0",
"description": "",
"main": "index.js",
"permissions": [
"fs"
]
}
Then the user should provide permission for each module (as you need to do in your smartphone apps)
- Should the user be able to change the permissions in runtime?
If yes, how does it behave in an Asynchronous Context? Example:
const { setTimeout } = require('timers/promises');
console.log(process.policy.check('net')); // true
process.nextTick(() => {
process.policy.deny('net');
setTimeout(1000).then(() => {
console.log(process.policy.check('net')); // false
});
});
process.nextTick(() => {
setTimeout(1000).then(() => {
console.log(process.policy.check('net')); // ???
});
});
- What would be the desired granularity level?
--policy-deny=fs
or--policy-deny=fs.in
?--policy-deny=net
or--policy-deny=net.tcp.in
?- Should the user be capable to restrict specific TCP ports, for instance, denying all inbound packages at port 3000?
- Is
Deno
granularity enough?--allow-read
--allow-net