I’m currently managing and re-factoring a piece of software that has been used at my company for over a decade now. One of the elements of this application is a sort of admin or power-user mode which provides things like some additional/internal input as well as the ability to turn off input limits.
Historically this mode has been turned on by placing a specifically named file in a specific place in the windows system directory (both of which were hard coded into the application), the file being named ‘something.DLL’, even though it was an empty ASCII file and not a dll.
So I recently added some code and a little modal form that allows the user to enter an admin password to turn this functionality on. It is a set password, not user specific. When the correct password is entered, it does sort of the same thing by creating a ‘key file’ in the applications root directory so that the program can start in admin mode if that file is present.
Now the manager of the department that this software is mostly for doesn’t like that idea so much. He thinks that if we have just a simple, preset password that it will easily ‘get out’, and he doesn’t want inexperienced users accessing those extra features.
So my question is, what other methods are there for providing this kind of access that would be somewhat more secure? It’s pretty much just me when it comes to maintaining and managing this software, so anything that isn’t almost completely built in or automated wouldn’t help (such as sending requests for ‘license keys’ or something similar to that).
Notes: This application is written in VB.NET (.NET 4.0), and I am currently planning on using click-once deployment when the new version is done.
1
If you have Active Directory, you can test for membership in an Active Directory Group:
public bool IsInADGroup(string ADGroupName)
{
bool result = false;
List<string> myGroups = new List<string>();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, SystemInformation.UserDomainName))
{
using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(pc, SystemInformation.UserName).GetGroups(pc))
{
src.ToList().ForEach(sr => myGroups.Add(sr.SamAccountName));
}
}
result = myGroups.Contains(ADGroupName);
return result;
}
1
The manager is right about the password getting out. Its not a matter of if, but when.
Since Active Directory isn’t an option for some users, you could create a signed text file with a list of windows login names that are allowed super user access. This assumes that people are not sharing computers or logins.
The user names would just go in an easily distributed text file that would be put in the application’s folder. The important part is to sign the list of user names. Keep it very simple. One user name per row and put the hash on the last line. Embed some sort of secret key in your program binary and hash it with the usernames. The secret key will prevent people from modifying the file and then calculating the hash themselves (which is probably far-fetched to start with).
UserName1
UserName2
.
.
.
UserName34
<HashOfUserNamesAndSecretKey>
This, of course, requires someone somewhere to act as the admin of the list of authorized users. The admin should have a program (written by you!) that generates the file and hash. If nothing else, it could just take an text file of user names and add the hash.
In the interest of being thorough, someone who has been revoked access could grab the copy of the file that still has their login name in it. Whenever they wanted access, they could just put their copy in place. Probably not something to worry about, though.
Since Active Directory is not an option, I would hash the current date. Use elements with the most entropy first (day of month) and those with least entropy last (year). If need be, add a domain-specific salt (a customer ID, company name, etc. since it is used outside your company). This should produce a very different password each day that is practically impossible for end users to guess, and it can be different for different companies that use the software.
This is essentially a chicken and egg problem since the software needs to be able to authenticate the user without phoning home. So make an egg with a really obscure cracking mechanism: while security through obscurity is not real security, this is the best you have given the parameters of your problem.
This is also better than placing a text file somewhere: that is no better than a static password because once the secret gets out, game over.
Use Access Control Lists.
The quick and dirty way to do this is to remove all permissions from the application directory (including read permission), then add these permissions for any users who are permitted to run the application. Of course, a user with permission could just as easily copy the application directory to a public location, but this is unlikely to happen accidentally, whereas password sharing can easily happen accidentally.
This assumes, of course, that the computers involved are secured (hopefully with active directory).
2
My preference is as @Dan suggested – use active directory. If this is not possible, then a password generator based on time can be useful. In a similar situation, (very distant past) one my company I worked for used 9999-MMDD. This did get out after a couple of years. If you threw in hhmm and mixed it up a bit you might get a year or two out of it before someone lets the cat out the bag.
You could always write a program that generates a password using a similar, but more complex strategy. Throw in the used name an machine name as well. You manager can run that program to get the current password for just that machine. Store some information in the file so its not valid if copied to another machine or if a different user is logged in. Its then up to you manager to keep the program secure and if the cat gets out, its his fault.
This scheme is considered weak and unreliable from a cyrpto perspective, but is adequate for the problem you have.