Yes, if it is implemented properly for each and every endpoint. And the more complex the rules for that endpoint become, the more likely it is for a silly human being like me to get it wrong.
It also relies on all the bits of software being able to do exactly what the app developer has in mind … when the configurability of those components no longer is sufficient, then what?
This is complicated by details like default endpoint configuration being application-level in most of these cases, rather than per-authenticated-connection. Example: “this endpoint will accept files up to N bytes in size” (e.g. the length
parameter handed to Plug.Parsers
) … and we’ll sort the real constraints out during authentication (which is necessarily code that is run after configuration values are applied).
That is backwards: the endpoint should never accept anything at all, full stop, until authorization has had a chance to do its thing. I ended up having to place part of the authorization in the Multipart uploader, entirely separate from the file processing function in the Controller (which also had to do its own checks), and even that only got run after the file made it through the actual webserver upload.
So, yes, it is possible to achieve something similar … but in practice it is more code, spread out over more places, is not always possible to perform the full authorization path desired at every relevant stage, and is all done via a publicly-exposed endpoint.
I used to have conversations with C programmers who insisted it was possible to write complex C programs securely. They were, of course, right. It absolutely is possible, at least theoretically. But unless your name is D. J. Bernstein, it’s entirely unlikely, and the history of servers and OS’s written in C have shown that to be the case.
Design principles such as “don’t expose API until authorized”, “don’t spread authorization across disconnected components”, “multi-stage authorization is always harder”, “a single source of truth is easier to get right”, “unit tests are easier and more reliable than integration tests”, etc. exist to make it more likely to get it right … or at least more likely to not get it wrong.
C programs were plagued by the same set of security issues for literally decades until a combination of tools improving, enough time passing to find most of the worst bugs and fix them, and people not using C for those sorts of use cases to avoid the pitfalls has started to reduce the constant threat of buffer overflows and the like.
The web is going through something similar. LiveView is not a silver bullet. It has its own complexities, and there is still room for me to shoot my feet off. But it is far easier to get right, and that is mostly because it keeps all the right pieces together in the place they belong and can be most easily tested.