|
Hi,
While this implementation works well during runtime, the sensitive information in the config file isn't encrypted until the ProtectSection method is called. Even if the ProtectSection was called in the Main() method of the app, the info is still exposed until the app is run for the first time.
An improvement to this solution is to place the call to the encryption mechanism in a custom Installer class and then call the custom installer from a Setup project, etc.
Dave Black
Black Box Solutions, Inc.
|
|
|
|
|
Hi Dave,
Yes, I know this is a problem. Using a custom installer to solve it is a great idea. Thanks.
Regards,
Ton de Ron
InfoSupport
|
|
|
|
|
Dave:
Do you have an example of how to do this?
Thanks,
Kevin
|
|
|
|
|
|
Thank you very much for this link
|
|
|
|
|
Hi,
Thank you for the helpful article, I'm however having trouble encrypting a WSE 3.0 wse3PolicyCache.config configuration file. I need to secure the user name and password in this file.
The problem is the code below returns null for the config.GetSection(sectionName) if I pass in either "policy" or "policies" as the section name.
string sectionName = "policy";
Configuration config = ConfigurationManager.OpenExeConfiguration(configPath);
ConfigurationSection protectedSection = config.GetSection(sectionName);
Here is the configuration file:
<policies xmlns="http://schemas.microsoft.com/wse/2005/06/policy">
<extensions>
<extension name="usernameOverTransportSecurity" type="Microsoft.Web.Services3.Design.UsernameOverTransportAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="username" type="Microsoft.Web.Services3.Design.UsernameTokenProvider, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<extension name="requireActionHeader" type="Microsoft.Web.Services3.Design.RequireActionHeaderAssertion, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</extensions>
<policy name="ClientSecurityPolicy">
<usernameOverTransportSecurity>
<clientToken>
<username username="DOMAIN\AllowedUser" password="password" />
</clientToken>
</usernameOverTransportSecurity>
<requireActionHeader />
</policy>
</policies>
Any advice will be greatly appreciated!
Thanks
Henk
|
|
|
|
|
Hi Henk,
Sorry for my late reaction but I was on holiday. Take a look at http://www.codeproject.com/soap/WSE30UsernameAssertion.asp. I think this is what you want to do. I did not read the entire article but it seems to be about your problem. Maybe it is helpful.
Anyway the configuration namespace defines config files as being xml files with the root element <configuration>. This policy file does not conform to this standard. So no configuration section are defined in the file and that why null is returned.
Hope this helped you.
Regards,
Tron
|
|
|
|
|
You can trick the aspnet_regiis.exe tool to encrypt sections in your app.config file. You just rename your app.config to web.config, call aspnet_regiis.exe, then rename web.config back to the original filename. Encrypting the file from within .NET code can be useful, but this will work too - try it!
Run these commands from a command prompt in the app's directory to encrypt the "connectionStrings" section:
move myapp.exe.config web.config
aspnet_regiis -pef connectionStrings .
move web.config myapp.exe.config
|
|
|
|
|
Hi
I run your scirpt, but it failed to encrypt.
When I run the aspnet_regiis command, I run it in the "C:\Windows\Microsoft.Net\Framework\v2.0.50727" like that: Aspnet_regiis -pef "appSettings" "C:\Newfolders\web.config"
I got this error:
Aspnet_regiis -pef "appSettings" C:\Newfolders\web.config
The configuration for the physical path C:\Newfolders\web.config cannot be opened
I have an admin right on my local computer.
Any idea what I did wrong?
Thanks.
|
|
|
|
|
The last parameter should be the path to the directory containing web.config, not the path to web.config itself. So try: aspnet_regiis -pef appSettings C:\Newfolders
|
|
|
|
|
Your quick way is simple and effective. It also works well with Microsoft Entreprise library (DAAB). I like that!
|
|
|
|
|
Even i am trying this. I was able to encrypt the app.config, by following the steps mentioned above. However when tried to run my application, which is a windows service, it gave me error
"Failed to decrypt using provider 'RsaProtectedConfigurationProvider'. Error message from the provider: The RSA key container could not be opened".
The detailed error is as follows:
System.Configuration.ConfigurationErrorsException was unhandled by user code
Message="Failed to decrypt using provider 'RsaProtectedConfigurationProvider'. Error message from the provider: The RSA key container could not be opened. (D:\\ContentIngestionTools\\RSSIngestorWS\\bin\\Debug\\NDNrssIngestor.exe.Config line 16)"
Source="System.Configuration"
BareMessage="Failed to decrypt using provider 'RsaProtectedConfigurationProvider'. Error message from the provider: The RSA key container could not be opened."
Filename="D:\\ContentIngestionTools\\RSSIngestorWS\\bin\\Debug\\NDNrssIngestor.exe.Config"
Line=16
StackTrace:
at System.Configuration.BaseConfigurationRecord.EvaluateOne(String[] keys, SectionInput input, Boolean isTrusted, FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult)
at System.Configuration.BaseConfigurationRecord.Evaluate(FactoryRecord factoryRecord, SectionRecord sectionRecord, Object parentResult, Boolean getLkg, Boolean getRuntimeObject, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
at System.Configuration.BaseConfigurationRecord.GetSection(String configKey, Boolean getLkg, Boolean checkPermission)
at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at System.Configuration.ConfigurationManager.get_AppSettings()
at System.Configuration.ConfigurationSettings.get_AppSettings()
at RSSIngestorWS.RSSService.OnStart(String[] args) in D:\ContentIngestionTools\RSSIngestorWS\RSSService.cs:line 49
at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)
InnerException: System.Configuration.ConfigurationErrorsException
Message="The RSA key container could not be opened."
Source="System.Configuration"
BareMessage="The RSA key container could not be opened."
Line=0
StackTrace:
at System.Configuration.RsaProtectedConfigurationProvider.ThrowBetterException(Boolean keyMustExist)
at System.Configuration.RsaProtectedConfigurationProvider.GetCryptoServiceProvider(Boolean exportable, Boolean keyMustExist)
at System.Configuration.RsaProtectedConfigurationProvider.Decrypt(XmlNode encryptedNode)
at System.Configuration.ProtectedConfigurationSection.DecryptSection(String encryptedXml, ProtectedConfigurationProvider provider)
at System.Configuration.Internal.InternalConfigHost.System.Configuration.Internal.IInternalConfigHost.DecryptSection(String encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
at System.Configuration.Internal.DelegatingConfigHost.DecryptSection(String encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfigSection)
at System.Configuration.BaseConfigurationRecord.CallHostDecryptSection(String encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfig)
at System.Configuration.RuntimeConfigurationRecord.CallHostDecryptSection(String encryptedXml, ProtectedConfigurationProvider protectionProvider, ProtectedConfigurationSection protectedConfig)
at System.Configuration.BaseConfigurationRecord.DecryptConfigSection(ConfigXmlReader reader, ProtectedConfigurationProvider protectionProvider)
InnerException:
|
|
|
|
|
Probably your service doesn't have the rights to access key container. Check under which identity your service runs (probably "LocalService") and give that identity access to machine key container:
aspnet_regiis -pa "NetFrameworkConfigurationKey" "<identity name>"
More details about this on MSDN:
http://msdn.microsoft.com/en-us/library/yxw286t2.aspx[^]
|
|
|
|
|
Very nice, I like this. I can encrypt the conn string section before deploying it with this method. I was unsure as well how an application would handle/be able to encrypt it on the first use, when the app was deployed as a click once with only online execution being set (what I'm doing). And, the ability to never have the sensitive connection info exist in plain text in the situation where I'm not using an installer, is very desirable.
I found one thing to pay attention to though, else the connection string is viewable to someone who looks in the right place. After trying this method, I looked at every deployed file and found the conn string in <your apps="" name="">.exe.deploy
It was at the end near references to the settings file it seemed, at least for the readable information that was present.
So, I looked at my connection string (a setting of my application like many may do). For that setting, there is a property 'GenerateDefaultSettingInCode' that was set to true. I changed it to false and re-deployed and the conn string info was gone!
So, the steps are:
-Create your app, storing potential sensitive info in a setting, such as the connection string.
-Make sure the 'GenerateDefaultSettingInCode' property is set to false for the setting you wish to protect.
-Do the steps you've outlined.
-Deploy the application (I'm using click once, deploying to a network location, where the app is only available online).
Oh, I'm using VS2008 and a 3.5 based app, in case others don't have the experience I've noted.
|
|
|
|
|
When I try to encrypt the connection string in with the following command it does not work:
'...MyApplication_Startup - right after the protection call for "Vault"...
vaultProtector = Nothing
vaultProtector = New ConfigSectionProtector("connectionStrings")
vaultProtector.ProtectSection()
because in the ProtectSection method the "protectedSection.SectionInformation.IsDeclared" returns False. I have never used the app.config file to store settings because I have never needed to, or because it is not encrypted (specifically, connection strings). Because of this I don't know much about how to use or configure it. Is the "IsDeclared" check necessary? If so, then how do we declare "connectionString". Thanks in advance! If I can encrypt connection strings then this will be really useful. Good work and thanks for sharing.
Mike
|
|
|
|
|
Hi Mike,
The SectionInformation.ProtectSection method throws an exception if the section to be protected does not exist. You can look at this method with Reflector. So the IsDeclared checked is necessary if one wants to prevent unnecessary exceptions. In other words you have to declare the connectionStrings section before encrypting it.
By the way you do not have to define the connectionStrings section manually if you do not want to. Open the properties of your project and goto the settings tab. On this tab you can define application wide or user wide settings that are accessible via the My namespace. To define a connectionstring enter a name in the name column and select '(Connection string)' in the type column. Tab out of the type column. The scope column will default to 'Application'. Left it that way. Now you can click the '...' button and a connectionstring wizard appears. The connectionStrings section is created automatically. To encrypt this section call the following code in the startup event of your application:
' Connection string encryption
Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
config.ConnectionStrings.SectionInformation.ProtectSection(Nothing)
Make sure you call it before deploying. Winforms does not support automatic encryption of the connectionString section like ASP.Net 2.0 does.
I hope this answers your question. Feel free to contact me again if you have other questions.
Tron
|
|
|
|
|
Sorry, but I can't get it to encrypt the connection string. I'm just using your demo I downloaded. I see the commands you define in your response above and in your article, and I see the connection string in the config file. I run a Clean Solution command to clear out previously built files out of the Debug folder, check that they're actually gone, run the program, close the form, and then open the \Debug\EncryptConnStringsSection.exe.config -- the connection string isn't encrypted but the Vault section is. Can you get your sample app to encrypt the connection string? Sorry for the hassle!
Mike
|
|
|
|
|
Yesterday I was doing research on how to encrypt my data used for my application. I just finished everything for my app.
Nicely done.
Michael
If we knew what it was we were doing, it would not be called research, would it? --Albert Einstein
|
|
|
|
|