How to encrypt web.config connection string - asp.net

I am trying to encrypt connection string in my web.config. I have followed the guidelines by microsoft, but it doesn't work. http://msdn.microsoft.com/en-us/library/ff650304.aspx#paght000006_step3
After I got "encrypting configuration sections succeeded!" in command prompt. I deleted "connectionStrings" section from my web.config and kept the newly added "connectionStrings" with encrypted data.
I had two MSSQL database connection strings for Entity Framework, but I am getting an error on runtime compile saying "The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid."
When you open up the model edmx file, and update model from database. Visual Studio displays error saying "Failed to decrypt using provider RSAProtectedConfigurationProvider....The RSA key container could not be opened."
<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>Rsa Key</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>..........</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>........</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
-------- solved, answer below. ------

It looks like the account which created the key is different from the account running the app. Have you ensured the appropriate accounts have access to the key store? From that article you sent...
To grant access to the ASP.NET application identity
a.If you are not sure which identity to use, check the identity from a Web page by using the following code:
using System.Security.Principal;
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(WindowsIdentity.GetCurrent().Name);
}
By default, ASP.NET applications on Windows Server 2003 run using the NT Authority\Network Service account. Open a .NET command prompt, and use the following command to give this account access to the NetFrameworkConfigurationKey store:
aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT Authority\Network Service"
If the command runs successfully you will see the following output:
Adding ACL for access to the RSA Key container...
Succeeded!
You can check the ACL of the file in the following folder:
\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys
Your RSA key container file is the file in this folder with the most recent timestamp.
Also, these simple commands seemed to work for use of EF/Linq-to-Entities

When you run aspnet commands, the encrypted data should replace the "connectionStrings", if it doesn't, then it failed. aspnet_regiis -pe "connectionStrings" -app "/" -location "subfolder" -site "2"
I ran that command, but it turns out I don't need -location and that was incorrect.
I should have known, when the cipher Value XML field was so small.
However, these two commands do the trick...
aspnet_regiis -pe "connectionStrings" -app "/" -site "2"
aspnet_regiis -pa "NetFrameworkConfigurationKey" "IIS APPPOOL\MyApp"

Run This Code On Your Server that Publish your Project
string provider = "RSAProtectedConfigurationProvider";
string section = "connectionStrings";
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnEncrypt_Click(object sender, EventArgs e)
{
Configuration confg = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection configSect = confg.GetSection(section);
if (configSect != null)
{
configSect.SectionInformation.ProtectSection(provider);
confg.Save();
}
}
protected void btnDecrypt_Click(object sender, EventArgs e)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection configSect = config.GetSection(section);
if (configSect.SectionInformation.IsProtected)
{
configSect.SectionInformation.UnprotectSection();
config.Save();
}
}
in this link : http://www.codeproject.com/Tips/304638/Encrypt-or-Decrypt-Connection-Strings-in-web-confi
<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>Rsa Key</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>WagJ9DDjWTNc1nmYVNQXaQqXalQzXaiCHAOtUJvTWBRZiuT6UK1fBElM80PnL6dC5Umb8qvfHdkSMgoMW9CJzwOTZ0zTy17JBGZqRQmlfW2G9LacoWIil0UrxjhgmJmRXhwXHFpdGwEVl7AoQGVlJGabXuChutaTxmfGOoUbCr0=</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>qry5qnr3qxOgyoNPeP7OKEiHpr/PPTsaeQ2mYUsSK7cg4Kkl9uPO4RyUXgBIkgCTsjbObqLlyndcSBnYyek6bxG/IBL82G1R5J1ci8i1eyt8kIDqouzYOx5vtouErld4z1L+7WGf9Wg37QAH5RiiEfkCHndJJq3dTqjxnnXZSno6NgbxSXDfqzwE/eKDVhGV3oaTQSfjVmO8e5a9wvREYeeyasDhojx8J2mdy7/Q9rEIpv98RTiRxA==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>

Related

RSA decrypting a Web.config section

I'm trying to decrypt a Web.config section that was encrypted with RSA from an external Powershell script. The section goes:
<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>Rsa Key</KeyName>
</KeyInfo>
<CipherData>
<CipherValue>.......</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>.......</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
The code goes:
[xml]$x = Get-Content "$Path\Web.config"
$Prov = New-Object System.Configuration.RsaProtectedConfigurationProvider
$Prov.Decrypt($x.configuration.connectionStrings.EncryptedData)
It's executed via remote Powershell on the server where the config is. The account is an admin, so local machine keys should be available. And I'm getting an error:
Value cannot be null. Parameter name: keyName
An identical, modulo provider name, fragment works for DPAPI encrypted sections. The key name is right there in the section. What am I missing here?
Update: when the Web code does it, it calls Initialize() on the provider first. I've mimicked the parameters on that Initialize call. They come from machine. config.
$nv = New-Object System.Collections.Specialized.NameValueCollection
$nv.Add("description", "Uses RsaCryptoServiceProvider to encrypt and decrypt")
$nv.Add("keyContainerName", "NetFrameworkConfigurationKey")
$nv.Add("cspProviderName", "")
$nv.Add("useMachineContainer", "true")
$nv.Add("useOAEP", "false")
$Prov.Initialize("RsaProtectedConfigurationProvider", $nv)
Now I'm getting a different error: "Bad data".
Update 2: tried siccing aspnet_regiis on that file, got the same "Bad data" error. But the site itself seems up and running and database aware. Maybe the connectionString section is damaged after all, and the site takes it elsewhere.
I"m not sure about doing it via Powershell but here's what I do manually via code-behind on a web page. There might be a clue in here. I can delete this answer if it doesn't help.
protected void btnEncryptConnStrings_Click(object sender, EventArgs e)
{
// Open web.config file as a configuration object to get information.
Configuration objConfigFile = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
// Work with the <connectionStrings> section.
ConfigurationSection connectionStrings = objConfigFile.GetSection("connectionStrings");
if(connectionStrings != null)
{
// Only encrypt the section if it is not already protected.
if(!connectionStrings.SectionInformation.IsProtected)
{
// Encrypt the <connectionStrings> section using the
// DataProtectionConfigurationProvider provider (see notes at top of file).
connectionStrings.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider"); // alt: DataProtectionConfigurationProvider
objConfigFile.Save();
// other stuff.
}
}
}

Share ADFS/WIF federated claims cookie on multiple virtual applications (but the same domain)

I'm trying to (re)use ADFS 2/WIF claims based authentication cookies for multiple different applications running on the same domain.
So I have these applications/virtual directories that I would like to reuse the same authentication cookie:
https://domain.local/portal
https://domain.local/myapp
In the portal, I'd like to include (client side authenticated) content from myapp, so I don't want every app to be authenticated separately with a redirect to STS/ADFS.
I thought this would be pretty straightforward as they could both access the same cookie as they reside on the same domain, but the cookie is only valid for the application it was created in (FedAuth and FedAuth1 cookie paths are restricted to "/portal/")
When I set the 'path' in the cookieHandler settings to "/", I will get an exception:
[SecurityTokenException: ID4291: The security token 'System.IdentityModel.Tokens.SessionSecurityToken' is not scoped to the current endpoint.]
System.IdentityModel.Tokens.SessionSecurityTokenHandler.ValidateToken(SessionSecurityToken token, String endpointId) +1008632
System.IdentityModel.Services.SessionAuthenticationModule.ValidateSessionToken(SessionSecurityToken sessionSecurityToken) +351
System.IdentityModel.Services.SessionAuthenticationModule.SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken) +91
System.IdentityModel.Services.SessionAuthenticationModule.AuthenticateSessionSecurityToken(SessionSecurityToken sessionToken, Boolean writeCookie) +66
System.IdentityModel.Services.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +929
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +80
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +165
I've tried to use the Microsoft.Owin.Security.WsFederation beta packages mentioned in this article as an alternative, no success getting this running:
http://blogs.msdn.com/b/webdev/archive/2014/02/21/using-claims-in-your-web-app-is-easier-with-the-new-owin-security-components.aspx
Before I'm going to try to override methods in the SessionSecurityTokenHandler, is it even possible what I'm trying to achieve?
Thanks in advance!
Change cookieHandler as below in system.identityModel.services --> federationConfiguration
<federatedAuthentication>
<cookieHandler requireSsl="true" path="/" />
</federatedAuthentication>
It was actually pretty simple to do it, by replacing MachineKeySessionSecurityTokenHandler with a custom implementation that get's rid of the token validation:
public class SharedSecurityTokenHandler : MachineKeySessionSecurityTokenHandler
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SessionSecurityToken token, string endpointId)
{
if (token == null) throw new ArgumentNullException("token");
if (endpointId == null) throw new ArgumentNullException("endpointId");
return ValidateToken(token);
}
}
the just registering it here in the web.config:
<system.identityModel>
<identityConfiguration>
<securityTokenHandlers>
<add type="Security.Web.SharedSecurityTokenHandler, Security.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>
I've been trying to achieve the same thing and found that SessionAuthenticationModule.ValidateSessionToken(SessionSecurityToken sessionSecurityToken) calls:
securityTokenHandler.ValidateToken(sessionSecurityToken, this.CookieHandler.Path)
..where the second argument is endpointId. Therefore, configuring both my apps with:
<system.identityModel.services>
<federationConfiguration>
<cookieHandler domain="example.com" path="/" />
...
</federationConfiguration>
</system.identityModel.services>
..allowed the validation in MachineKeySessionSecurityTokenHandler to pass.

Encrypting only Passwords in web.config ASP.NET

How can I encrypt only passwords in a web.config file?
<add name="PSystem" connectionString="Server=test;Database=Dev;User ID=testuser;Password=password#123;Trusted_Connection=False;Encrypt=True;" providerName="System.Data.SqlClient" />
I believe that built-in encryption mechanisms work on the entire connectionString section:
See this website for more info
If you would like to encrypt in-memory passwords, maybe entered by the user through a login form, you could use SecureString
you can try using flags in the connecction string as follows:
<add name="PSystem"
connectionString="Server=test;
Database=Dev;
User ID=#UserID#;
Password=#Password#;
Trusted_Connection=False;
Encrypt=True;"
providerName="System.Data.SqlClient" />
then you can have the encrypted user and password as follows:
<add key="DB_User" value = [Encrypted Username]>
<add key="DB_Password" value = [Encrypted Password]>
Then in code you just replace the flags:
string _connectionString = ConfigurationManager.ConnectionStrings["PSystem"].ConnectionString;
string user = Decrypt(ConfigurationManager.AppSettings["DB_User"]);
string password = Decrypt(ConfigurationManager.AppSettings["DB_Password"]);
_connectionString = _connectionString.Replace("##User##", user).Replace("##Password##", password);
To encrypt configuration file
contents, use the Aspnet_regiis.exe tool with the –pe option and the
name of the configuration element to be encrypted.
aspnet_regiis -pe "connectionStrings" -app "/SampleApplication" -prov
"RsaProtectedConfigurationProvider"
Source: http://msdn.microsoft.com/en-us/library/zhhddkxy(v=vs.100).aspx

Editing a web.config file through web application will cause any security problem?

We developed an application to edit the web.config settings. The user has to locate the web.config file which they like to edit. Once their task is completed they can download the web.config file with the changes made by them. Since the web.config file has the database server information and passwords I have a concern that will it cause any security problem.
If so how can I rectify it?
Better encrypt your Connection string....
For ref MSDN article
You can use the following method to secure the the webconfig.
if there exist the following code at web.config.
<connectionStrings>
<add name="yjsDBConnectionString" connectionString="Data Source=HUAJLI-XP\SUN;Initial Catalog=yjsDB;Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
Then we can use the following code to protect it.
protected void Encryption()
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.ConnectionStrings;
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
}
}
And you can use the following code to Decrypting it.
protected void Decrypting()
{
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.ConnectionStrings;
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
}
}

log4net with ASP.NET 3.5 problems

I'm having some trouble getting log4net to work from ASP.NET 3.5. This is the first time I've tried to use log4net, I feel like I'm missing a piece of the puzzle.
My project references the log4net assembly, and as far as I can tell, it is being deployed successfully on my server.
My web.config contains the following:
<configSections>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler
, log4net"
requirePermission="false"/>
</configSections>
<log4net>
<appender name="InfoAppender" type="log4net.Appender.FileAppender">
<file value="..\..\logs\\InfoLog.html" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern
value="%d [%t] %-5p %c [%x] - %m%n" />
</layout>
</appender>
<logger name="_Default">
<level value="INFO" />
<appender-ref ref="InfoAppender" />
</logger>
</log4net>
I'm using the following code to test the logger:
using log4net;
using log4net.Config;
public partial class _Default : System.Web.UI.Page
{
private static readonly ILog log = LogManager.GetLogger("_Default");
protected void Page_Load(object sender, EventArgs e)
{
log.Info("Hello logging world!");
}
}
In my Global.asax, I'm doing the following:
void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.Configure();
}
At this point, I can't think of what else I might be doing wrong. The directory I'm trying to store the log in is writable, and even if I try different directories I get the same result: no file, no logs.
Any suggestions? :-)
Edit: I've tried several different formats for the path & name of the log file, some of which include "..\..\InfoLog.html", "InfoLog.html", "logs\InfoLog.html", etc, just in case someone is wondering if that's the problem.
Edit: I've added the root logger node back into the log4net section, I ommitted that on accident when copying from the samples. The root logger node looks like this:
<root>
<level value="INFO" />
<appender-ref ref="InfoAppender" />
</root>
Even with it, however, I'm still having no luck.
The root logger is mandatory I think. I suspect configuration is failing because the root doesn't exist.
Another potential problem is that Configure isn't being pointed to the Web.config.
Try Configure(Server.MapPath("~/web.config")) instead.
It sounds very much like a file permissions issue to me. If you specify a file name without any path, log4net will write to the root directory of the web application. Try that. Barring any success there, I'd recommend you enable internal log4net debugging by putting the following in your web.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="log4net.Internal.Debug" value="true"/>
</appSettings>
</configuration>
Then, deploy the app compiled in debug mode and run the visual studio remote debugger to see any errors that are thrown.
Iv just spent 3 hours trying to fix this problem is the end it was the web.config formatting.
I had this, and it didn't work:
<section name="SubSonicService" type="SubSonic.SubSonicSection, SubSonic" requirePermission="false"/>
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler
, log4net"
requirePermission="false"/>
changing it to this fixed it:
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" requirePermission="false"/>
Annoying!!
Just for info: the file path must be formatted as follows:
<file value="..\\..\\logs\\InfoLog.html" />
A simple configuration tutorial from CodeProject
I don't have the Global.asx to run in .net 3.5
this is my code... I configure the log4net in a separate file log4net.config
// Configure log4net using the .config file
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
//My Web Services class name
private static readonly log4net.ILog log = log4net.LogManager.GetLogger("Service1");
i had the same (frustrating) problem. i moved the root to the top of the log4net config section and it all worked. Also, i too had root and a logger element, this resulted in two lines each time i made a call to the logger. i removed the logger element and simply keep the root and its working great.
How about creating the logger with the page's type, like this:
private static readonly ILog log = LogManager.GetLogger(typeof(_Default));
This is what i have in Global.ASX. Got it all working in asp.net 3.5
<%# Application Language="C#" %>
<script runat="server">
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
log4net.Config.XmlConfigurator.Configure();
}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown
log4net.LogManager.Shutdown();
}
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
}
void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started
}
void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
}
</script>

Resources