I am working with C# & WPF and, of course, an app.config file. I have not been able to find an example of encrypted connection strings, stored in the app.config. There's plenty of examples for ASP.NET and web.config but nothing solid for app.config. The only examples I have come across clearly state that the string is only "decode-able" (is that even a word?) on the same machine that it was first encrypted on. Are there any viable options for working with encrypted connection strings (or other data) in an app.config?
Encrypt ConnectionStrings in App.config
private void ProtectSection(String sSectionName)
{
// Open the app.config file.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// Get the section in the file.
ConfigurationSection section = config.GetSection(sSectionName);
// If the section exists and the section is not readonly, then protect the section.
if (section != null)
{
if (!section.IsReadOnly())
{
// Protect the section.
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
section.SectionInformation.ForceSave = true;
// Save the change.
config.Save(ConfigurationSaveMode.Modified);
}
}
}
Related
I have a couple of tools that are initialized as a process by my .NET application. Some of them are from third parties. The list of tools to start is configurable. I want to protect the system against executing (maliciously) modified tools.
Assumption and possible attack vectors
I assume my application is protected by the operating system, including its configuration file. The folders containing the tools to be started are not though. Meaning an attacker could theoretically replace any of the tools with a different program bearing the same name.
Possible solution
My current concept would be to add SHA256 hashes of each tool to the config. This should prevent them from being replaced by manipulated applications, assuming my application and the configuration file containing the list is protected.
Implementation example
Config file example:
<FileHashes>
<Hashes>
<add Filename="the-tool.exe" Hash="87BC21C157F7B3E4..." />
</Hashes>
</FileHashes>
Application example:
public void Execute(FileInfo fileToLoad)
{
var hashDictionary = LoadHashDictionary(); //load hash from config
if (!hashDictionary.TryGetValue(fileToLoad.Name, out string configFileHash))
{
throw new Exception("Unknown file");
}
var fileHash = GetFileHash(fileToLoad);
if (!configFileHash.ToUpperInvariant().Equals(fileHash))
{
throw new Exception("File is manipulated");
}
Process.Start(new ProcessStartInfo()
{
FileName = fileToLoad.FullName
});
}
public string GetFileHash(FileInfo fileToLoad)
{
using (var fileStream = new FileStream(fileToLoad.FullName, FileMode.Open))
{
using (var shaHash = SHA256.Create())
{
fileStream.Position = 0;
byte[] hasValue = shaHash.ComputeHash(fileStream);
return BitConverter.ToString(hasValue)
.Replace("-", string.Empty)
.ToUpperInvariant();
}
}
}
Questions
Are there better ways to protect against manipulated files on application level?
Assuming the configuration file isn't safe, as it is also placed in a folder that can theoretically be accessed by an attacker. Where could I place the application whitelist and the hashes?
As you said. Confg file isn't safe either. Malicious application can modify your tools + config files all together to mask itself.
Whats an easy way to prevent this? Code signing.
Simply sign all your tools and do a certificate verification before you start your tool from main app.
I have a class library which by default doesn't have an app.config. The calling app for this library is "explorer.exe" and I won't be able to use explorer.exe.config to add my settings.
Is there any way I can have my class library read an app.config? It needs to be an app.config because I intend on encrypting it during deployment using aspnet_regiis (I'll rename it web.config, encrypt it and rename it back to app.config).
In C# the only config that matters really is the app.config of the output project. In the case of a console app this will be the .exe config. Which will appear in the bin as {your app name}.exe.config.
You can read this file using the ConfigurationManager in the System.Configuration DLL. All the uses of this will point to the executing code's configuration file, even in a class library. So any additional configuration needed in an imported class library will need to be added to this file. This is the canonical way of dealing with config.
If you really want to have some other configuration file, you can use:
ConfigurationManager.OpenMappedExeConfiguration(
new ExeConfigurationFileMap
{
ExeConfigFilename = overrideConfigFileName
},
ConfigurationUserLevel.None)
Where overrideConfigFileName points to your other app.config file. You can set the file in the class library as Content and ensure it is copied into the output directory at build time. Then you will have to ensure that it is included in the final deploy package and all the paths match.
In the end (as per #Stand__Sure and #tigerswithguitars I created a new project within my solution which will be a console App. It will be executed at deployment.
Thanks to Stand__Sure for his link to https://learn.microsoft.com/en-us/dotnet/standard/security/how-to-use-data-protection
The console app does the following:
private static void Run()
{
try
{
// Get unencrypted data from Settings.dat
string[] unencrypted = File.ReadAllLines("C:\\Program Files (x86)\\theAPPSettings\\Settings.dat");
string unencryptedGuid = unencrypted[0]; //its only 1 setting that I'm interested in
// Create a file.
FileStream fStream = new FileStream("C:\\Program Files (x86)\\theAPPSettings\\ProtectedSettings.dat", FileMode.OpenOrCreate);
byte[] toEncrypt = UnicodeEncoding.ASCII.GetBytes(unencryptedGuid);
byte[] entropy = UnicodeEncoding.ASCII.GetBytes("A Shared Phrase between the encryption and decryption");
// Encrypt a copy of the data to the stream.
int bytesWritten = Protection.EncryptDataToStream(toEncrypt, entropy, DataProtectionScope.CurrentUser, fStream);
fStream.Close();
File.Delete("C:\\Program Files (x86)\\theAPPSettings\\Settings.dat");
//Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine("ERROR: " + e.Message);
}
}
The calling app decrypts it as follows:
FileStream fStream = new FileStream("C:\\Program Files (x86)\\theAPPSettings\\ProtectedSettings.dat", FileMode.Open);
byte[] entropy = UnicodeEncoding.ASCII.GetBytes("A Shared Phrase between the encryption and decryption");
// Read from the stream and decrypt the data.
byte[] decryptData = Protection.DecryptDataFromStream(entropy, DataProtectionScope.CurrentUser, fStream, Length_of_Stream);
fStream.Close();
string temp = UnicodeEncoding.ASCII.GetString(decryptData);
After I setup a project, there are some .config files in bin folder. I want to make them non human-readable formats.
1. I know I can use command such as asp net_ reg i i s -p e ..., but the project is a Win Form Project, and in my config file there is no parts like Web.config. My config file formats is like below:
<...>
<add key="..." value="...." />
<add key="..." value="..." />
</...>
I also tried to encrypt the config files, however there are so many places that call the config files. It seems too complex to do so.
So, is there some easy way to make my config files in bin folder into non human-readable formats using C#?
You have two options.. If you are interested in protecting some special parameter, e.g. a password, you can just encrypt it, and only have the encrypted value. If you really want to make the whole thing protected, you can use SectionInformation.ProtectSection.
MSDN Sample code for that:
static public void ProtectSection()
{
// Get the current configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
// Get the section.
UrlsSection section =
(UrlsSection)config.GetSection("MyUrls");
// Protect (encrypt)the section.
section.SectionInformation.ProtectSection(
"RsaProtectedConfigurationProvider");
// Save the encrypted section.
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
// Display decrypted configuration
// section. Note, the system
// uses the Rsa provider to decrypt
// the section transparently.
string sectionXml =
section.SectionInformation.GetRawXml();
Console.WriteLine("Decrypted section:");
Console.WriteLine(sectionXml);
}
I am trying to read the app settings in the config file of another application (app.exe.config).
I have tried several things. Most recently I used this:
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(FullPath() + ".config");
// Get the AppSetins section.
AppSettingsSection appSettingSection = config.AppSettings;
// Display raw xml.
Debug.WriteLine(appSettingSection.SectionInformation.GetRawXml());
but the GetRawXml() returns nothing. Where am I going wrong? The FullPath() method returns the correct path, I have tested this.
M
Config files are valid xml files so you can also try using XElement.Load(filepath) and process the xml tree as desired.
var appSettingsRawXml = System.Xml.Linq.XElement.Load(FullPath() + ".config")
.Element("appSettings")
.ToString();
GetRawXml supports the .NET Framework infrastructure and is not intended to be used directly from your code. MSDN
I currently have a Windows service (running as LocalSystem) which I'm installing using InstallSheild LE. This service is meant to read some data from a local database file, package it up, and post it to an external server on a set interval. Rather that have the database location, server url, etc. hard coded I want to read them from a settings file. I can do that easily enough with App.config, but from my research I'm getting the picture that modifying the App.config (or any file in Program Files) is difficult/impossible post installation.
My question is what would be the best way to have an application which I can run to modify the necessary settings for the service without having to "Run as Administrator". Should I be putting these settings in the Registry. Is putting them in AppData the right answer and if so how are those settings shared between the settings changing application and the service?
I'm more of a web application developer and don't yet have much experience with desktop application/service development so any point in the right direction would be much appreciated.
You can locate the App.Config outside of the application install directory and place it in a common folder (like AppData). You'll then tell your application to load it from there instead of just pulling it in from the application install directory.
ConfigurationManager.OpenMappedExeConfig allows you to load your config from a custom location.
// Access a configuration file using mapping.
// This function uses the OpenMappedExeConfiguration
// method to access a new configuration file.
// It also gets the custom ConsoleSection and
// sets its ConsoleEment BackgroundColor and
// ForegroundColor properties to green and red
// respectively. Then it uses these properties to
// set the console colors.
public static void MapExeConfiguration()
{
// Get the application configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
Console.WriteLine(config.FilePath);
if (config == null)
{
Console.WriteLine(
"The configuration file does not exist.");
Console.WriteLine(
"Use OpenExeConfiguration to create the file.");
}
// Create a new configuration file by saving
// the application configuration to a new file.
string appName =
Environment.GetCommandLineArgs()[0];
string configFile = string.Concat(appName,
".2.config");
config.SaveAs(configFile, ConfigurationSaveMode.Full);
// Map the new configuration file.
ExeConfigurationFileMap configFileMap =
new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = configFile;
// Get the mapped configuration file
config =
ConfigurationManager.OpenMappedExeConfiguration(
configFileMap, ConfigurationUserLevel.None);
// Make changes to the new configuration file.
// This is to show that this file is the
// one that is used.
string sectionName = "consoleSection";
ConsoleSection customSection =
(ConsoleSection)config.GetSection(sectionName);
if (customSection == null)
{
customSection = new ConsoleSection();
config.Sections.Add(sectionName, customSection);
}
else
// Change the section configuration values.
customSection =
(ConsoleSection)config.GetSection(sectionName);
customSection.ConsoleElement.BackgroundColor =
ConsoleColor.Green;
customSection.ConsoleElement.ForegroundColor =
ConsoleColor.Red;
// Save the configuration file.
config.Save(ConfigurationSaveMode.Modified);
// Force a reload of the changed section. This
// makes the new values available for reading.
ConfigurationManager.RefreshSection(sectionName);
// Set console properties using the
// configuration values contained in the
// new configuration file.
Console.BackgroundColor =
customSection.ConsoleElement.BackgroundColor;
Console.ForegroundColor =
customSection.ConsoleElement.ForegroundColor;
Console.Clear();
Console.WriteLine();
Console.WriteLine("Using OpenMappedExeConfiguration.");
Console.WriteLine("Configuration file is: {0}",
config.FilePath);
}
Sample Source: MSDN