Password storage in code. How to make it safe? - c#

I have made an application in C# that sends mail and SMS ( SMS via an API). It works perfectly, but my concern is that someone will decompile my application, which has the credentials to both the sending emailaccount and the API. The API works with
private void sendSMS(String username, String password, String destination, String body, String sender)
{
String browserURL = "http://api.messagebird.com/api/sms?username="
+ username + "&password=" + password + "&destination="
+ destination + "&body=" + body + "&sender=" + sender;
_w.Navigate(browserURL);
}
Just by decompiling or using wireshark the "hacker" can send SMS as he desires, while the application is designed to send him an SMS on special events like a security breach in his house. also I don't want the hacker be able to change the E-mail's password, so other users don't get their email anymore.
How can I prevent this?
The code is designed to run on the customers own computer/server and alert him for example if there was motion detection.
I thank you all for you answers. I choose to let the customer fill in their own credentials for mail and SMS services, just to avoid having a security breach.

Do not put secrets in code. Put them in an encrypted, safe place, on disk and read it when needed.
Obfuscation is exactly what it says: it hides rather than it protects.
Also: do not send credentials unencrypted over the internet.

The safest way to protect your password is simply to not store it all, at least locally.
As soon as you store anything client-side the safety of the data is only as strong as the safety of the hardware it's sitting on. For example, if someone were to install your app on a public machine (e.g. internet cafe) anyone who knows what they are doing has the potential to get access to your password. It's less of a problem if you can be sure that the app is only going to be installed on private machines and only used by "good" users (which, ultimately, you can't).
How secure you need this password to be is really down to you. The questions you really need to ask yourself are
What sort of damage could be done if they did manage to get the password?
What measures do I have in place to detect any sort of misuse? (e.g. IP logging etc.)
What procedures do I have in place if someone was misusing the API? (e.g. password change)
The 3rd point poses a few problems when storing the password locally. If you detected misuse of the API and consequently changed the password, how can you cascade those changes down to the clients?
For me, the safest way to avoid all these issues is to have your app query your API server and have it return some sort of authentication token (aka API token). This token would then be passed along with any request back to your (hopefully, secure) server which validates the token and, if authorised, forwards the SMS request onto the SMS server.

Consider using System.Security.Cryptography.ProtectedData
This class provides access to the Data Protection API (DPAPI)
available in Microsoft Windows 2000 and later operating systems. This
is a service that is provided by the operating system and does not
require additional libraries. It provides protection using the user or
machine credentials to encrypt or decrypt data.
The class consists of two wrappers for the unmanaged DPAPI, Protect
and Unprotect. These two methods can be used to encrypt and decrypt
data such as passwords, keys, and connection strings.
http://msdn.microsoft.com/en-us/library/system.security.cryptography.protecteddata.aspx

Related

ValidateCredentials() - Security Concerns

I'm hoping all of you .NET devs out there can help me with this dilemma. I currently manage an ASP.NET intranet site at my company. To authenticate our users with Active Directory, we have code similar to the following:
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, string name, string user, string password) {
bool credsOK = pc.ValidateCredentials(string user, string password);
//Check if the creds come back valid
if(credsOK) {
//Do Stuff
}
}
My concern is that someone with access to the code could potentially set a breakpoint at the if statement after the call to ValidateCredentials, add a watch on the password variable, and thus be able to see the user's password in plain text, which to me is dangerous and insecure, especially in a domain context.
So a couple of questions:
1) Why does ValidateCredentials take credentials as plain strings vs. more secure data types?
2) What are some best practice ways I could pursue authenticating the user against AD using their credentials, without using ValidateCredentials()?
Any help you can provide is greatly appreciated.
Thanks,
-rk15000
My thinking on this, if someone has access to the source code and put breakpoints for harvesting passwords, there is probably bigger concerns to worry about. They are after all going to need to be in a position to be able to attach remote debuggers to your production server(s).
To answer your question though. You will probably need to go down the route of separate sign-in services that would isolate the authentication form your application using some SSO tool like ADFS maybe. However based on the example you've given it's unclear how much of an impact that is going to have

C# Most secure way to load a password into Process method with a service

I have a C# service that needs to run a process as another user (interactive mode). That user is an admin level user and I know I should NOT store the password as a string in the code.
I could use some help pointing me in the right direction as all the research I have done seems point to a ton of methods that all do not seem to fit with what I want to do.
Am I required to store a hashed PW in a config file? Can I store a hashed PW right in the code and someone pass that to a secure string? I feel a bit lost here and could use some guidance.
If I understood the problem correctly, you need the plaintext password, so you can start the external process as another user. This would rule out password hashes, since you need the plaintext password.
1) Probably the safest thing you can do, is to ask for the password whenever the service starts. The service can then hold the password in memory as long as the service is up.
This way you don't have to store the password at all on the harddisk.
The disadvantage is of course that the password must be entered when the service starts.
2) If you need to persist the password, there is no absolute safe way, but Windows offers an Api for exactly this problem, the Data Protection API (DPAPI). It solves the problem, that one cannot encrypt a password, without storing the key somewhere (which raises the question of where to store the key...).
using System.Security.Cryptography;
byte[] passwordBytes = Encoding.UTF8.GetBytes(plaintextPassword);
byte[] encryptedPassword = ProtectedData.Protect(passwordBytes, optionalEntropy, DataProtectionScope.LocalMachine);
With this code, Windows will encrypt the password using information of the running computer. Only your process running on this computer should be able to decrypt the password then.

Web service lifetime against authentication list

What I have
I'm making a web service using C#.
In order to authenticate users, they have to send their name plus their encrypted password, in order to check if exists in a database.
Then, If it's found, I create a string token, which is a 10 char string randomly generated in order to send it the next times while the session is alive, avoiding to have to send the original credentials anymore.
What is my problem
Using this approach, my problem appears due to the service lifetime.
It's known that web services are not initialized each time a request arrives, but nor is infinite. So there will be a moment, when it'll be destroyed and initialized again.
At this point, my token list would be erased, as well as all the alive connections with it, as this is its function.
So I'm stuck at this point. I'm not sure about how to proceed, maybe I'm just fooling around and there's a simpler way to authenticate users? Or maybe you've and idea about how to don't loose all these alive sessions without having to write them at a DB.
Thank you in advance
Update:
My goal
I aim to create a personal Web Service, just build for me and some friends. Not inside a company nor anything like this. Not in the same LAN neither.
I want to add a bit of security to this service, so I wanted to add authentication to the WS, mainly in order to avoid people pretending to be another and this kind of stuff. So I created User+Password system.
Then, in order to avoid to send them both in each WS Request, I started to write the "token" approach described above.
Notice that I'm using token word because it's similarity with token systems for these cases, but it's a completely created from 0 system, nothing proffesional, so do not assume anything complex about it if I've not said that.
How my system works (or try to)
User -> Auth (user, pass_encrypted) -> WS -> DB (exist? OK)
WS -> token (randomly generated, 10char string) -> User
After that, at each WS request, User sends the token instead of credentials.
After receiving it, WS looks for the token at a List<structureToken>, so it obtains the user which is doing the call, and (for example) the access level, in order to know if the user has rights to run this call.
Your current problem is that you want same list to be persisted through restarts and not persisted to any physical media at the same time. You have to pick one of the choices and live with it: not persisted - just ignore the fact you can have list in memory and make sure token can be validated by itself, if persisting - pick storage and save you list of random numbers.
Since you are building simple system without actual need to have proven verifiable security you can get some ideas from existing systems (like STS and the way it creates token). Basically STS signs information about user (indeed after validation) and than encrypts it with public key of receiving party. So particular server that supposed to get the token can decrypt it (as it has private key part), everyone else may still use it but have to treat as non-verifiable black box token.
Simplest version of this would be no encryption of information, just basic signing. Proper signing requires private/public pair (so external party can validate signature), but since in your case both parties are the same service - you can just SHA256. To prevent external callers to fake you signature you need to have some private information included in hash to "salt" value before hashing. Random number hardcoded into server code (or read from settings) would be good enough. You may also want to include expiration as part of signed value.
So your "token" could look like:
Name,expiration,Base64 of SHA256 of {Name + expiration + secret value}
Bob-2015-06-30-A23BDEDDC56
Since your server code have "secret value" you can always re-compute hash to verify if it is indeed the correct token.
Notes:
do not use it for any real services. Use an existing authentication and make sure to review all security comments related to proper usage of it.
this approach gives you chance to learn a some other concepts - i.e. key update (when your "secret value" need to change, or in real systems signing/encryption certs).

OAuth 2.0 authentication to Gmail works for accounts with gmail.com domain but not for Google Apps domains

I have a C# installed application that accesses Gmail via IMAP. Using traditional IMAP authentication, it works well both for individual Gmail users and for Google Apps users.
I have now added support for OAuth 2.0 authentication using Google's .Net APIs. This works beautifully for regular Gmail accounts (e.g. someone#gmail.com) but fails for Google Apps accounts that have a different domain. The user is prompted to login via web browser and accept the access but then the IMAP authentication attempt fails with "Invalid credentials". Is there something that needs to be done differently for a Google Apps domain?
As I first reported in a comment below, I made a minor breakthrough with this. Originally I was calling GoogleWebAuthorizationBroker.AuthorizeAsync() with the literal string "user" for the user argument (because this is what I had seen done in many examples). This works for regular Gmail users but I find that, for Google Apps, one must pass the actual email address of the authorizing user.
For a while I thought that this was the whole solution to the problem. It turns out not to be however. The trouble is that it now works perfectly in in-house testing but routinely fails in the same old way at the one beta site we have. I can think of only 4 possible reasons for the failure: (1) the program is getting an invalid access token, (2) it is corrupting that token somehow, (3) it is doing the XOAUTH authentication wrongly or (4) it is using the token to authenticate an account that the token does not apply for. I assume Google is unlikely to supply an invalid token so (1) can largely be discounted. (2) and (3) are always possible but the fact that the code works for our own several Gmail and Google Apps accounts makes them seem unlikely. And the customer insists that (4) is not the case. So I remain puzzled.
It was suggested early on that I post some of my code and I am now ready to do that. Here is the start of the C# function that performs the authentication:
private void AuthenticateXOAuth2(string strUsername, string strAccessToken)
{
uint uStatus = 0;
// The SASL XOAUTH2 initial client response has the following format:
//
// base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A")
string strInitialClientResponse = "user=" + strUsername + "\x1" + "auth=Bearer " + strAccessToken + "\x1\x1";
byte[] vbInitialClientResponse = Encoding.UTF8.GetBytes(strInitialClientResponse);
string strBase64InitialClientResponse = System.Convert.ToBase64String(vbInitialClientResponse);
string strCommand = "AUTHENTICATE XOAUTH2 " + strBase64InitialClientResponse;
SendCommand(strCommand);
...
I am still struggling with this, going up blind alleys and getting even more frustrated. I have to correct one thing I said before: I asserted that the program was working for Google Apps domains in in-house testing. This was an illusion; it actually never has.
Someone told me that I need to use a Service Account to cover domain users. This seems puzzling to me since my program is in no sense a server but I tried it. And it did not work the way I tried it -- but I cannot be sure I did it right. Having some confirmation or negation that using a Service Account is the right strategy would help tremendously.
Without seeing your code, my only hunch is that you're not sending the full email address for the initial client response:
https://developers.google.com/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism
other than that, showing your code may help us in seeing the issue.
Probably you need to check if IMAP/POP is activated in your domain account; In the company i work they restricted this access by security reasons, here's how you should enable it:
Enable IMAP in your Gmail settings
Sign in to Gmail.
Click the gear in the top right.
Select Settings.
Click Forwarding and POP/IMAP.
Select Enable IMAP.
Click Save Changes.
Ref: https://support.google.com/mail/troubleshooter/1668960?hl=en#ts=1665018

Storing My Amazon Credentials in C# Desktop App

I'm Looking at using Amazon S3 and simpleDB in a desktop application.
The main issue I have is that I either need to store my aws credentials in the application or use some other scheme.
I'm guessing that storing them in the application is out of the question as they would be easily picked out.
Another option is to create a web service that creates the aws authentication signature but this has its own issues.
Does the signature require all the data from a file thats being uploaded? If so I would have to transfer all the data twice.
There would then be a central failure point which was one of the main reasons for using aws.
Any ideas?
UPDATE:
I needed to make it a bit clearer that I'm wanting to store my aws credentials in an application handed out to others. DPAPI or any other encryption would be only stop people simply using reflector to get the credentials. Using any encryption still needs the key that is easy to get.
UPDATE 2 - Sept 2011
Amazon have released some details on using the AWS Security Token Service, which allows for authentication without disclosing your secret key. More details are available on this blog post.
Tim, you're indeed hitting on the two key approaches:
NOT GOOD ENOUGH: store the secret key "secretly" in the app. There is indeed a grave risk of someone just picking it out of the app code. Some mitigations might be to (a) use the DPAPI to store the key outside the app binary, or (b) obtain the key over the wire from your web service each time you need it (over SSL), but never store it locally. No mitigation can really slow down a competent attacker with a debugger, as the cleartext key must end up in the app's RAM.
BETTER: Push the content that needs to be protected to your web service and sign it there. The good news is that only the request name and timestamp need to be signed -- not all the uploaded bits (I guess Amazon doesn't want to spend the cycles on verifying all those bits either!). Below are the relevant code lines from Amazon's own "Introduction to AWS for C# Developers". Notice how Aws_GetSignature gets called only with "PutObject" and a timestamp? You could definitely implement the signature on your own web service without having to send the whole file and without compromising your key. In case you're wondering, Aws_GetSignature is a 9-line function that does a SHA1 hash on a concatenation of the constant string "AmazonS3", the operation name, and the RFC822 representation of the timestamp -- using your secret key.
DateTime timestamp = Aws_GetDatestamp();
string signature = Aws_GetSignature( "PutObject", timestamp );
byte[] data = UnicodeEncoding.ASCII.GetBytes( content );
service.PutObjectInline( "MainBucket", cAWSSecretKey, metadata,
data, content.Length, null,
StorageClass.STANDARD, true,
cAWSAccessKeyId, timestamp, true,
signature, null );
EDIT: note that while you can keep the secret key portion of your Amazon identity hidden, the access key ID portion needs to be embedded in the request. Unless you send the file through your own web service, you'll have to embed it in the app.
The main issue I have is that I either need to store my aws credentials in the application or use some other scheme.
Does Windows have a system-wide service similar to Apple's Keychain Manager? If so, put your credentials there. If not, perhaps you can build a watered-down version of it for storing a strongly-encrypted version of your AWS credentials.
Does the signature require all the data from a file thats being uploaded?
The HMAC SHA-1 signature is an encoded encryption of the HTTP request headers. This signature is a hash value and will be very short relative to your data, only 20 bytes long.
You can encrypt the config file and/or use ProtectedData. Here's my blog post on both.
UPDATE: You might be a be to encrypt your app.config as part of an install step. Sample here: http://www.codeproject.com/KB/security/encryptstrings.aspx. Not great, but the best I've found so far.
Will you let anyone that gets a hold of a copy of your program access the data on S3/SimpleDB? If not, you will need your own authentication scheme that's independent from AWS security.
In that case, you could implement a web service that accepts the credentials that you give your customers (a username/password for example, a digital certificate, etc) and then performs the S3/SimpleDB operations that your program requires. That way, the AWS credentials never leave AWS. If a particular user's credentials are compromised, you can cancel those credentials in your web service.

Categories

Resources