Securely Storing Database Password - c#

I'd like to randomly generate an encryption key and password for an SQL Server CE database when it's created, and then save the key in some secure way that would allow the program to open a connection, but not be easily reachable by potential attackers.
I'm working on an offline WPF application that stores certain user and setting information in a local database.
My current implementation is to have one "Device Password" that the user sets up which is used as the encryption key for the generated SQL Server CE database password. The base64 encrypted database password is then saved in a simple .txt settings file. When the application starts up, the user enters the Device Password and that string is used as the decryption key for the saved password. If the resulting string is able to open a connection to the database, the password was correct and the program is opened with full access.
What I'm trying to do now is modify the system to allow multiple users with specific Username/Password credentials to open the program and access the database with varying levels of privilege. The way that I'm trying to achieve this is by handling the user authentication separately, and opening the database regardless of the credentials to load some basic application info.
Below is roughly my current implementation:
var candidateDBPwd = DecryptDatabasePassword(passwordBox.Password, Settings.Instance.EncryptedDatabasePassword);
if (candidateDBPwd.IsNullOrEmpty())
{
// User's password didn't decrypt database password.
return false;
}
if (File.Exists(Constants.DB_FILE))
{
// Normal operation: Try to open the database file to see that
// we've got the correct password.
string databaseArguments = Constants.DB_ARGS_SECURE + candidateDBPwd;
using (var conn = new SqlCeConnection(databaseArguments))
{
try
{
conn.Open();
}
catch (System.Data.SqlServerCe.SqlCeException ex)
{
// Failed to open the database: User's password must have been wrong!
return false;
}
}
I've spent the past few hours researching similar issues and am now beginning to wonder if it's possible. Consensus seems to state that storing passwords or connectionStrings in the App.config file is futile because if you encrypt the sections, you still need to store that key somewhere in code. Most of the existing SO threads on the issue seem to be several years out of date and it seems that that practice has deprecated. Is there some new respectable way to store a local database password? Or would you recommend a different approach to implementing the feature?

For you information here is the code snippet that can be used to encrypt certain sections of app.config. This is machine specific encryption and I think it is most simple and straightforward way to go.
I am using this with Click-once app, so that the config sections are encrypted during the first launch of the app. It means, that it is unecrypted on the publish server, it is downloaded also unencrypted and it is encrypted right after the installation finishes and application is started.
So using this method you have to distribute your files unencrypted and they are enrypted only after the installation is completed. I suppose it can be achieved by running this code during install, it depends on how you plan to install your app.
Also you can use UnprotectSection() to unencrypt previously encrypted section.
static void EncryptConfig()
{
// Encrypt config for ClickOnce deploys on first run
// ClickOnce deploys config into 2 dirs, so the parent dir is traversed to encrypt all
if (ApplicationDeployment.IsNetworkDeployed)
{
// Get paths
Assembly asm = Assembly.GetExecutingAssembly();
string exeName = Path.GetFileName(asm.Location);
string configName = exeName + ".config";
DirectoryInfo parentPath = Directory.GetParent(Directory.GetCurrentDirectory());
// Protect config files
foreach (DirectoryInfo dir in parentPath.GetDirectories())
{
foreach (FileInfo fil in dir.GetFiles())
{
if (fil.Name == configName)
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = fil.FullName;
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
ProtectSection(config, "connectionStrings");
config.Save(ConfigurationSaveMode.Modified);
}
}
}
}
}
private static void ProtectSection(Configuration config, string sectionName)
{
ConfigurationSection section = config.GetSection(sectionName);
if (section != null)
{
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
}
section.SectionInformation.ForceSave = true;
}
else
Tools.LogWarning("Section {1} not found in {0}.",config.FilePath, sectionName);
}

You can store it in registry editor. You mention that your system is offline wpf application .

Related

Declaring per-user (roaming user) configuration settings for a plugin DLL?

How can I setup support for per (roaming) user configuration settings for a particular plugin .DLL loaded from another application?
I have a .DLL that is loaded as add-in/plugin from another application, and want to persist configuration settings particular for this one independently of the main application that loads it, based on machine, .dll (=executable), roaming user or user profile.
I have found the System.Configuration.ExeConfigurationFileMap class that looks likely to provide what I need, but I can't figure out how to setup the right paths specific for my (plugin) application.
What code I have so far is:
public class MyConfigurationSettings : ConfigurationSection
{
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
string configFile = Assembly.GetAssembly(typeof(MyConfigurationSettings)).Location + ".config";
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = configFile;
configFileMap.LocalUserConfigFilename = <localUserConfigFile>; // ??? What filename to place here and how to get it based on the current environment ???
configFileMap.RoamingUserConfigFilename = <roamingUserConfigFile>; // ???;
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigLevel);
// ...
}
}
Can anyone point me into the right direction? The available documentation and search results are too confusing or insufficient for me to get this right. Sorry , if this seems to be a silly question, but my C# (.NET) skills are going to get rusty after 4+ years not using it for earning daily bread.
I also believe it's not primarily an issue about configuration settings management, but how to get paths for installation specific application instance configurations.
You set RoamingUserConfigFilename = RoamingName.config and put it under Roaming Profile:
%AppData%\[AppName]\[Vendor]\[CodedPath]\[Version]\RoamingName.config
Also you set LocalUserConfigFilename = LocalName.config and put it under Local Profile:
%LocalAppData%\[AppName]\[Vendor]\[CodedPath]\[Version]\LocalName.config
Now calling
ConfigurationManager.OpenMappedExeConfiguration(
exeMap,
ConfigurationUserLevel.PerUserRoamingAndLocal);
config will be read in the following order:
Source on MSDN blogs.
For samples search for User.config under c:\Users\[User]\AppData. Also see CP article.
Code Sample:
public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel)
{
try
{
string appDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string localDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
System.Configuration.ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap();
exeMap.ExeConfigFilename = System.IO.Path.Combine(appDataPath, #"MyCompany\MyPlugin\Default.config");
exeMap.RoamingUserConfigFilename = System.IO.Path.Combine(appDataPath, #"MyCompany\MyPlugin\Roaming.config");
exeMap.LocalUserConfigFilename = System.IO.Path.Combine(localDataPath, #"MyCompany\MyPlugin\Local.config");
System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,ConfigLevel);
return (MyConfigurationSettings)Config.GetSection("MyConfigurationSettings");
}
catch (Exception ex) {
// ...
}
return null; // or throw an appropriate exception
}
Generally load the configuration from the special folder where you put it in and put it into one of the roaming (i.e. non local) locations. The OS handles the rest as per roaming specifications.
The usage of ConfigSections is totally irrelevant unless there is a very very special need to use the config file for that. In any .NET project I have seen in the last 10 years this file was never used for user specific settings.

DataDirectory Set up project

I am doing a SETUP project for a C# winforms, sqlite application.
Connection string seems to a bit of a problem. The user will put the Database he wants to work with at a location(which v will tell him). In this example it is "C:\\Program Files(x86)\\DefaultCompany\\RSetup"; The user can work his own copy of the DB.
So I am setting the data directory to this path in the Program.cs Main
This is the only way I can think of. If there is a better way thats grt!!.
App.config
<add name="ConnString" connectionString="|DataDirectory|\MySQlite.db;Compress=True;Version=3"
providerName="System.Data.Sqlite" />
Program.cs
Setting the datadirectory to the path of the executable. Currently hard coded the path of the executable
static void Main()
{
AppDomain.CurrentDomain.SetData("DataDirectory","C:\\Program Files(x86)\\DefaultCompany\\RSetup");
This doesn't seem to be working. It doesn't give any error except the data is not blank. Doesn't seem to be working in both set up and the regular project
Thank you
JC
You could ask the user where the database is located, store that path somewhere (such as User Settings) and then you can retrieve it at any time. This would give the user more flexibility of where to put it and multiple users on the same machine could have their own database if desired.
Here is some pseudocode...
string dbLocation = Properties.Settings.Default.DatabaseLocation;
if (string.IsNullOrWhiteSpace(dbLocation)
{
dbLocation = AskUserForLocation();
Properties.Settings.Default.DatabaseLocation = dbLocation;
Properties.Settings.Default.Save();
}
AppDomain.CurrentDomain.SetData("DataDirectory",dbLocation);
Using this approach you could also add a menu option to allow the user to change the location if desired.
It also gives you the ability to retrieve the value anywhere, including where you create a connection, you can append the path to the location between where you read the connection string and you create a new connection.
SQLiteConnection myConnection = new SQLiteConnection;();
myConnection.ConnectionString = Path.Combine(Properties.Settings.Default.DatabaseLocation, myConnectionString);
myConnection.Open();

Hiding Important Data

just want to ask what would be the best way to hide sensitive data (ftp accounts, database connectionstring, etc) in .Net desktop applications.. any suggestions please.. :)
i was aware of putting data in the application and got in mind that what if the application will be deobfuscated or decompiled the hidden data will be expose.
i tried using Application Settings
Properties.Settings.Default.MyConnectionString = theConString;
but still the data can be seend when decompiled.
any suggestions please.
You can encrypt all or part of the app.config file. This is particularly common for protecting database connection strings.
Here is a detailed article about how to to this. In a nutshell, here is the code from there for encrypting the connection string section in app.config:
static void ToggleConfigEncryption(string exeConfigName)
{
// Takes the executable file name without the
// .config extension.
try
{
// Open the configuration file and retrieve
// the connectionStrings section.
Configuration config = ConfigurationManager.
OpenExeConfiguration(exeConfigName);
ConnectionStringsSection section =
config.GetSection("connectionStrings")
as ConnectionStringsSection;
if (section.SectionInformation.IsProtected)
{
// Remove encryption.
section.SectionInformation.UnprotectSection();
}
else
{
// Encrypt the section.
section.SectionInformation.ProtectSection(
"DataProtectionConfigurationProvider");
}
// Save the current configuration.
config.Save();
Console.WriteLine("Protected={0}",
section.SectionInformation.IsProtected);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Directory.CreateDirectory access to path is denied?

I have server-client application, it's a file manager
my problem is when I go inside a folder which requires access control like system folders, it becomes to read-only, but I need to move/delete or create new folder, how can I get the permission to do that?
here's how I create a new folder at the server side
public void NewFolder(string path)
{
try
{
string name = #"\New Folder";
string current = name;
int i = 0;
while (Directory.Exists(path + current))
{
i++;
current = String.Format("{0} {1}", name, i);
}
Directory.CreateDirectory(path + current);
Explore(path); //this line is to refresh the items in the client side after creating the new folder
}
catch (Exception e)
{
sendInfo(e.Message, "error");
}
}
There are often directories on a drive that even a user with administrator privileges cannot access. A directory with a name like "HDDRecovery" is quite likely to be troublesome like this. Surely it contains sensitive data that helps the user recover from disk failure. Another directory that fits this category is "c:\system volume information", it contains restore point data.
An admin can change the permissions on folders like this. But of course that doesn't solve the real problem nor is it a wise thing to do. Your user can't and shouldn't. Be sure to write code that deals with permission problems like this, simply catch the IOExeption. Keep the user out of trouble by never showing a directory that has the Hidden or System attribute set. They are the "don't mess with me" attributes.
If you want to remove directory read-only attribute use this: http://social.msdn.microsoft.com/Forums/en/vblanguage/thread/cb75ea00-f9c1-41e5-ac8e-296c302827a4
If you want to access system folders you can run your program as local administrator.
I had a similar problem (asp.net MVC vs2017) with this code:
Directory.CreateDirectory("~/temp");
Here is my solution:
// Create path on your web server
System.IO.Directory.CreateDirectory(System.Web.HttpContext.Current.Server.MapPath("~/temp"));
I also ran into an issue similar to this, but I was able to manually navigate through Windows Explorer and create directories.
However, my web app, running in VS on my laptop, hosted through my local IIS and not the built-in IIS deal for VS, was triggering the Access Denied issue.
So when I was hitting the error in code, I drilled down to glean more data from the System.Environment object and found the user, which of course was the App Pool that my app was running under in IIS.
So I opened IIS and opened the Advanced Settings for the app pool in question and changed the Identity to run under Network Service. Click OK. "cmd -> iisreset" for good measure. Try the app again, and SUCCESS!!!!
I had the same issue when creating a directory. I used DirectorySecurity as shown below:
DirectorySecurity securityRules = new DirectorySecurity();
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\AdminAccount1", FileSystemRights.Read, AccessControlType.Allow));
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\YourAppAllowedGroup", FileSystemRights.FullControl, AccessControlType.Allow));
DirectoryInfo di = Directory.CreateDirectory(path + current, securityRules);
Also keep in mind about the security as explained by Hans Passant's answer.
Full details can be found on MSDN.
So the complete code:
public void NewFolder(string path)
{
try
{
string name = #"\New Folder";
string current = name;
int i = 0;
while (Directory.Exists(path + current))
{
i++;
current = String.Format("{0} {1}", name, i);
}
//Directory.CreateDirectory(path + current);
DirectorySecurity securityRules = new DirectorySecurity();
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\AdminAccount1", FileSystemRights.Read, AccessControlType.Allow));
securityRules.AddAccessRule(new FileSystemAccessRule(#"Domain\YourAppAllowedGroup", FileSystemRights.FullControl, AccessControlType.Allow));
DirectoryInfo di = Directory.CreateDirectory(path + current, securityRules);
Explore(path); //this line is to refresh the items in the client side after creating the new folder
}
catch (Exception e)
{
sendInfo(e.Message, "error");
}
}
My suspicion is that when you are running the application in client/server mode, the server portion needs to be running as Administrator, in addition to possibly removing read-only or system flags, to be able to do what you want.
That said, I agree with #HansPassant- it sounds like what you are trying to do is ill-advised.
Solved:
Directory created on remote server using below code & setting.
Share folder and give the full permission rights also in Advance
setting in the folder.
DirectoryInfo di = Directory.CreateDirectory(#"\\191.168.01.01\Test\Test1");
Test is destination folder where to create new Test1 folder(directory)

How to Delete a file using asp.net?

i write the code in asp.net using c# to delete the file in my computer, but it is not deleting please help me thank u. this is my code, i write in button click event
string path = "E:\\sasi\\delt.doc";
FileInfo myfileinf = new FileInfo(path);
myfileinf.Delete();
public void DeleteFileFromFolder(string StrFilename)
{
string strPhysicalFolder = Server.MapPath("..\\");
string strFileFullPath = strPhysicalFolder + StrFilename;
if (IO.File.Exists(strFileFullPath)) {
IO.File.Delete(strFileFullPath);
}
}
In order to delete a file you must ensure that the account has sufficient permissions. In general ASP.NET applications run under limited permission account such as Network Service. For example if your application runs under IIS 6 you could go to the Administration Console and set a custom account in the application pool properties:
alt text http://i.msdn.microsoft.com/Bb969101.SharePoint_SQL_TshootingFig3%28en-US,SQL.90%29.jpg
You need to ensure that the account is member of the IIS_WPG group.
Make sure the ASP user has permissions to this folder. By default this user is not given access to much of the harddrive..

Categories