It looks like a good evolutionary improvement over Node.js. However, I have a concern about its security claims. Perhaps someone on the project can allay these concerns.
My brief skimming of its site indicates that its security model is based around the ability to disable, say, network access for whole Deno programs. However, does it allow starting up with network access, allowing a subset of the program to handle it, and then dropping those rights for the rest of the program, _especially_ subdependencies?
A modern Node.js web service will have hundreds, if not thousands, of indirect dependencies. Some network access will be required for at least the Express routing, or an equivalent.
For a Deno equivalent, this would amount to enabling network access for all hundreds of those subdependencies, not reproducing the isolation in capability-based security such as WebAssembly nanoprocesses.
Have I missed something here? That doesn't seem like much of an improvement over Node.js except for very small and contained programs. Yes, Deno's dropping of centralised package repositories and package.json might alleviate this problem _somewhat_, but the same fundamental issue seems to remain.
This prevents dependencies from using call back locations that are outside
the permitted list, preventing much of the nefarious activity they can dream up.
If a dependency needs access to specific resources, it can advertise this fact and the parent module can in turn request this from the user.
Importantly, the user is explicitly aware of these & controls it in an absolute sense, at run time.
The whitelisting looks great. Even with the remaining concerns I raised in the other comment, the ability to whitelist only allowed domains for network connections is a massive step up security-wise, even if they are allowed for the entire program (until revoked globally).
I'm not an expert on this in any sense, but would it be possible to add this into Node at the OS level, e.g. make use of network namespaces to restrict outbound network access?
Yeah, the OS or network firewall can do this, but security happens in layers, and to me it makes sense that an app config is the place to put a whitelist for the apps network needs.
If I was just spitballing an ideal scenario, I’d suggest that each module would define what it needs, and then some sort of central file would be built to hold the aggregate of them (urls / modules), for easy scanning.
The reason I’d rather have it in the app is if you are switching platforms, you don’t need to worry about firewall configs being exactly the same, or being fine grained. Also you might be whitelisting up ranges on the network level, then locking it down further on the app level.
> Importantly, the user is explicitly aware of these & controls it in an absolute sense, at run time.
I mean, I guess I see value there for the use case of "I want to download a script to run locally on my machine" type of thing, but for the most common use of Node, i.e. I'm running a server process, does this really even matter?
For most networked applications, there are two classes of permissions control - inbound and outbound.
The inbound is a run-time decision and dynamic at that - Firewalls, WAFs etc. are used for control. These are not (and probably should not) be set by the application author, but by the application operator.
The outbound however, is typically something that is designed into the application - it should be specified by the author, be available for auditing - both on first install and all subsequent changes. IMHO, this is where these whitelists shine.
For the server example you mention, whitelists don't prevent a malicious dependency from using your CPU for mining. With deno, by default, there is no way to dial-home the proof-of-work and collect the reward. Eventually, as the operator of the service, you'll notice a performance/cost problem and detect the malicious activity.
That's a good start, supporting the dropping of privileges after performing something on startup.
What about keeping the network allowed in the layer handling, say, inbound HTTP connections, but blocking it in the data access layer or purely computational component?
From what I can see, this doesn't work with global boolean flags in the runtime, instead requiring isolated tasks with whitelisted capabilities passed in, some form of "immutable, set-once, dynamically-scoped capability flags", or something like that.
The problem with the global boolean flag approach is that if any part of a service needs it constantly, the entire program gets it, even obscure subdependencies for generating colour pickers.
Don't get me wrong, it's an incremental improvement over's Node.js blase approach. It's also quite niche to see languages support this feature. E was one of them. There was another newer Python-like language with this too, starting with an `M`, but its name escapes me.
I'd recommend Deno's developers look at E a bit more before committing too much to the platform boolean flag approach. Or I've misunderstood their approach and it actually does more than I'm giving it credit for.
What would be really useful is if only sections of code can be delineated as requiring certain permissions. This way, it's much easier to see what parts of the code do what and also to make sure that users only get prompted for such permissions when the code actually runs.
Also, "promise first" seems to be premature to me. You could have simpler, more stateless async/await without promises: https://www.npmjs.com/package/casync
My brief skimming of its site indicates that its security model is based around the ability to disable, say, network access for whole Deno programs. However, does it allow starting up with network access, allowing a subset of the program to handle it, and then dropping those rights for the rest of the program, _especially_ subdependencies?
I can't see any mention of a more fine-grained approach: https://deno.land/manual/getting_started/permissions
A modern Node.js web service will have hundreds, if not thousands, of indirect dependencies. Some network access will be required for at least the Express routing, or an equivalent.
For a Deno equivalent, this would amount to enabling network access for all hundreds of those subdependencies, not reproducing the isolation in capability-based security such as WebAssembly nanoprocesses.
Have I missed something here? That doesn't seem like much of an improvement over Node.js except for very small and contained programs. Yes, Deno's dropping of centralised package repositories and package.json might alleviate this problem _somewhat_, but the same fundamental issue seems to remain.