Write Partially Trusted Apps
For years, software developers have written apps that have contributed to the barrage of malware attacks, by writing software that required administrative privileges to run. Once an attacker finds an attack vector through a software application running under an administrative account, the attacker has full access to the local machine and probably the local network.
So, in this new world of insecure computing, it's essential that we write partially trusted applications, and handle the cases where the app doesn't have full control of protected resources. This means working within the limitations of Windows ACLs and other limitations, and taking full advantage of Code Access Security (CAS) in .NET Framework applications. CAS is our friend, but only if we learn to use it effectively. And it's far too easy to punt and write a full-trust application when CAS gets in the way.
The trick, of course, is to design the app well and degrade gracefully. This means designing the app to reduce its reliance on protected resources (such as by not using System32 for configuration files), catching security exceptions and handling them in sensible ways, and giving guidance to users when things go wrong. Vow to never again write an application that requires administrative privileges or requires full trust in .NET. Of course, some apps require such powers, but they tend to be system utilities such as antivirus or administrative tools that by their nature require complete control over the machine. But even those apps can be written to require the admin privileges for as short a time as possible, thereby narrowing the potential destruction from an attack that takes control of the app. Most business apps just don't need that level of privilege.
In every application, software developers should strive for three major goals:
- Give a privilege or permission only to the component needing it. By sandboxing the risk, you limit the danger. Say that you really do need to write to the configuration file in the Windows System32 directory. Put all the code that manipulates the file into a separate component or command-line tool, and protect access to the component. This way, the entire application doesn't need to have the dangerous permission. Maybe you could run the dangerous code on a different thread or process with the heightened security credentials, so the main process or thread can happily run with lesser privileges. In .NET, maybe you can run the code in a different AppDomain, which provides similar protection. But if you use techniques like this, be sure to secure the communications between process, threads, or AppDomains as well!
- Give only the privilege or permission needed. Don't ask for full control if you just need to write to a file or registry value. This approach requires you to think ahead of time about which permissions are really necessary and code only those permissions. You can also create separate users or groups with the special permission, or create a separate SQL Server login for different kinds of data access. Think constantly of ways to avoid giving the permission to the user running the application.
- Give the permission for the shortest time possible. Then permanently give it up! You don't have to demand a permission for an application at load time, particularly if the protected resource is used only occasionally. The longer an application has an unneeded permission, the longer an attacker gets to take advantage of it.
It's both possible and imperative that we in the software industry stop writing and deploying applications that require administrative privileges. We are a significant part of the problem, but both together and individually we can make a big contribution to the solution.
In the next installment, I'll finish up this series on living the least privilege lifestyle with tips, tricks, and tools you can use to survive software development as a mere user.