I’m doing some basic security work for an application. When a user logs in, their credentials are validated via Active Directory. Sometimes, a user requests changes that cause the program to restart. Since this application is not a single instance program, I simply launch another instance and close the current one. Everything within the application is fine.
However, users aren’t happy that they have to re-login every time it restarts. So I pieced together some basic security using SecureString to store the password in the application. If the application restarts, the password gets decrypted then re-encrypted using a basic implementation of Rijndael’s algorithm from CodeProject. The application passes the username and encrypted password as command line parameters to the new instance. The application needs to encrypt the password, because any further calls of wmic process would show the password. The new instance decrypts the password, validates it against Active Directory silently, and stores it as a SecureString as usual.
I’m not too familiar with general security practices. I’m a little nervous about returning the password from the decryption method. It’s not being stored in any variable per se, because the call is made right in the Active Directory validation request. I’m still not sure if the returned password is accessible somewhere in memory or if it’s stored in a register.
This process doesn’t need to be the greatest security ever. It just needs to discourage people from getting a password in cleartext if they can easily access the memory contents.
Many thanks!
Function return values are, in .NET apps, pushed onto an “evaluation stack”, which resides in protected memory within the process. However, you’re talking about a string, and that’s a reference type, so what’s on the evaluation stack is a pointer to that string’s location on the heap. Heap memory is relatively insecure because it can be shared, and because it lives as long as the GC doesn’t think it needs to be collected, unlike the evaluation or call stacks which are highly volatile. But, to access heap memory, that memory must be shared, and your attacker must have an app with permission from the OS and CLR to access that memory, and that knows where to look.
There are much easier ways to get a plaintext password from a computer, if an attacker has that kind of access. A keylogger can watch the password being typed in, or another snooper could watch the actual handle on the unmanaged side of the GDI UI and see the textbox that’s actually displayed in the Windows GUI get the plaintext value (it’s only obfuscated on the display). All that without even trying to crack .NET’s code access security or protected memory.
If your attacker has this kind of control, you have lost. Therefore, that should be the first line of defense; make sure there is no such malware on the client computer, and that the instance of your client app that the user is attempting to log into has not been replaced with a cracked lookalike.
As far as obfuscated password storage between instances, if you’re worried about mem-snooping, a symmetric algorithm like Rijndael is no defense. If your attacker can see the client computer’s memory, he knows the key that was used to encrypt it because your application will need to know it in order to decrypt it; it will thus either be hard-coded into the client app or it will be stored near the secure string. Again, if your attacker has this kind of control, you have lost if you do your authentication client-side.
I would, instead, use a service layer on a physically and electronically secured machine to provide any functionality of your app that would be harmful to you if misused by an attacker (primarily data retrieval/modification). That service layer could be used both to authenticate and to authorize the user to perform whatever the client app would allow.
Consider the following:
Now, when your client application closes, all “session state” is lost between client and server; the session token is not valid for any other negotiated channel. So, you’ve lost authentication; the next client who connects could be anyone regardless of who they say they are. This is where the “transfer token” comes in:
Here’s the rub; this system, by relying on a secret password that is not persisted anywhere except the user’s mind, has no back doors; administrators cannot retrieve a lost password to the client app. Also, the AD credentials, when they have to change, can only be changed from within the client app; the user can’t be forced to change their password by AD itself on a Windows login, because doing so will destroy the authentication scheme they need to get into the client app (the encrypted credentials will no longer work, and the client app credentials are needed to re-encrypt the new ones). If you were somehow able to intercept this validation inside AD, and the client’s app credentials were the AD credentials, you could change the credentials in the user app automatically, but now you’re using one set of credentials to obfuscate the same set of credentials, and if that secret were known you’re hosed.
Lastly, this variant of this security system functions solely on one principle; that the server is not currently being compromised by an attacker. Someone can get in, download offline data, and they’re stuck; but if they can install something to monitor memory or traffic, you’re hosed, because when the credentials (either username/password hash or transfer token/hardware ID) come in and are verified, the attacker now has the key to decrypt the user’s AD credentials. Usually, what happens is that the client never sends the decryption key, only the verification half of the hashed password, and then the server sends back the encrypted credentials; but, you are considering the client to be a bigger security risk than the server, so as long as that is true, it’s best to keep as little plaintext as possible on the client for any length of time.