Secure Coding Practices: Running with Least Privileges in Windows

An article on developing software while running with least privileges in Windows

Introduction

There is an old rule in Unix environments, that you should never run a desktop environment as root. It makes sense; root is the super user that has complete control of everything in the operating system, and from a security perspective it makes no sense to expose such privileges as you work in the system unless you absolutely have to.

In the Windows world, as far as desktop environments go, there hasn’t been this same “rule of thumb”. Well, more to the point… no one is touting it. Well, this article is to do just that. Although many of us who are security conscience run our systems with least privilege as we do development, most of you do not. Hopefully I can show you a few reasons why developing in a least privileged environment is a good idea, and answer some of the issues people have when they try it, and it fails.

Understanding Least Privilege

If the term “least privilege” seems foreign to you, don’t fret. The term itself is a pretty good definition. Least privilege is a concept in the field of security where basically you give the absolute minimum amount of access rights and privileges to accomplish a task. Think about this concept in reflection of the old wives tale about fishing with dynamite. Perhaps you heard of it? You take a stick of dynamite, light it and throw it in the lake. BOOM! Now go collect the fish that float to the top. Ok, fishing complete. Yet it could have been done with a fishing hook, some line and a little patience. Both can do the job, but the dynamite is excessive… it’s just not the right tool. If something goes wrong, there is a bigger chance you will hurt yourself or others around you than if you used your fishing gear. The same analogy can be used with applications in any environment – they should only need enough privileges to do their job.

When you consider all the security compromises that relate to buffer overflows, privilege elevation, data destruction etc, an application ran in least privilege will do less damage than if it was ran as a super user like root or administrator. The injection of faulty data (malicious or not) makes it way to easy to wreak havoc on the system. As an example, a Trojan executed will spawn itself with the same privileges as the calling process. If your account is part of the local administrator group, a Trojan will now have complete system access which could open you up to virtually everything.

Outside of the issues that relate to application security, there is another good reason to not run as administrator on the local machine, especially if you are doing development. You should be doing your development in an environment as a normal user so your applications will be in the same security sandbox as your intended users. This may seem like a small point, but consider the outcome. If you write your code with full privileges, many conditions that your normal users will have imposed on them will never be seen in a development or QA environment.

I just finished installing an app today that had this problem and did not work for me. It is the whole reason I decided to write this article. No error conditions or alerts of any kind were shown during the normal operation of using the application. Yet every time I tried to click a button it just sat there. Finally I realized that maybe it was trying to read or write something in the registry in which I didn’t have access to. Sure enough, that was the case. It was trying to write to a registry key that I had no rights to. How did I get around this? I used a tool built within Windows XP/2000 to change my user credentials for this application only, so that it could set the required key. Once that was done, I could run the application fine as a normal user. Lets talk about that tool.

The "runas" command

Windows has a neat utility that can run application with other credentials called "runas"[1]. Runas allows a user to run specific tools and programs with different permissions than the user's current logon provides. This can be done through the command line, or through a graphical user interface. Lets give it a try. Here is the scenario. Lets assume you are a normal user without any administrative privileges on Windows XP. You need to check out some settings in HKEY_LOCAL_MACHINE\SECURITY. You do the following:

Click Start->Run

Type: regedit

Expand the HKEY_LOCAL_MACHINE tree node.

Expand the SECURITY tree node.

Get prompted with “Error Opening Key” Dialog. Access is denied!

This is expected. As a normal user you shouldn’t be allowed to see this particular key. Now lets try accomplishing the same task using the runas command.

Click Start->Run

Type: runas /user:Administrator regedit

Enter the administrator’s password at the prompt

Expand the HKEY_LOCAL_MACHINE tree node.

Expand the SECURITY tree node.

Note you have access

Bingo. You started the process regedit as administrator on your local desktop running as a normal user. This gives you the flexibility of still being able to run administrative tasks and processes, but on your conditions, when you want it. Yet at the same time, you are restricting the possibilities of malicious code from gaining extra privileges than what is provides as a normal user.

Runas is a pretty good tool for this. But you don’t have to always use it from the command line. You could just as easy create a shortcut on your desktop to regedit, and set it up to run with different credentials. Here is how you could do it on Windows XP.

Create a new shortcut on your desktop

Right click and choose Properties

Select the "Shortcut: Tab

Click the "Advanced" button

Select the "Run with different credentials" checkbox

Click "Ok"

Click "Apply"

When you double click on the shortcut, it will now prompt you with a graphical dialog on which account’s credentials you wish to launch regedit as. You could also get to this from any shortcut by right clicking and selecting "Run as…" from the popup menu.

Setting up Access Rights for Debugging

As a developer one key feature you will ultimately need is the ability to debug programs. One issue you will have as a normal user is that you cannot attach a debugger to processes that you don’t own. In the real world, I found that sometimes even when it IS your process there are issues in tools like Visual Studio .NET. Further to this, you will want to be able to terminate processes easily, which isn’t permitted as a normal user. These are all issues due to the SeDebugPrivilege flag not being available to you. No worries though, as you can easily increase your privileges for just local (or even remote) debugging by adding yourself to the "Debugger Users" group. This can be accomplished by:

You will now be a member of the Debugger Users group, and will now have efficient privileges to be able to attach a debugger to any process in the system. Now, I would like to give you a word of caution if you decide to increase your privileges to include debug access. If an attacker can gain access to your account that now has debug privileges, it may be possible to execute malicious code within any running process on the system. There have been recent security proofs [4] in which you can use functions like OpenProcess() and CreateRemoteThread() to insert code in this manner. Even with this potential threat, it is still safer than running as a full administrator. By reducing the attack surface of your account privileges in the system, it is much harder for an attacker to maliciously elevate his (your) privileges in this way, compared to how easy he gets it if he compromises an administrator account.

Tracking down Least Privilege Issues

If any of you take my advice and remove yourself from the administrator’s group, you will probably come across some issues and will have trouble trying to get existing applications you wrote to work as a normal user. This should be expected. It’s not really your fault (Well, it is… but why dwell on it). You probably originally wrote it for Windows 98/ME which didn’t have such finite access control and although it worked fine in W2K/XP, it was because you ran as an administrator with full privileges. You just haven’t dealt with the security permissions and access control lists that you should be in newer Windows environments.

There is a way to help diagnose what may be causing your application to fail as a normal user. If you modify your computer’s logging policy, you can trap many issues your application may have as it dumps it to Event Viewer. Here is how you would configure your security policy to support this:

Click Start->Run

Type: runas /user:Administrator “mmc secpol.msc /s”

Enter the administrator’s password at the prompt

Expand the “Local Policies” tree node

Click on the “Audit Policy” folder

Double click the “Audit privilege use” item

Check the “Faillure” check box

Click “Ok”

Now when your application runs, failed privilege attempts will be logged to Event Viewer, and you can begin to figure out what and where your application may be failing.

Another issue that will come up will relate to access privileges to files, directories and the registry. Mark Russinovich and Bryce Cogswell over at SysInternals (http://www.sysinternals.com[^]) wrote two excellent tools that will aid you in diagnosing these types of issues. FileMon and RegMon will monitor access attempts to files and the registry respectively, and will report an access denied (ACCDENIED) if you application does not have the required privileges in the system.

You can use this approach with these tools to quickly find issues in your applications and address them before other users come up to these problems. Remember, if YOU can’t run it as a user, how can you expect them to be able to? Requiring to install as administrator is just not acceptable, unless of course the application REQUIRES administrator access. Don’t get lazy…. do it right. Trust me, you will thank me in the end.

Conclusion

It is easy to be lax with security when it comes to comfort in our development environment. We want to get our job done, without any constraints. Yet doing this exposes us to large risks we really don’t NEED to take. A combination of a normal user account with Debugger User group privileges can give us the same environment to write code as if we were administrator. With addition of the runas command, we can even run administrative tasks in our normal user environment. Hopefully you can see this. It is the old “eat your own dog food” adage. If you yourself run with least privilege, and design your applications in this way, your quality of code will increase, as will the security. Who would have thought such a small change could create such a large benefit?

Of course, you can ignore this article. You could stick your head in the sand and expose yourself to unnecessary risk. You can write applications without thinking about least privilege and access control. Hopefully, I won’t have to run your stuff.

Security is part of our every day life, and we should embrace it. Using secure coding practices is a great start.

History

09/03/2003 - Initial Submission

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

O divine art of subtlety and secrecy!
Through you we learn to be invisible, through you inaudible;
and hence hold the enemy's fate in our hands.

-- Sun Tzu, The Art of War, c. 500bc

Sun Tzu said it best. I am your run of the mill security engineering geek that likes to break things. Well more to the point, I like to prevent others from being able to break things.

I dislike the FUD people sling around about how any one piece of software or their OS can completely secure the world. Security is a process and not a product, and should be treated as such. I think General Patton said it best when he said:

“Fixed fortifications are monuments to man’s stupidity.”

I spend most of my days developing code that is part of our security management life cycle, in the hopes people start to realize that static defences are not enough.

I spend most of my time on flavours of Windows (Currently XP) in a set of Cygwin bash shells SSHing to Linux and BSD systems to actually do a lot of my work. My main editor is vim with ctags (I can work faster in it than in Developer Studio) and it works great editing code both locally and remotely.

When I am not in front of a computer I can typically be found at the Squash courts or listening to contemporary jazz like Chris Botti, Diana Krall or Miles Davis (ok... so he is more Blues and fusion but his trumpet still sings). Otherwise, I will be immersed in a book which probably relates to information security, cryptography or has some sort of animal on the cover and is published by OR&A.

Comments and Discussions

As a developer, it doesn't really work for me to run with least privelege - I've tried and
too many things just don't go well. However, lots of my routine and most dangerous activity
could be done with less privelege - for example reading mail and surfing the web.

I've spent an entire day trying to set up a non-admin user I could run with "runas"
which would not have access to most of my files: and I just can't make it work. Despite
my best efforts, no combination of "deny" as a default file permission and "allow" for just
the directories the mail reader ought to have access to seems to work. Wither the files
I want remain inacessable, or files I don't want remain acessable. Arrgh!

Without starting a flame war about how broken window's file access security model is,
can anyone tell me how ?

Have aclass in my program that uses the function NetFileEnum(). Found out that this requires access rights to the root of the actual File Server, but my users don't have such rights...

So how can I give them access to the class I created, while they are logged in with their own user rights? Say I am prepared to even hard code the user / password for the administrator in my code (ugly I know), or is there another way?

I have XP Home. I'm not a very computer literate guy, but the "Run As" pop up is very annoying and I want it to stop. It pops up four times before any of my programs load. I'm just a home user (Internet, word processing, etc). I don't have passwords set and my wife and kids have different user groups when we turn on the machine. All this started popping up about February 27. I've tried going back, but the computer won't allow it. Even the Dell Tech was stumpt. Just make the "Run As" pop-ups go away without interfering with anything else. It won't allow my Norton System 2004 shortcut to work either. Thanks Bobby G.

My software has been installed on lots of computers over the last year where the resitry rights have been restricted -- and often even the IT people don't know how to configure the computer to give the user rights to the registry keys we want while maintaining the restrictions they want.

For what it is worth, I've got a bit of code that can set the rights for a key. We use it during our install process so the IT person/user doesn't have to run regedit, but its not perfect -- we've still not found a solution to the built in "restricted user" logins. If I can figure that one out I'll try to put it together in an article.

The problem with XP Home is that it doesn't have the Debugger Users Group at all as all users are part of the "Owners Group".

I wish I knew a solution for you, but I am afraid I have never tried to program under XP Home. You couldn't even do remote debugging except via TCP/IP, but at that point you may as well move your debugger to the other machine that is providing you the ability to do the remote debugging. Unless there is some werid way you could do remote debugging via localhost, but I have never tried this.

Sorry I can't be much help in this case. Only thing I could recommend to you at this point is to move to Pro or W2K/W2K3. Not sure if that is feasible for you or not.

.. lots of good info here. Even though I disagree with your fundamental premise that _users_ should never run as administrators - IMHO, security is highly overrated - but I agree that as a developer, I should make sure that my apps will run on systems that have tightened security.

What level of access would you suggest for testing.. Standard User, or Restricted User? I am writing desktop apps for musicians, who tend to want to be in total control of their systems, so it seems to me that Restricted User is a bit too much to worry about.

Determining what level of access you need for testing comes down to the environment your users would have. With that said, if you used the design philosophy of what least privilege provides, making it work as a restricted user immediately makes it work as a normal user, or even as an administrator.

Make it work in the most stringent environment, and you will make it work on anything MORE open than that standard.

It depends on the situation though. Many enterprises do not want employees to even install other programs on their computers for various reasons (license infringement due to pirated software, objectionable content, IT management issues etc.) So the computer tends to be locked down to a very high level. Access may be restricted to parts of the registry etc. by a central policy.

In those situations, it is good to design systems such that it runs with the least required privileges. A business dataentry app does not need to have administrative privileges. But, many applications use things that need administrative privileges. Testing for these inadvertent things will save a lot of headache, if you let the apps run into the field and fail there.

One issue that I have is trying to run EXPLORER.EXE as an administrator, for those times that I need to change permissions or access files that an ordinary user normally doesn't have access to. (I know I can do this using the command line to set permissions etc, but would prefer to use the GUI).

I've tried enabling "Launch folder windows in a separate process", and then using the command line: runas /user:Administrator explorer.exe

I can hear the drive going, but nothing happens. Task Manager still shows a single Explorer.exe process running as my current user.

I think the way to deal with this one is to put the registration stuff into the setup program. If you are using the windows installer you get rollback of registration entries as a nice bonus if the install doesn't complete. It is nice to have components that can register themselves (e.g. if a problem occurs in the registry the admin can just use regsvr to fix), but this shouldn't preclude the program running if it is correctly registered, but just doesn't have enough rights to write into HKCR.

It would be nice if MS would fix this problem. And also provide a way to generate the necessary registry entries in the setup project for all the things to be installed (by either scanning the code, or doing a registration and capturing the registry writes).

My program has self-update code to provide automated updates, and install new features and components. May be I sould have done than using MFC. I just realized that group: "users" don't have write access to HKCR.

OK, well lets live with the constraints for a moment and approach this logically.

Absolute security is a myth. What we want to do is reduce the risk as much as we can, while at the same time allowing the user to do their job.

Perhaps you could separate your update code with your main application. The update "daemon" could verify all transactions to the update server through the use of digital certificates to guarantee the authenticity of the update data, as well as the connection itself, reducing the potential harm from network and file attacks.

In this way, we only give enough code the privileges it needs to do its tasks. Installation, registration with the system and file overwriting (in self-updating code) can be done with more privilege, but the actual application itself does not.

This might meet your requirements. Of course without seeing a threat model I am just guessing here.

Secure Coding Practices You write, good enough, we need that.Running with Least Privileges in Windows, that's not gonna make me code more secure code, but after half an hour I just throw my computer out the window because all the stuff I cannot do.

I test my applications as a normal user, and check that everything works perfectly good, but there is no way I'm gonna code as a normal user.
I do too much stuff, as admin and coder, on my small network, that needs some privileges.

Now I just wait and see if this makes you say that I write more insecure code bacause of that!

No, but I do copy files, and change registry keys, that normal users don't have permisions to do.
I have to do that, in order to test and develop the software I develop.

Andreas Saurwein wrote:because you dont understand how to use least privileges

Now you are just too plain stupid!

Andreas Saurwein wrote:you consider it is to difficult|cumbersome to bother with it.

What do you know, I know how it is to work as a restricted user, and I know what they can do. I also test my applications as a restricted user, but I don't develop as one.

Andreas Saurwein wrote:Learn it.

Listen you fool, I have learned it, I just don't agree with your black/white attitude.
I have worked with security for several years, full time, and I do know what I talk about.

Your problem is that you don't want to understand what I say.

Read carefuly:

I do test all my applications as a restricted user, so that I know it works out there in the real world.
I don't log on and code as a restricted user, because it gives me way too many problems in my day to day work.

Is that so hard to understand?
And why is my code more insecure than yours because of that?

Anders Molin wrote:I do test all my applications as a restricted user, so that I know it works out there in the real world.
I don't log on and code as a restricted user, because it gives me way too many problems in my day to day work.

Is that so hard to understand?
And why is my code more insecure than yours because of that?

Developing in an environment of least privilege is not about code quality. Code quality is an added benefit of you yourself taking the effort to run in a more secure environment. It is great you test your application as a normal user. That is one step towards making the user experience easier.

With that said however, your attitude of requiring to run as an administrator "becausing it gives me way to many problems in my day to day work" to run as a normal user is very reflective of your potential attitudes on security as a whole. And I don't criticize you for this personally. Most developers have this attitude because they have better things to do with their time. If you wish to expose yourself to unnecessary risk, I have to believe in a crunch you will sacrifice security in your application over getting a release out. This is human nature when deadlines loom. It takes a strong character to put your foot down and say "No.. I will not sacrifice security to get this out sooner".

From what you say you need to do daily, I am not convinced you need to be an administrator. More to the point, your personal experiences show you have given up because you have had problems. This can easily be overcome with education and experience. You sound like you have had plenty of experience over the "last several years" when it comes to security. Apparently it wasn't a good experience, or I would highly doubt you would have this same position on running with least privilege.

I appreciate your cander, and wish you well. I only hope in time you will realize that security as an after thought will always be trumpted by security by design and use. If you take your experiences (which by your own admission were bad) and think about it from a user's POV, the increasing threats that have elevated over time and the vulnerabilities that we get exposed to on a daily basis, why WOULDN'T you learn to run with least privilege?

Dana Epp wrote:your attitude of requiring to run as an administrator "becausing it gives me way to many problems in my day to day work" to run as a normal user is very reflective of your potential attitudes on security as a whole.

Dana Epp wrote:I have to believe in a crunch you will sacrifice security in your application over getting a release out.

When you say this it just tells me that you are too stupid or narrow minded. I don't wanna waste much time on you...

With that said, I would necer sacrifice security in my applications, because of a deadline, I have no problem telling the boss that!

You know what, you have no idea of what I do and why I need elevated rights in my everyday work. You just asume that all developers sit and code their stupid GUI-applications as you probably do.

Dana Epp wrote:I only hope in time you will realize that security as an after thought will always be trumpted by security by design and use.

For me security is not an afterthought, why do you think that. Just because I don't wanna program when running as a normal user?
If that is the case, you should grow up and stop being so narrow minded.

Difr'nt strokes for difr'nt folks. It's been my experience that people who do things in a small, tightly and easily controlled environment(s) have a wildly different outlook than those people who do things in large, widely distributed environments. Every time we hire a new programmer who has no hesitation to do something on his desktop at home seems completely confused as to why we don't get anywhere near doing those things when we have nearly 200 clients and 1000 users to support.

Now, I may be wrong in that you're only writing and testing on the small network, but are distributing to a larger widely used user base.

I think that super high, squeaky tight security measures are not always applicable. Ie, not everyone's home safe has the same security as fort knox. I think what Mr. Epps was saying is that security is a process, and therefore may not apply evenly to every situation. But in some cases, they're more than necessary.

... there is no security education among most developers. My experience with most developers is like this:

User/QA: "The app doesnt run when I am not logged on as Administrator"
Developer: "Then dont do it. It is not intended to run as normal user."

Things like, why open a registry key with read access instead of full access, are generally not understood by windows developers. The common excuse is "but that requires lots of code just to have less [rights|privileges|access]".
And in many cases we cant even say they are wrong. Most API interfaces make it too easy to request full access.
One contributor here at CP once replied to me: "...All my applications require full access to registry and files, no one ever complained. And if it does not run with non-admin users, I dont care..."
If we can change this attitude, security in our applications will increase.

There is yet so much to teach
Thanks for the article.

Shaken, stirred, or strained through a diaper, nothing can make a martini palatable. Roger Wright, Soapbox

What can I say. You are right. Education is by far the biggest problem when it comes to security. People just don't know WHAT to do. The weakest link is always the human factor, and to strengthen it requires effort.

What can we do about it? Well, I now have a SOP where everyone I work with receives a copy of the books "Writing Secure Code" and "Security Engineering" and are forced to read it before they even begin touching the CVS trees. I am offering free lectures at the local university to help increase security awareness in the CIS curriculum to provide atleast a small foundation of learning. Each member of my team now must have intimate knowlege of the threats exposed to our software, and must be part of threat modeling sessions.

I don't say this to impress you, but impress upon you that the best way to solve the educational barrier is to help break it. Maybe we can't change the world, but we can change our part of it.

I do most of my stuff as a 'user', as well, and I deploy my final projects to clients with as little permissions as possible. It's good to see the word spreading.

Doing this is especially importaint if you build services which accept connections from anywhere else. Even though I usually build my services in .NET these days (and I trust the .NET security features), there is still the possibility that there is a semantic error in the code which exposes some critical operation like file IO. (an example of a semantic error is SQL injection or relative path commands like ../../)

But if you run under an account that has access to only the files and keys which are needed by the application, such an error would only be able to damage the service, and not spread to the computer as a whole.

You are so right. Especially with services. I cannot fathem why so many are running as SYSTEM when they don't need to.

I found a neat trick for dealing with least privilege and services. During install time I actually prompt the user to basically do a "runas" to create a new user with a resticted token, boxing the service to only access config data and devices as needed without access to basically anything else from the system. The CreateRestrictedToken() function was well thought out when it was designed for that. A combination of that and strong DACL for the SID, and you can really constrain the rights and privileges of services.

What is sad is that few developers even know this. I have seen a few codeproject wrapper classes for services which don't even consider this, which promotes bad security design principles. (No offense intended to the authors)

Oh well. I am going to start writing more security related articles for Code Project, and hopefully over time we can change this sort of attitude.

thanks for your article.
Some of the reasons developers tend to a general laxity appliying security settings:
- "run as" is a feature that didn't exist prior to Windows 2000. It was possible to obtain a similar functionality by manually loading registry hives and logging on a separate user programmatically - but the user account from which this operation could be performed had to have administrator rights, thus the whole operation had no merits.

- Microsoft's documentation for the security stuff is miserable at least. Documentation on what user right is necessary to perform operations is virtually non-existent.
Trying to debug an application where security stuff pees between your legs is an awful experience, especially when your customer's breath is already condensing on your neck.
It would be nice if there were a more detailed mechanism than getting just an "access denied" error message, that is, obtaining what specific user right is missing to perform a specific function.

So, _theoretically_ it is a good thing to use security functionality, but practically it's something simular to unuseable crap.

I agree on Microsoft's lack of documentation on security. However, I would like to say it is getting better. People like Michael Howard over in the Secure Windows Initative have made many efforts in educating developers and writing documents that are reflective of better security. One of my favorite books is "Writing Secure Code" by Michael Howard and David LeBlanc, and it thoroughly covers many of these topics.

As far as debugging concerns go, a lot of my points will help you immensly when debugging. Modifying your security policy to report on failures (and even success if you want) gives you a good starting point for tracking down failures. It would be nice if GetLastError() would be more instructive of issues, but if everything was so easy I would highly doubt we would talk about it!

Seriously though, I will bet in time this will get better. MSDN seems to be adding articles/documents relating to security on a semi-regular basis, and I would hope part of Microsoft's Trustworthy Computing strategy includes an increase in documentation and support to developers who wish to harness these type of security controls.