I'm working on my first real WinForms application, and my boss has asked that I figure out a way to encrypt the connection string inside the app.config. I've read some of the suggestions in other questions about connection string encryption, and I recognize that it isn't a silver bullet answer to the security/privacy problem. We've considered writing web services to retrieve data from the database, but this is a very small project and unfortunately isn't a priority at this time.
Edit: I left out the detail that I'm working for a state institution (community college) where, because we're identifying students using a state-mandated private system ID, we need to secure the application in some form or fashion. Students may enter their network IDs to identify themselves (which we need to protect anyway as some students have restraining orders and need much of their records kept private), but many students only know their system IDs (which are always kept private).
Regardless, we'd like to get this process working in conjunction with ClickOnce deployment, but my encryption process crashes the application when I run the ClickOnce executable. Here's my encryption code (which is lifted from another question here on SO):
public static void EncryptConfigSection(string sectionName)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection section = config.GetSection(sectionName);
if (section != null)
{
if (section.IsReadOnly() == false &&
section.SectionInformation.IsProtected == false)
{
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}
}
ConfigurationManager.RefreshSection(sectionName);
}
I'm calling this function from the Main() function in Program.cs, but I'm not sure if this is the appropriate place for it. Additionally, while this function encrypts the app.config correctly, as soon as I exit the application, the app.config decrypts. I feel like I'm missing a piece to the puzzle (or perhaps large swaths of the puzzle).
Can anyone offer me some insight into these problems? I'd like to reiterate that I recognize that web services are the end goal here, so if this is just not a solvable problem using CLickOnce, then I'm willing to suggest that we prioritize writing web services now.
Have you looked at this topic? It talks about setting up the client using DPAPI so the string is encrypted. I would still look at the web services route rather than embed a connection string, encrypted or not, into a client application. This is ESPECIALLY true if you are talking about client apps outside of your domain (ie, non-employee use).
Related
General/Introduction:
I work on a project where we have two parts of software. There is a client application that runs on the user's computer and a web application that manages a lot of things related to this project.
The client application reads a lot of different values via IPC from another program, that I don't have the source code of and I don't have the option to change anything in that other program I am reading from.
So, my application collects those values and stores them locally, since it is not always connected to the web application.
Since the web application builds statistics and more out of those values and since the values that are collected are quite important for the whole project, the user should not be able to change them (or at least it should be really hard - I am pretty sure you can't provide 100 % security for data on the client).
Just for the sake of full information: The client application is written in C#, while the web application is based on the Laravel Framework (PHP). But this question is more about theory than exactly how to code this.
My thoughts:
I was thinking about having asymmetric encryption. The client encrypts the data with the public key of the web application server. The data is now stored encrypted. But of course, the client has this public key. Hence, an attacker could just go ahead and encrypt his own manipulated values and store them in the file.
Another thought, that builds upon the encryption, was that I could not only encrypt the data, but the whole file and use a format that is not too obvious. But that is more like security through obscurity and should be avoided as far as I know. Plus one could just decompile the client application and instantly have the format that I am using.
My question:
Is there any way I can provide a decent level of integrity when sending that data to the server? If so, how can it be done?
There are two things you can do:
Give up, because client software authenticity is not the server's problem, and it's theoretically impossible to know for sure that the other end is running the software you intend in a way that isn't spoofable.
If you're using the client software as a data mule, use hash_hmac() and hash_equals() to authenticate the data so it's tamper-evident.
For example, you could store the MAC by prefixing it to the data:
$key = random_bytes(32); // Store me for long-term. Maybe per-client?
$data = "foo";
$mac = hash_hmac('sha256', $data, $key);
echo $data . $mac;
And then to validate it upon being returned by the client software:
if (mb_strlen($message, '8bit') < 64) {
throw new Exception("Invalid message length.");
}
$mac = mb_substr($message, 0, 64, '8bit');
$data = mb_substr($message, 64, null, '8bit');
$recalc = hash_hmac('sha256', $data, $key);
if (!hash_equals($recalc, $mac)) {
throw new Exception("Invalid MAC.");
}
// Now we know $data is legitimate.
It is important to use hash_equals() not == or === to prevent timing attacks.
Note that this renders any such data unavoidably read-only. If you want them to be able to edit data, you're stuck with option 1.
I have done the following...
private static IDbConnectionProvider CreateSqlConnectionProvider(DbConfig dbConfig)
{
return new QcDbConnectionProvider(() =>
{
SqlConnectionStringBuilder csBuilder = new SqlConnectionStringBuilder();
if (!string.IsNullOrEmpty(dbConfig.DataSource))
csBuilder.DataSource = dbConfig.DataSource;
if (!string.IsNullOrEmpty(dbConfig.Database))
csBuilder.InitialCatalog = dbConfig.Database;
.
.
.
.
return new SqlConnection(csBuilder.ConnectionString);
});
}
The client is using VERACODE tool for doing code analysis and the VERACODE has detected a flaw "Untrusted initialization" at
return new SqlConnection(csBuilder.ConnectionString);
Also, the dbConfig is being initialized as shown below...
DbConfig configDbConfig = new DbConfig
{
Database = codeFile.ConfigurationDb,
DataSource = codeFile.DataSource,
IntegratedSecurity = sqlCredentials.UseWindowsAuthentication ? 1 : 0,
UserId = sqlCredentials.UseWindowsAuthentication ? null : sqlCredentials.SqlUserName,
ClearTextPassword = sqlCredentials.UseWindowsAuthentication ? null : sqlCredentials.SqlUserPassword
};
What else I need to do in order to fix this flaw? Also as per this link, I am creating the connection string using the SqlConnectionStringBuilder which is safe of creating the connection string.
Thanks in advance...
Description for Untrusted initialization issue is:
Applications should be reluctant to trust variables that have been initialized outside of its trust boundary. Untrusted initialization refers to instances in which an application allows external control of system settings or variables, which can disrupt service or cause an application to behave in unexpected ways. For example, if an application uses values from the environment, assuming the data cannot be tampered with, it may use that data in a dangerous way.
In your case you're reading data for dbConfig from file:
if (TryReadCodeFile(configurationProfileFile...)) {
DbConfig configDbConfig = new DbConfig...
}
Note that warning you get should also come with a line number (to circumscribe erroneous code). Almost everything in code you posted can generate this issue (I don't see where sqlCredentials comes from but it may even be another source of security problems if they're in clear text - or code to decrypt is accessible in your application).
From cited paragraph: "...application allows external control of system settings or variables, which can disrupt service...". This is the core of this issue: if your application uses external data without a direct control over them then its behavior can be changed modifying that data. What these external data are? List is all but not exhaustive:
Environment variables (for example to resolve a path to another file or program) because user may change them. Original files aren't touched but you read something else.
Paths (to load code or data) because user may redirect to something else (again original files aren't touched but you read something else).
Support files because user can change them (in your case, for example, to point to another server and/or catalog).
Configuration files because user can change them (same as above).
Databases because they may be accessible to other users too and they may be changed (but they may be protected).
How a malicious user may use this? Imagine each user is connected to a different catalog (according to their rule in organization). This cannot be changed and it's configured during installation. If they can have access to your configuration files they may change catalog to something else. They may also change DB host name to a tunnel where they may sniff data (if they have physical access to someone else's machine).
Also note that they also say "...assuming the data cannot be tampered with, it may use that data in a dangerous way". It means if, for example, your application runs on a web server and physical access is secured then you may consider that data safe.
Be aware your application will be secure as less secure item in your whole system. Note that to make an application safe (I know, this term is pretty vague) to encrypt password is not enough.
If support files may be manipulated then best thing you can do is to encrypt them with a public/private key encryption. A less optimal solution is to calculate a CRC or hash (for example) you'll apply to configuration files before you use them (they are able to change them but your application will detect this issue).
To summarize: you can ignore this issue but you have to prove your customer that data you rely on cannot be tampered. You can reasonably prove if at least one of these conditions is satisfied:
1) System where support files reside is not accessible by anyone else than your application. Your application security cannot be higher than system security.
2) Your support files are valid per-machine (to avoid copies between different machines) and they're encrypted in a way they cannot be changed (intentionally or not) by anyone.
3) Your support files are valid per-machine and they're hashed in a way your application can detect external changes.
4) It doesn't matter what users do with your configuration files, application itself cannot change its behavior because of that (for example it's a single installation where only one DB and one catalog exist).
The most important for connection strings is how they are stored. If they are stored in plaintext, this poses a security risk. So, it is advisable to store them in encrypted format and in application decrypt and use it.
I have a requirement to protect my Web.config file from malicious users accessing our webserver & junior developers in team. I have used RsaProtectedConfigurationProvider to successfully encrypt & decrypt our file. However, decypting the connection string is as easy as accessing it from withing my application, no matter if it is encrypted or not
protected void btnShowConnectionString_Click(object sender, EventArgs e)
{
lblMessage.Text = WebConfigurationManager.ConnectionStrings["MyTestConnection"].ConnectionString;
}
How do I secure my connection string to avoid work arounds like these?
You cannot do this with standard solutions.
To do such protection you should write your own wrapper around standard library using this connection string, that will decrypt connection string from webconfig.
And you should protect your wrapper from decompiling with something like Sentinel Hasp. If you don't protect your wrapper it will be simple to get encryption algorithm and decrypt connection string.
But it will be simpler to do not write production connection strings to developers webconfig. Use developer enviroment for developing and write production enviroment connection strings when deploying to production enviroment.
You can read this link about secure string connection, recommended solution by msdn
link : http://msdn.microsoft.com/en-us/library/89211k9b(v=vs.80).aspx
IMHO, the "workaround" you are mentioning isn't really a workaround, rather, it is what it is.
Your application (web or otherwise), must be able to decyrpt the information so that i can actually make the connection. Unless you are using Windows Authentication to your SQL server, user/pwd are always "there"...the nagging question I have is why/how would such code exist in your application (in the first place)?
As noted above in previous answers, separate your development environment from production - perhaps only have production config transforms in production environment.
I am using Visual Studio 2010 and Microsoft Access 2010 to develop a desktop application using C# programming language.
connection string is:
connectionString="Provider=Microsoft.ACE.OLEDB.12.0;Data
Source=|DataDirectory|\KBank.accdb;Persist Security Info=False"
and i give it the password in the C# code as follows:
public string GetConnectionStringByName()
{
string returnValue = null;
ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Info_Bank_Project.Properties.Settings.KBankConnectionString"];
if (settings != null)
returnValue = settings.ConnectionString + ";Jet OLEDB:Database Password=blablabla";
return returnValue;
}
i have used the database in the project in just one simple "Select" query.
so, concerning to the security issue..
can any one decrypt the access database or see the password?
and what is your suggestion to make it hard for any one to see the database data
This is little old thread, My experience on this issue might help someone.
You can create C++ DLL with the strong password located inside it, then call it from C# app to encrypt/Decrypt methods with the data base file name.
No, your data is not safe, since anyone can inspect your code using an MSIL decompiler and retrieve your connection strings from your app. There will be a point at some point in your process where someone has the possibility of seeing that password, whether it's in memory, in reflection, or something else.
If you have data that is in the possession of someone other than you, not on your servers, then you can assume you no longer have control over that data.
Now, with all that said, you can make it harder for them to get to by encrypting the database file and obfuscating your code.
Why not just put the password in your app.config and encrypt the app.config.
See here
I have a web application , for presentation to my client they ask me to install it on their local server so they can test it , here is my question !?
Is there any way so i can publish uniquely for that server , i did put some limitation but many features in my app are open , so they can make a disk image from server and use it anywhere else ,
Is there any method to use so my web application check if this server is same server ( by hardware id or anything i don't have any idea ) then start to work !
I saw many codes but they are win forms for generating unique hid , but how can i connect done it with asp .net
EDIT
Could u take a look at this also ,
i am using system.management class
is this reliable i mean are they unique ?
private string GetUniqueID()
{
string cpuInfo = string.Empty;
ManagementClass mc = new ManagementClass("win32_processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if (cpuInfo == "")
{
//Get only the first CPU's ID
cpuInfo = mo.Properties["processorID"].Value.ToString();
break;
}
}
ManagementObject dsk = new ManagementObject(#"win32_logicaldisk.deviceid=""" + "C" + #":""");
dsk.Get();
string volumeSerial = dsk["VolumeSerialNumber"].ToString();
string HardWareUniqueID = volumeSerial + cpuInfo;
return HardWareUniqueID;
}
Appreciate your answers,
Thanks in advance
If you want to avoid having it "phone home" an alternative is to generate some kind of certificate and place it on the machine. Use a private key that only you know to encrypt the machine name and/or IP. Then have your app use your public key to decrypt it to verify that it is allowed to run on this server. Nobody who doesn't know your private key will be able to create valid certificates.
You hae a few choices...
Lock your web site to the single IP address you install it on. To make your life easier, check for that IP in a common page base class. (Note, you could also write HTTP handlers, but the base-class approach is easier.)
Put a 'phone home' call in the app that checks with your server every time it's started up. That way you can check if they have moved it or if multiple instances are running.
Use the built-in licensing features of .NET (the same one third-party developers use for controls, etc.)
The easiest... just put in a time-bomb that lets them test it for a few weeks, then automatically blocks access. Be smart though... persist the last-checked time so you can tell if they've rolled back their clock trying to get more usage.
Just make sure to distribute a web application, not a web project so you can distribute your code as a compiled bumary rather than having to ship the code-behind files. That will keep prying eyes out, but does make deployment more a pain since you always have to recompile with every change (as opposed to on-demand compiling.)
I would put in a time bomb. It's trivial to implement. Also, your client's won't think that you don't trust them. A fixed evaluation period in the application is extremely common.
Provide them a VMware image without any user-access just allow them to open the website externally via HTTP in their web browser.