4 ms·
Totally agreed, and I'm surprised this idea hasn't become more mainstream yet. If a package wants to access the filesystem, shell, OS API's, sockets, etc., tho
by crazygringo 1y ago
Totally agreed, and I'm surprised this idea hasn't become more mainstream yet.
If a package wants to access the filesystem, shell, OS API's, sockets, etc., those should be permissions you have to explicitly grant in your code.
- crdrost 1y agoThis was one of Doug Crockford's big bugaboos since The Good Parts and JSLint and Yahoo days—the idea that lexical scope aka closures give you an unprecedented ability to actually control I/O because you can say function main(io) { const result = somethingThatRequiresHttp(io.fetch); // ... } and as long as you don't put I/O in global scope (i.e. window.fetch) but do an injection into the main entrypoint, that entrypoint gets to control what everyone else can do. I could for example do function main(io) { const result = something(readonlyFetch(onlyOurAPI(io.fetch)) } function onlyOurAPI(fetch) { return (...args) => { const test = /^https:\/\/api.mydomain.example\//.exec(args[0]); if (test == null) { throw new ValueError("must only communicate with our API"); } return fetch(..args); } } function readonlyFetch(fetch) { /* similar but allowlist only GET/HEAD methods */ } I vaguely remember him being really passionate about "JavaScript lets you do this, we should all program in JavaScript" at the time... these days he's much more likely to say "JavaScript doesn't have any way to force you to do this and close off all the exploits from the now-leaked global scope, we should never program in JavaScript." Shoutout to Ryan Dahl and Deno, where you write `#!/usr/bin/env deno --allow-net=api.mydomain.example` at the start of your shell script to accomplish something similar. In my amateur programming-conlang hobby that will probably never produce anything joyful to anyone other than me, one of those programming languages has a notion of sending messages to "message-spaces" and I shamelessly steal Doug's idea -- message-spaces have handles that you can use to communicate with them, your I/O is a message sent to your main m-space containing a bunch of handles, you can then pattern-match on that message and make a new handle for a new m-space, provisioned with a pattern-matcher that only listens for, say, HTTP GET/HEAD events directed at the API, and forwards only those to the I/O handle. So then when I give this new handle to someone, they have no way of knowing that it's not fully I/O capable, requests they make to the not-API just sit there blackholed until you get an alert "there are too many unread messages in this m-space" and peek in to see why.
- mike_hearn 1y agoIt's harder than it looks. I wrote an essay exploring why here: https://blog.plan99.net/why-not-capability-languages-a8e6cbdf9682 https://blog.plan99.net/why-not-capability-languages-a8e6cbd...
- Groxx 1y agotbh none of that sounds particularly bad, nor do I think capabilities are necessary (but obviously useful). we could literally just take Go and categorize on "imports risky package" and we'd have a better situation than we have now, and it would encourage library design that isolates those risky accesses so people don't worry about them being used. even that much should have been table stakes over a decade ago. and like: >No language has such an object or such interfaces in its standard library, and in fact “god objects” are viewed as violating good object oriented design. sure they do. that's dependency injection, and you'd probably delegate it to a dependency injector (your god object) that resolves permissions. plus go already has an object for it that's passed almost everywhere: context. perfect isn't necessary. what we have now very nearly everywhere is the most extreme example of "yolo", almost anything would be an improvement.
- mike_hearn 1y agoYes, dependency injection can help although injectors don't have any understanding of whether an object really needs a dependency. But that's not a god object in the sense it's normally meant. For one, it's injecting different objects :)
- Groxx 1y agoto be clear, I mean that the DI container/whatever is "the god object" - it holds essentially every dependency and every piece of your own code, knows how to construct every single one, and knows what everything needs. it's the biggest and most complicatedly-intertwined thing in pretty much any application, and it works so well that people forget it exists or how it works, and carrying permission-objects through that on a library level would be literally trivial because all of them already do everything needed. hence: doesn't sound too bad "truly needs": currently, yes. but that seems like a fairly easy thing to address with library packaging systems and a language that supports that. static analysis and language design to support it can cover a lot (e.g. go is limited enough that you can handle some just from scanning imports), and "you can ask for something you don't use, it just means people are less likely to use your library" for the exceptions is hardly a problem compared to our current "you already have every permission and nobody knows it".
- int_19h 1y agoThis exact idea has already been mainstream. Both Java and .NET used to have mechanisms like that, e.g.: https://en.wikipedia.org/wiki/Code_Access_Security https://en.wikipedia.org/wiki/Code_Access_Security
- Groxx 1y ago"it exists as a niche feature that few use and fewer understand" isn't exactly "mainstream" IMO (it's significantly less common from what I've seen than manual classloader shenanigans, for example). But yes, it's nice that it exists, and I wish it were used more - it'd catch low-effort stuff like this one was.
- darthwalsh 1y agoNo, C# had it: past tense. CAS was neutered in .NET Framework 4.0 then removed in dotnet core.
- Groxx 1y agoalas. don't suppose you know of any good articles on why it's removed? I'd be curious about the reasoning / challenges. there are some rather obvious challenges, but a huge amount of the ones I've run across end up looking mostly like "it's hard to add to an existing language" which is extremely understandable, but hardly a blocker for new ones.
- int_19h 1y agoI don't know if there were any articles specifically detailing it, but from blog posts at the time the clear message was that they didn't consider the intended security guarantees to be possible to uphold in practice, so much so that "CAS and appdomains shouldn't be considered a security boundary".