A PowerBox is a security pattern common in the CapabilitySecurityModel. The PowerBox is an object that may be queried for an arbitrary authority (a capability). On receiving the request, it can examine security policies or query a user for the capability. The capabilities it provides are typically either very limited use (i.e. single use or short expiration) or revocable, such that a user or security policy may later block the authority.
A power box is very similar to a ContextObject, except with extra support for authority management, such as ability to revoke authority. The initial power box in a program is provided to the main function (from the UI or whatever code launched it). Often, a PowerBox will transparently call back to the provider in order to validate a request. A common example to explain the PowerBox pattern is for the file selection dialog - i.e. to load a file or save a file. Instead of granting authority directly to the FileSystem, you give a PowerBox. When the program needs to save a file, the PowerBox passes the buck to its parent in the UI, which raises a dialog (possibly highlighting a suggestion from the caller) to the user allowing them to control where the file is saved or deny the authority. When the program needs to load a file, the PowerBox raises a dialog to the user allowing them to control which file is loaded, or deny the authority.
Usefully, the dialog is transparent to the program saving the file; it potentially treats the entire operation as straightforward FileSystem access, albeit with a little extra meta-data - perhaps a string to explain to a user why the program wants the access.
Deciding whether to grant a specific request is fundamentally a difficult problem. If it was easy, security wouldn't ever become a problem. The problem is that evil requests often look a very great deal like benign ones. Use of context can offer the callee some extra information with which to decide the risks for granting a request. However, the context itself must also be secure, because you cannot entirely trust the caller.
To support context, the PowerBox patterns can easily be chained. Assume program A holds powerbox Pa, and wishes to pass some powers to program B. To do so, it may wrap the Pa to produce a new powerbox, Pb. Rather than passing arguments directly from Pb to Pa, it can introduce security policies, filters, transforms, and even its own surrogates. If it does decide to pass a request from Pb towards Pa, it is free to frame that context to say: "This request is from subprogram B", and offer some extra meta-data regarding that program. Program B, then, cannot effectively pretend to the user that the context is anything else. Further, if it receives an authority from Pa, powerbox Pb has opportunity to introduce an intermediate to ensure the authority is locally revocable (i.e. so that when program A no longer needs suprogram B, it can revoke all of B's authorities at once.)
This chaining, of course, can also be branched if program A also gives a powerbox Pc to program C. Thus, we end up with a massive 'tree' of powerboxes, each enforcing its own security policies, filters, and providing surrogates. The 'root' of the tree, insofar as one exists, would be an agent trusted by the user to not abuse any of its (likely excessive) authorities. The OperatingSystem or WebBrowser are candidates. Usefully, the powerbox could present to a user exactly which authorities any program has at any given moment, with precision.
Thus PowerBox offers a very powerful mechanism for controlling and managing requests for authority!
Downsides of PowerBox
Power box pattern has its flaws.
The power box is fundamentally about "turning strings into power". Well, passing data structures other than strings to the power box is certainly feasible, but the point remains that these are relatively opaque structures, and the requests are for rich authorities. It is difficult to express and apply meaningful security policies to these 'strings' - i.e. if one asks for FileSystem access, which regions of the FileSystem should be allowed? If one asks for Internet access, which regions of the Internet? Too often, one will need to pass the request all the way back to the user. Users are not automatons. Unless the authority requested is, of immediate relevance and they can make an informed decision, they should not see the request at all - lest they form bad habits (ToolsThatTeachPoorHabits) of approving an authority without thinking critically about it.
Also, PowerBox too easily influences application architectures, and in a negative manner. It can become the MasterControlProgram that the rest of the application code worships with inefficient arcane hierarchy and rituals. A power box is a simple way to represent a traditional ApplicationModel in an ObjectCapabilityLanguage (where 'traditional' means 'an application is basically a giant procedure call with loops and libraries of sub-procedures'). However, there exist application models that are simply a better fit for ObjectCapabilityModel - i.e. an application or service might simply be a 'long-lived' object rather than a procedure call, with links to other objects and inside other applications and services instead of 'libraries'. In that case, one doesn't benefit quite so much from a power box, since authority to the environment is hooked directly between apps and services from the IntegratedDevelopmentEnvironment.
An advantage of this latter model is that one can work with much higher level authorities; for example, a power box might grant 'network access' and the application would need to include its own 'HTTP library' that can turn network access into HTTP. However, the objects-as-apps design would allow developers to build an HTTP service with access to the network, then simply hook that HTTP service into the new application. This obviates the need for PowerBox, and greatly reduces the dependencies of apps upon 'library' code. The advantage of using higher level authorities is that it's a lot easier to reason about their use and potential for abuse. Additionally, this would make applications a lot more compositional, a lot smaller, and simplify communication between them.
So, rather than a PowerBox to force popular ambient-authority based software development models to work with an ObjectCapabilityLanguage, one should consider finding a better ApplicationModel that depends less upon libraries to turn low-level authorities into high level authorities. Any alternative application model would greatly affect design of the IntegratedDevelopmentEnvironment; the one suggested here would probably want to include a database of 'exported' object references and their meta-data. Those would then allow integration between apps and services. The IDE would also need to be suitable for LiveProgramming, in order to modify application objects while they're active. This would hark back to SmalltalkLanguage and its like.
Another alternative: LazinessForSecurity?
A PowerBox is fundamentally an eager coding pattern. That is, you are requesting authorities so that you may do something useful with them. But, if your code is even moderately robust, it is hardly as though you'll lose anything of value if the authority is denied. (You do handle the authority-denied case, right?) Since it's no skin off your back if the authority is denied and you can't do the work, then why are you so eager to do the work?
Lay back. Be lazy.
Laziness is almost always the right answer - not only for security problems, but also for modularity problems, and it can sometimes help with performance issues. Delegate the jobs you don't care about. Don't ask for extra work. Simply push the job - and the minimal set of authorities necessary to complete it - off to someone else. Then go have a beer.
Examples for the FileSystem case:
Alternative: LiveProgramming + OrthogonalPersistence + FirstClass Distribution
PowerBox is essentially a pattern to support (within an ObjectCapabilityLanguage) an ApplicationModel where libraries are helpers. Generically, a PowerBox is passed as an argument to PublicStaticVoidMain (or the language's equivalent) and contains low-level authorities to the OperatingSystem. Helper libraries take a bunch of low-level generic authorities, and produce high-level specific authorities. However, these libraries are themselves security problems because they are big, we can't readily validate whether or not they abuse their authorities, and we should not trust them. The maintenance life-cycle wherein libraries are upgraded, can only exacerbate the security issues introduced by libraries-as-helpers.
But so long as we enter PublicStaticVoidMain with a bunch of low-level authorities, we simply cannot avoid the need for libraries-as-helpers. Even laziness won't help.
The solution, then, is to allow entry points to code to be granted high-level specific authorities from the start. The applications themselves, in this sense, would follow POLA.
Assuming we managed to solve this problem, the bulk of 'libraries-as-helpers' would no longer be necessary. We would still need libraries, i.e. to perform transforms and local analysis, but the vast majority of them could be pure-functional, and most could be relatively shallow because their inputs can be high-level without any special efforts. Pure functional libraries would be easy to validate in the sense that they can't 'abuse' authorities.
How might this be managed? Can we push the problem to the OperatingSystem shell, ask it to provide high-level specific authorities to PublicStaticVoidMain? Well, yes we could. But that regresses the problem such that, now, we must figure out how to manage high-level specific capabilities in the shell. Yet maybe that idea can offer some insights. The shell, after all, is already known to deal with a few 'medium'-level authorities, such as pipelining processes and files.
If we want to run a program with a given set of high-level capabilities - akin to running a program on a given set of files - we will need to get those high-level capabilities from somewhere. If the problem were regressed back to the shell, we would also recognize that these capabilities really ought to be 'persistent', because we don't want to lose all our work every time we shut down the computer. How would we obtain these high-level capabilities? Well, the most natural answer is by developing or running programs atop a set of other high-level capabilities, the same way we currently produce new files by running programs on old files. Or, similarly, we use a service to help produce more services, the same way we use a text editor or 3D model editor to produce a new file.
But something to consider is that the output is effectively a program. A service to produce services is MetaProgramming. Everything we would be doing in such a shell would be LiveProgramming with OrthogonalPersistence. This idea has been discussed a multitude of times... NoApplication, NakedObject?, ObjectBrowser, etc. This is already realized to a degree in SmallTalk, ToonTalk, OpenCroquet, SecondLife, and other ImageBasedLanguage environments. We don't need to regress to the shell before avoiding or diminishing the utility of libraries-as-helpers.
But a problem faced for ImageBasedLanguage is distribution of code. Distribution of code isn't a necessary thing - one could always use remote services by MessagePassing on the network, for example. But distribution has a lot of nice properties: disruption tolerance, redundancy and recovery after node failure, better latencies, better bandwidth efficiencies, better distribution of resource costs (i.e. users share load with servers), and support for non-revocable licensing.
For helper-libraries (and their associated ApplicationModel) the developers of libraries could trust a relatively "dumb" DistributionModel? because those libraries obtain all of their relevant authorities - and then some! - from the users who are desperate enough to run them. We cannot do the same for 'live services' that embed authorities because we don't want remote users be privy to sensitive information or authority. Thus (unless we are okay with sacrifice of security) we must introduce some intelligence with regards to distribution of code.
Inherently, introducing 'intelligence' with regards to secure distribution of code requires somehow expressing or inferring which code is safe for distribution. It would be a little awkward to express these issues within some ad-hoc external system. The most natural place to perform such expression and inference is the code itself. Thus, I suggest FirstClass support for distribution is the third element of the answer.
Exactly how this expression is achieved is still an open problem. EeLanguage chose to make 'potentially-remote' calls explicit in the language via 'far' pointers, and allows you to control how an object is distributed (by copy, by proxy, by construction), and otherwise assumes that you know what you are doing. Unfortunately, that approach forces programmers to be especially conservative. I'm enamored of TransparentDistribution and "tierless" style, where service code and data, within the security limits, replicates and migrates just enough to get the desired level of redundancy, disruption tolerance, and performance. The tierless approach requires some sort of dataflow analysis and annotations be built into the language, to control distribution.
Providing for LiveProgramming + OrthogonalPersistence + FirstClass Distribution is to answer the root cause for the PowerBox pattern, i.e. by changing the forces that led to it in the first place.
A SandBox in an AmbientAuthorityLanguage? has a purpose akin to that of a PowerBox in an ObjectCapabilityLanguage. However, the practice between the two is very different. All the flaws of a powerbox apply to a sandbox, yet sandbox loses powerbox advantages. Both are similarly about turning strings into power, a sort of CoverYourAss disingenuity, forcing a libraries-as-helpers design requiring too many low-level authorities. Here are some significant differences: