Invalid encryption key after website published - asp.net

So i managed to encrypt my connectionstrings on my localhost, and everything was fine.. it could read without any problems.
Now after i have published my project on my webhote, the story is quite different.
I get following error:
Key not valid for use in specified state. (Exception from HRESULT: 0x8009000B)
Im wondering if i should decrypt it locally and thereafter encrypt it after it has been published to my webhotel? i have seen another thread where people suggest, that a machinekey should be added. but where would i place it, and where would i find it?
the whole stacktrace can be seen here
I used the following cmd to encrypt:
aspnet_regiis -pef "connectionStrings" "PATH" -prov "DataProtectionConfigurationProvider"

So i figured that the following error is yielded when the machinekey doesnt correspond with the key that has been used to encrypt the string in the first place (my localhost).
Therefore i had to make the following method:
private void ProtectSection(string sectionName, string provider)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~/");
ConfigurationSection section = config.GetSection(sectionName);
if (section != null && !section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection(provider);
config.Save();
}
}
And call it in my global.asax file..
By doing so, i first uploaded my web.config unprotected and then asked my web hotel encrypt my connection string when the website was run the first time. Obviously it therefore used it's own machinekey, and nothing therefore conflicted.

Related

is machine required for a web application with single page

I have created a web forms .net application which has jut got one page with four input fields.
I am storing the input parameters in the view state to be available between post backs.
This application is now deployed onto live server which is actually load balanced between two servers.
When I load the page, it works fine. But this application is going to be used by
10,000 users.
There is no machine key on the web.config file for this application. I read in a documentation when a application
is loaded on a web farm(when load balanced between two servers), a machine key is required to preserve
view state information.
So I tried to generated a machine key on my local host with the following settings
Encryption method: SHA1
Decryption method: auto
Validation key:
Automatically generate at runtime (unchecked)
Generate a unique key for each application (unchecked)
Decryption key:
Automatically generate at runtime (unchecked)
Generate a unique key for each application (unchecked)
I used the generated keys on the web.config of live server, but the application fails to load trying to load the login
page which is not my start page.
So my questions are:
1) Do I really need a machine key as the application is loading without it?
2) When thousands of users use the application page at the same time, is it alright without machine key?
3) If machine key is required, how is it generated and what encryption method, validation key and decryption key
parameters need to be used?
I dont know if you need a machine key. But here's how you generate one: Here is a little console program, which will create a machine key tag for your web.config. You can just copy the text from the console to your web.config like this:
<system.web>
...
<machineKey ... />
</system.web>
And the program. DISCLAIMER: Code not by me, I merely adapted it:
public class KeyCreator
{
const int VALIDATION_KEY_LENGTH = 24;
const int DECRYPTION_KEY_LENGTH = 64;
public static void Main(string[] args)
{
string decryptionKey = CreateKey(VALIDATION_KEY_LENGTH);
string validationKey = CreateKey(DECRYPTION_KEY_LENGTH);
Console.WriteLine("<machineKey validationKey=\"{0}\" decryptionKey=\"{1}\" validation=\"SHA1\"/>", validationKey, decryptionKey);
Console.ReadKey();
}
static string CreateKey(int numBytes)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[numBytes];
rng.GetBytes(buff);
return BytesToHexString(buff);
}
static string BytesToHexString(byte[] bytes)
{
StringBuilder hexString = new StringBuilder(64);
for (int counter = 0; counter < bytes.Length; counter++)
{
hexString.Append(String.Format("{0:X2}", bytes[counter]));
}
return hexString.ToString();
}
}
I have generated the machine key as below on my local IIS and applied to the config file. I have then published that to live folder and it seems to be working fine.
Encryption method: SHA1
Decryption method: auto
Validation key:
Automatically generate at runtime (unchecked)
Generate a unique key for each application (unchecked)

How do I access the host application's web.config file from a class library/assembly?

I'm creating a class library that will be used in a web application. One of the things that happens in one of the assembly classes is that it hits a database. Normally, when I do this from a service, the connection string gets extracted from the web.config file. With the class library, I'm not so sure how that's going to work the same way. Any suggestions?
Right now, I tried putting my normal config call in the assembly:
protected readonly string _utiConnStr =
System.Web.Configuration.WebConfigurationManager.ConnectionStrings["UTI"].ConnectionString;
It pukes, saying "Object reference not set to an instance of an object."
For instance if I want mail settings:
//open the webconfig
Configuration webConfig = WebConfigurationManager.OpenWebConfiguration(#"~/web.config");
// Get mail settings
mailSettings = webConfig.GetSectionGroup("system.net/mailSettings") as MailSettingsSectionGroup;

Encrypt Connection String in Web.Config Fails

I would like to encrypt the connection string of my web.config. Here I have found a nice example on how to do this. I implemented this and on my development machine this runs find.
However if I upload it to the provider, it does not work with the following error:
[SecurityException: Request failed.]
System.Configuration.DpapiProtectedConfigurationProvider.Encrypt(XmlNode node)
In this blog I have read, that this is because of the web probably runs in medium trust and therefore WebConfigurationManager.OpenWebConfiguration can not be used. Instead of this, WebConfigurationManager.GetSection should be used. However, if I get the section as proposed, the call to ProtectSection fails with the following error message:
System.InvalidOperationException: This operation does not apply at runtime
Can anyone lead me to a solution, how I can encode (and decode) the connection string in the web.config file (at runtime)?
Update
Not a real answer to the question, but the hoster gave full trust to the web and now, all worked fine. I leave the quesion open, maybe someone posts a solution to the original question and helps with this people having the same problem but not getting full trust.
From http://msdn.microsoft.com/en-us/library/89211k9b%28v=vs.80%29.aspx
static void ToggleWebEncrypt()
{
// Open the Web.config file.
Configuration config = WebConfigurationManager.
OpenWebConfiguration("~");
// Get the connectionStrings section.
ConnectionStringsSection section =
config.GetSection("connectionStrings")
as ConnectionStringsSection;
// Toggle encryption.
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
}
else
{
section.SectionInformation.ProtectSection(
"DataProtectionConfigurationProvider");
}
// Save changes to the Web.config file.
config.Save();
}
UPDATE
Also, ensure that your service account has write permissions to the Web.config. Also, be aware that granting write permissions to your service account on the Web.config increases somewhat the security footprint of your application. Only do so if you understand and accept the risks.

Moved asp.net site to new server, getting "Key not valid for use in specified state." error

I have set up a brand new, clean server to run our asp.net 4 website on. I have copied over the wwwroot folder from one of the existing servers, imported the configuration, and imported pfx file from the "old" server.
Our website contains a shopping cart and during the payment portion of the cart process on this new server it throws the following error:
[CryptographicException: Key not valid for use in specified state.]
System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) +374
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.ProtectedKey.Unprotect() +15
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.SymmetricCryptographer.Decrypt(Byte[] encryptedText) +66
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.SymmetricAlgorithmProvider.Decrypt(Byte[] ciphertext) +187
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.Cryptographer.DecryptSymmetric(String symmetricInstance, Byte[] ciphertext) +114
Microsoft.Practices.EnterpriseLibrary.Security.Cryptography.Cryptographer.DecryptSymmetric(String symmetricInstance, String ciphertextBase64) +73
CompanyName.Objects.BasePayment.get_PaymentNumberLastFour() +17
[TargetInvocationException: Property accessor 'PaymentNumberLastFour' on object
'CompanyName.Objects.Payment' threw the following exception:'Key not valid for use in specified state.
The code has not changed, its the same code on the other web server so I'm assuming it has something to do with the machinekeys. I have tried removing the rsa keys from the application data folder but to no avail. I'm not very familiar with cryptography in asp.net so its probably something I'm missing.
Anyone have any ideas?
Thanks.
Typically with the encryption process, there is something machine based that makes the key only work on the machine that generated it, even if you are using some kind of third party provider or key.
Try using the following MSDN documentation to export and regenerate the key on your new server.
I wonder if you have to resign your key used for encrypting CC info.

Encrypting Web.config and installing

I am new to the encryption process and have tried unsuccessfully to install an encrypted web.config file onto a hosting companies server. I am using Microsoft Visual Web Developer 2010 Express.
I have followed the steps located in Walkthrough: Encrypting Configuration Information Using Protected several times.
Please Note regarding the walkthrough, I do not have any machineKeys in my web.config file, so I skipped that encryption step.
When I Ran the aspnet_regiis -pef connectionStrings "c:\Users......\mywebsite.com"
Return is:
Encrypting configuration section ...
Succeeded!
2) I then FTP my web.config file and the site gets the below error: Note: The Line 8 is highlighted)
Server Error in '/' Application.
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
Parser Error Message: Failed to decrypt using provider 'RsaProtectedConfigurationProvider'. Error message from the provider: Bad Data.
Source Error:
Line 6:
Line 7:
Line 8:
Line 10:
Source File: C:\HostingSpaces*username**mywebsite.com*\wwwroot\web.config Line: 8
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1
I know there must be some piece missing but I have searched and have not found anything. I emailed the hosting company to find out if they need to do anything regarding encrypting web sites and they have not responded yet.
What I would expect is that there is a key that resides elsewhere which takes the encrypted value and decrypts it using an algorhythm. If this is so, where would I get that key and where would it go.
Any help is greatly appreciated and somewhat surprised I cannot find any issues similar to this on the web.
Thanks Much.
I don't have a direct answer to your question, but here's a simple technique to encrypt web.config. It may not be the best way, but it might be enough to get you started. This technique encrypts web.config during application start-up.
VERY IMPORTANT: make sure this code only runs in production. If you run it during development, you'll encrypt your source web.config and you won't be able to get it back.
private static void EncryptConfig() {
System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath);
foreach (string sectionName in new[] { "connectionStrings", "appSettings" }) {
ConfigurationSection section = config.GetSection(sectionName);
if (!section.SectionInformation.IsProtected) {
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
}
}
config.Save();
}
You can then call this method in Application_Start()
protected void Application_Start() {
if (IsProduction) {
EncryptConfig();
}
}
This solution isn't perfect because when you deploy your web.config to your production server, it won't be encrypted. Because the encryption happens during runtime, it will only be encrypted once your application starts. When the first request comes in, web.config will be encrypted. When the second request comes in, your app will need to restart because asp.net will detect that web.config was changed. And then from that point on, your app will operate normally with an encrypted web.config. The benefit of this technique is that the encryption happens automatically. Whenever you deploy a new web.config file, it will automatically be encrypted during start-up.
Important: Make sure that EncryptConfig() only runs in production so that you don't encrypt your source web.config.
Jonny O - Thanks. This worked so easily. CP
I added the global.asax file and here are the code snippets that went into this file (global.asax.cs).
Granted much of this is duplicated from above, but it is my entire solution. Thanks again.
using System.Web.Configuration;
using System.Configuration;
using System.Web.Hosting;
protected void Application_Start(object sender, EventArgs e)
{
//Test to see if this app is being started on the development machine (e.g. in the debugger)
//This code will encript web.config the first time this program runs.
//Therefore, it is important to have a backup copy of the non-encrypted web.config as this
//code below will encrypt it, which is what we want to happen on the production server.
if (! System.Diagnostics.Debugger.IsAttached )
{
EncryptConfig(); //See below
}
}
/// <summary>
/// This technique of encrypting the web.config file was learned from this forum post:
/// http://stackoverflow.com/questions/5602630/encrypting-web-config-and-installing
/// </summary>
private static void EncryptConfig()
{
System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration(HostingEnvironment.ApplicationVirtualPath);
foreach (string sectionName in new[] { "connectionStrings", "appSettings" })
{
ConfigurationSection section = config.GetSection(sectionName);
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
}
}
config.Save();
}

Resources