When deciding on access to resources within a system (we’re talking very generically here), there are two common approaches — “default allow”, and “default deny”.
“Default allow” suggests that if for some conceivable (or inconceivable — we do not want to be presumptuous about our ability to foresee possibilities) resource access may at some point be required, it should be granted by default.
“Default deny” is the opposite, it suggests that unless some use case explicitly requires access to a resource, access should be denied.
“Default deny” should be the approach of choice for most cases. “Default allow” is responsible for myriads of security flaws, spaghetti code, abuses, misuses, hacks, and other nastiness that you don’t want anywhere near a software system or a code base that you are working on.
For example, when smartphone apps first became a thing, WebViews embedded in them could make requests to any domain — default allow. This allowed phishing attacks, the webview could be hijacked and redirected to a malicious domain that would present some UI to steal your password. When framework and OS authors realized this, all too late, they switched to a default deny approach — access to any domain was banned, unless it was explicitly allowed in the whitelist.
A default allow approach is what blacklists implement — access allowed unless the party/resource is blacklisted. This causes an arms race — for any party/resource in the blacklists, attackers can find some other that aren’t, and attack from that direction. System owners then add the new item to the blacklist, and the cycle repeats. There’s no way to win. This does not happen if you employ “default deny”, explicitly allowing access when you choose and denying it for everything else.
In programming, a good concrete example of default deny is visibility modifiers on functions. Say you have a class, and it has a doSomething
function, that is currently only used internally in the class. It is conceivable that somebody may at some point want to call this function externally, so it may be tempting to make it public. This would be the “default allow” approach, and it can be detrimental. A private function is easy to refactor — you know the only callers are in the same file, so the consequences of the refactor are easy to predict. When made public, this no longer holds. When made public without explicit intent, it may be tempting to change the internal behaviour, and this could break the use cases of external callers, especially in a stateful OOP style environment.
The philosophical underpinning of “default deny” is “if there’s a way to abuse something, eventually somebody will”. So when designing systems and APIs, prefer to only grant as much access as is really necessary, and critically evaluate any request for additional access.
Comments
Post a Comment