I am making a custom ftp client that logs onto a single ftp site and goes to a specific folder to avoid users' putting files in the wrong place.
I'm not super concerned about it, but the password is just a string to initiate the new ftp object.
FtpClient ftp = new FtpClient("www.markonsolutions.com", "user", "password");
What is the best way to keep this password from prying eyes?
FTP supports only plain text authentication - if you want to hide the password from attackers you have to use FTPS (FTP over SSL).
UPDATE
Don't care about hiding and obfuscating the password in your source code as a first step - your application will have to decrypt it and send it over the wire in plain text. Everyone can just start WireShark or any other packet sniffer and get the password back in plain text. First make sure that you don't send the password in plain text over a network, then start thinking about obfuscating it in your code.
UPDATE
Obfuscating the password in your code yields no security at all while you are sending it in plain text, but you can do so. Just encrypting the string adds one level of indirection. Without obfuscation I have to finde the password in your application and that's a matter of minutes with Reflector, with obfuscation I have to find the key, the encrypted password, and the encryption method. This will probably still take only minutes.
Using an obfuscator to prevent me from decompiling you application (into readable code) might stop me for a few hours until I find the relevant call into a system library function (but I wouldn't try, but only read the password from the wire ;).
So I suggest not to try to hard to obfuscate the password - the average user is probably unable to find a plain text password in a executable and people willing to find the password cannot be stopped by obfuscation. In this case the only way would be not to include the password in your application in the first place.
You can use this to protect your plain text string from reflector like programs.
See this SO post about how to encrypt and decrypt a string, in this case your password.
You should also consider obfuscating your code to make it difficult for people with appropriate tools to get the password by debugging your code.
Make your passwords and connection URLs configuration parameters, in a protected file. I uses INI files, and they are placed in a directory that is protected by the web server such that a browser can't open nor see the file/directory.
Related
Can someone give me a starting point on how to send an encypted mail from my C# .NET Application to a Lotus Notes inbox (in the company intranet)?
I requested a certificate and Notes User from our support.
But now I'm stuck. I read through this guide, and implemented the code but know the mails in my inbox do not have any content, but just a file named smime.p7m. So I am generally unsure if this is the right method.
Can you give me a hint to a tutorial or tell me the steps I need to do?
Or is the linked guide generally right and I goofed something up? In this case please leave a comment an I'll add my code.
Thank you very much in advance!
UPDATE 1 (26.08.16):
Here is what I'm now at so far:
System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("smtp.services.companyname");
smtp.Credentials = new System.Net.NetworkCredential("NOTESUSER","password");
smtp.Send(message);
In Notes itself I ticket the checkbox for "Send my mails encrypted". The thought behind it was the following:
I assumed this way the Notes User passes the credentials to the Smtp Server and uses the usersettings.
The eMails get delivered, but are not encrypted.
Maybe you could try and break down things a bit further. What about sending an encrypted email from a basic mail client like Thunderbird to a person who will open it in her Notes client ?
The fundamental thing is that the recipient must have a private key symetric to the public key you used for encryption. In normal use, Domino does this very well as it comes with its own two-factors PKI : users can't sign in without their private key, which is stored on their workstation in a tiny (~3 ko) file named something like hername.id or user.id. The corresponding public key is for all to see, as it should, in the Domino Directory (names.nsf)
While based on standard RSA stuff, those usual pairs of keys are managed and deployed in ways very specific to Domino.
Now, it is perfectly possible for a user to import a private key issued by a third-party certification authority. I don't have the exact procedure at hand right now buy you'll find it in the help.nsf available to any Notes client.
But I wonder. You are inside the intranet, which means that you do have access to the Domino Directory, thus to the usual public key of the recipient. Your application will probably need its own user.id and it's more than likely that you'll need to have the 1352 hole punched in various firewalls. By the way, if it helps to alleviate any concern, by virtue of the aformentioned native PKI, it is very easy to encrypt communications on port 1352 from end to end.
Another option is as follow. The Domino server is also a web server. Sometimes this option is activated, sometimes not. If it is, or if you can make it happen, the directory is available as a web application. Zooming in on the public key of a user would require some tinkering and some HTML parsing but should be doable.
One last one for the road, although you may not like it : Domino is a very good platform for intranet applications, be it of the client-server persuasion or of the HTTP creed.
Okay, here is what I finally did:
Domino.NotesSession nSession = new Domino.NotesSession();
nSession.Initialize("secretpassword"); //password for the Notes User
Domino.NotesDatabase nDatabase = nSession.GetDatabase("SERVER", "names"); //Server and location of the names.nfs file
Domino.NotesDocument nDocument = nDatabase.CreateDocument();
NotesStream nStream;
nDocument.ReplaceItemValue("Subject", tmp.Subject);
nBody = nDocument.CreateMIMEEntity();
nStream = nSession.CreateStream();
nStream.WriteText(tmp.Body);
nBody.SetContentFromText(nStream , "text/HTML;charset=UTF-8", MIME_ENCODING.ENC_IDENTITY_7BIT);
nDocument.EncryptOnSend = true;
nDocument.Send(false, user.INS_EMAIL);
This creates a Notes Session with the latest Notes User logged in. So you install the Notes client on the Server, log in with the user and it works so far.
We have a small console application (under 200kb) that will be distributed to clients and we want to ensure they run the latest version (verified by a WCF service). Currently it downloads the new .exe file over HTTPS and replaces the current .exe file with it.
Assuming our server isn't compromised, this would be ok. However we also sign our .exe file with a Code Signing certificate. Is there a way to verify this and delete the file if it doesn't match? We would need to be able to verify and delete the file without it ever being executed in case it is a virus.
How can we verify our signed .exe file? For example, Windows will show if it is invalid:
Edit: would this code do the job?
X509Certificate basicSigner = X509Certificate.CreateFromSignedFile(file);
X509Certificate2 cert = new X509Certificate2(basicSigner);
if (cert.Subject.Contains("CN=MY COMPANY NAME IN CERTIFICATE"))
valid = true;
Edit: if we also check StrongNameSignatureVerificationEx, it comes back failed if one bit is changed in the file. Perhaps this is enough?
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);
Edit: I've implemented this code too which calls WinVerifyTrust in WinTrust.dll to actually verify the Authenticode signature: http://www.pinvoke.net/default.aspx/wintrust.winverifytrust
Now, it checks if the digital signature contains the correct subject, is from a valid trusted root, the signature is valid and if the code is strong named with it's digital signature. This must be safe enough now?
This is a nice walkthrough including source code on the options available to achieve what you want...
Basically you need to pinvoke StrongNameSignatureVerificationEx since there is no managed API to do what you need.
Another option might be to call SignTool.
This is a pretty fundamentally wrong way to go about it. The only thing that a code signing certificate proves is the identity of the person or company that signed the EXE. The certificate authority merely proves that identity is valid. What you haven't proved at all is that it is your certificate, you only proved that it is somebody's certificate. An attacker could trivially replace your EXE with another one that was signed by him.
You'll probably object with "but can't I just verify it is mine!". And the answer is no, if the attacker can replace the EXE then he'll have no trouble replacing your checking code either. There is zero security in having the verification performed on the same machine.
Code certificates serve only one purpose, they prove the identity of the signer to the user. Making them do anything else is a security hole. The really bad kind, the kind that make you feel that your system is secure. And make you stop thinking about implementing real security.
I have a bit of code that needs to run with elevated privileges (more that I want the rest of my code running at).
I have my code that sets up the Impersonation working, but it requires a username, domain and password. As my code is in C#.net I know that the password can be found by anyone determined enough.
Is there a way to encrypt the password in my code? Or otherwise secure this password and still be able to pass it in?
Here is the code I am calling:
using (new Impersonator("UserNameGoesHere", "DomainNameGoesGere", "Password Goes Here"))
{
uint output;
NetUserAdd(AUTHENTICATION_SERVER, 1, ref userinfo, out output);
return output;
}
I would love an example that shows how to fix this to not show my password in plain text.
I am using Visual Studio 2008, .NET 3.5 SP1, and running on Windows Server 2003.
Vaccano,
I would recommend investigating the data protection API (DPAPI) for what you're attempting to achieve. It is considered part of the solution in many best practice approaches to reversibly storing passwords needed by applications.
A good article discussing the DPAPI (and other techniques + concerns) can be found here:
http://msdn.microsoft.com/en-us/magazine/cc164054.aspx
With C# 2.0, P/Invoking isn't even required; managed wrappers exist:
http://blogs.freshlogicstudios.com/Posts/View.aspx?Id=41ca5a99-ddc0-4d0a-9919-2ce10bf50c7e
I hope this helps!
You have multiple options here.
You can hash the password the very first time and store the hash to a file. Now the next time, you want to execute the code with elevated privileges, you need to accept/retype the password and re-compute the hash and match it with the stored hash. Only if it matches will you execute your code in elevation modes. You could hash using SHA. Please look at System.Crytography namespace for examples on hashing.
Second option is to encrypt the password using algorithms like AES. However you will need to have a key to do this and you will have to worry about securing this key.
Third option is to use DPAPI and encrypt the password but not worry about securing the keys - much easier option than 2.
I would recommend 1 if you do not mind re-entering the password every time the application starts. If that is not a possibility, I would suggest going with 3 and use DPAPI.
Here are some links to get you started.
1.http://www.obviex.com/samples/dpapi.aspx
2. http://www.obviex.com/samples/Encryption.aspx
You can use safe-config nuget package. Internally it uses data protection api to encrypt and decrypt data.
//Save some configuration data at folder data\temp\
var configManager = new ConfigManager()
.WithOptions(DataProtectionScope.CurrentUser)
.Set("password", "my-massword")
.AtFolder(#"data\temp\")
.Save();
...
//Load configuration data
var loadedValue = new ConfigManager()
.AtFolder(#"data\temp\")
.Load()
.Get<string>("password");
I need to store and encrypt a password in a (preferably text) file, that I later need to be able to decrypt. The password is for another service that I use, and needs to be sent there in clear text (over SSL). This is not something I can change. What are best practices in this area? How can achieve some degree of protection of the password from malicious users?
My platform is WinForms with C#/.NET 3.5.
Thanks.
I am assuming that you want to encrypt the password as it will be on the users machine and they will (possibly) be able to find it and use it? If so you are basically screwed - no matter what you do, since it is in the users domain they will be able to get it and figure out the encryption and get the password for the encryption (remember that using Reflector - and it's clones - isn't out of the reach of most) and decrypt it and they have it. In short all you are doing is obfuscating the password, not securing it.
What I would recommend is actually move it out of the users control. For example put up a web service which communicates with the client and returns the password securely when requested. This also allows you to change the password, if needed in future as well as provides you with a way to validate legitimate users.
Why you need to decrypt the password? Usually a salted hash of the password is stored and compared. If you encrypt/decrypt the password you have the password as plain text again and this is dangerous. The hash should be salted to avoid duplicated hash if the some users have the same passwords. For the salt you can take the user name.
HashAlgorithm hash = new SHA256Managed();
string password = "12345";
string salt = "UserName";
// compute hash of the password prefixing password with the salt
byte[] plainTextBytes = Encoding.UTF8.GetBytes(salt + password);
byte[] hashBytes = hash.ComputeHash(plainTextBytes);
string hashValue = Convert.ToBase64String(hashBytes);
You can calculate the salted hash of the password and store that within your file. During the authentication you calculate the hash from the user entries again and compare this hash with the stored password hash.
Since it should be very difficult (its never impossible, always a matter of time) to get the plain text from a hash the password is protected from reading as plain text again.
Tip: Never store or send a password unencrypted. If you get a new password, encrypt is as soon as possible!
System.Security.Cryptography.ProtectedData in the System.Security assembly uses some Windows APIs to encrypt data with a password only it knows.
One possibly use of this would be to have a Windows service that actually does the operation requiring the password. The application that the user interacts with calls into the service via remoting or WCF. As long as the service used DataProtectionScope.CurrentUser and the service user is different from the logged on user, the password should be pretty safe.
This of course assumes that the users are running as limited users who cannot modify the service or run program as the service's user.
Because you are using WinForms and .Net, your code is going to be visible in MSIL - even if obfuscated, and therefore your decryption code is visible.
Who are you trying to hide the password from? Is the user of the app not supposed to know the password?
I think you are going to need to do some user validation, and I would be tempted to put keys to the decryption in a separate database and provide some other mechanism to get that out which should require authentication. That way you can get the decryption code out of the winforms app.
I would also suggest a separate service which runs to regularly change the encryption decryption keys and updates all passwords in the database.
Encrypted in AES if you must store it in a text file.
AES is better known as Rijndael in c#
http://www.obviex.com/samples/Encryption.aspx
Better place would be the registry, since it would protect other users of the machine getting to it.
Still not the best storing it anywhere that a user might be able to get to is dangerous a 1/2 way decent developer can load up your app in reflector and find your key.
Or there is System.Security.Cryptography.ProtectedData that someone else suggested.
The best you could do on a machine is create a certificate and encrypt/decrypt with it loaded and locked down in the machine's keystore. (Still have to deal with the certificate password being in your code)
I just implemented something like this for storing a user supplied password. I converted the encrypted result to a base 64 encoded string, so that I could easily store it in my application's user settings.
From your question, it seems that your malicious user is actually using your application, so this will only provide obfuscation. Though no key would be revealed through the use of Reflector, the plain text would be visible in a debugger.
static byte[] entropy = { 65, 34, 87, 33 };
public string Password
{
get
{
if (this.EncryptedPassword == string.Empty)
{
return string.Empty;
}
var encrypted = Convert.FromBase64String(this.EncryptedPassword);
var data = ProtectedData.Unprotect(encrypted, entropy, DataProtectionScope.CurrentUser);
var password = Encoding.UTF8.GetString(data);
return password;
}
set
{
if (value == string.Empty)
{
this.EncryptedPassword = string.Empty;
return;
}
var data = Encoding.UTF8.GetBytes(value);
var encrypted = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser);
var stored = Convert.ToBase64String(encrypted);
this.EncryptedPassword = stored;
}
}
Do not store the password as part of the code. Aside from the issues of decompilation and relying on security through obscurity, if you change the password you need to recompile and redistribution your application.
Store the password as a webservice or in a database that the application has access to. You're communicating with a service over the web, so you will be connected, after all.
One of the most important thing is the permissions on the file. Even if the content is encrypted you need to make sure that only the processes that need access to the file can read it.
Since you must send the password in unencrypted form over the network, there is nothing you can do to protect it 100%.
AES is good enough if you need to store locally, and talking about disasms, network sniffers etc is not particulary good contra-argument becuase the same thing can be done with any program (sure, ASM is harder then CIL but its a minior point).
Such password protecting is good enough to prevent casual pick up, not to prevent decoding by proffesionals.
I am deploying a Windows Application that uses SQL Server 2005. The program will use SQL Authentication.
My question is, how do you handle the connection string when you don't know what the username/password will be? Do you load this from an encrypted file? Or are there provisions for handling this already?
If the user will provide their login details (username and password) then you just need to provide the ability to enter them in your app, e.g. show a dialog asking for these details. You can then use those values the user gives to build the connection string in your code.
Alternatively, if all your users are going to be using a single SQL account to connect then you can put the connection string in your app.config file using encryption if you want to hide it from your users, see cmsjr's answer for an example of how to do this.
Alternatively, if you're developing this on an internal domain (intranet) then switch your database to integrated security and put your users domain accounts into the relevant access group on your database server. Then you won't have to worry about collecting username or passwords at all.
If the enduser will provide the password you don't need to do anything, dont save the usernamne/password in the config file.
If you don't want the end user to provide the password you could put it in the config file at installation. But that could be a problem if the username needs to be changed and you have encrypted the connectionstring.
Encrypting sections of the configuration is not as simple for a windows app as for a web app, but it is certainly doable. Here's a sample.
Just make sure to check the username/password for "weird" characters that the user might enter. The last thing you want is for them to change around your connection string. Then basically you just specify the driver (if using ODBC), the database, the server, but leave all the username/password and trusted connection info out. Then just tack on username= and password= which will be set equal to what was entered by the user on the end. However watch out for semicolons. I've never tried to see what happens if there is both a username/password and a trusted_connection = true.