Can you set the MachineKey programmatically? - asp.net

In ASP.NET can you set the machineKey settings programmatically?
The web app that we use stores sensitive info encrypted in a database, so if we could put the decryptionKey there it would be handy.

No; the machineKey element must be set via config. However, web.config can itself be encrypted, which helps minimize risk of cryptographic key disclosure if an attacker ever gets access to the config file. (This same process can be used to protect SQL connection strings and pretty much any other sensitive config element you wish.) See http://msdn.microsoft.com/en-us/library/dtkwfdky(v=VS.100).aspx for a walkthrough on enabling this.

Yes, you can. I got success using this code in ConsoleApplication:
private static void ChangeWebConfig(string validationKey, string decryptionKey, string webConfigPath)
{
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = webConfigPath;
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
MachineKeySection section = (MachineKeySection)config.GetSection("system.web/machineKey");
section.ValidationKey = validationKey;
section.DecryptionKey = decryptionKey;
config.Save();
}

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)

DbContext ASP.Net and Quartz.net

I just created a cron job like job using Quartz.net. For the test, it execute a simple request to the database. It simply adds a field.
I have a dbcontext:
private TotoContext db = new TotoContext();
In my job I have:
var totos = from u in db.totos where u.name == name select u;
Toto[] totoArray = totos.ToArray();
In my web.config, I have a special field with my specific connectionstring and so on ("TotoContext").
But when I create a new dbContext it seems that it uses doesn't use the good connectionString. In the watch the connectionString is not linked with "TotoContext".
I initialize my job in:
public override bool OnStart()
And I have a specific Web.toto.config file with the connectionString for the build.
Why it doesn't use the good connectionString ?!
Thanks a lot !
Edit: if I set manually the connectionString in my db.Database.Connection.ConnectionString, it works. But why it doesn't use the web.config ConnectionString.
If you use full IIS mode (default configuration for web role), web.config will be ignored in the role entry point. So it is recommended to put all ASP.NET specific initialization tasks in Global.asax's Application_Start method. Role entry point is used to do something before ASP.NET application starts up, for example, modify IIS configuration. Inside Global.asax, web.config (and config transform) is respected.
I just found why it's not using the Web.config: https://stackoverflow.com/a/10153375/1396323
But the next question is how to store different connectionString depending on the build config (Debug, Release etc...) and where ?

How to operate with X509 certificates in .NET code

I have some code that needs to work with X509 Certificate information. I have downloaded a sample that does this:
const string CertWithoutPrivateKey = "MII....";
const string CertWithPrivateKey = "MII...";
public static SecurityToken GetSigningToken(bool includePrivateKey)
{
X509Certificate2 cert = null;
if (includePrivateKey)
{
cert = new X509Certificate2(
Convert.FromBase64String(CertWithPrivateKey),
"pw", X509KeyStorageFlags.PersistKeySet);
}
else
{
cert = new X509Certificate2(
Convert.FromBase64String(CertWithoutPrivateKey));
}
return cert;
}
The code needs to be able to get the cert with the private key. The Saml2AuthenticationModule (from the WIF Extension for the SAML 2.0 Protocol) relies on this private key to decrypt information sent from a SAML Identity Provider.
I don't know much about certificates or encryption, but it seems to me that hard-coding the certificate into a class is not secure.
So, how should my code go about retrieving the cert with private key? Afaik, this code is only run one time at app startup (so probably also after an app pool recycle).
I could:
Store the cert as an appSetting in config file. As long as appSettings are config encrypted, is this secure?
Store the cert in a database.
Store the cert as a file in bin/App_Data. Afaik this means it could not be read over the web, but would be in plain view to anyone who can access the host server. Imo if someone can get into my server, letting them read this cert is probably the least of my worries.
Are there any other options? What is most appropriate in this case?
A certificate with or without private key can be save to X509 store of a user or the computer. This already has build-in Windows security that should be sufficient. You can use mmc with Certificates snap-in to add certificates to the store and manage them.
A reference to the certificate, for example, its name or thumbnail, can saved to the config file and used to retrieve the certificate. The retrieval may look like the following:
public static X509Certificate2 GetCertificate(string name)
{
try
{
X509Store store = new X509Store (StoreLocation.LocalMachine);
X509Certificate2Collection collection = store.Certificates;
foreach (X509Certificate2 x509 in collection)
{
if (x509.FriendlyName.Equals(name))
{
return x509;
}
}
}
finally
{
store.Close();
}
return null;
}
Using Find on the collection is another (and cleaner) way to search certificates.
I'm not sure how WIF does it (you could probably use Reflector to see the internals of how it interacts with the certificate store), but it sounds like you are using WIF in an application hosted in IIS. If that's the case, WIF should take care of all the certificate interactions for you. You'll just have to make sure you have the following things set up:
The identity model configuration section set up with references to the thumbprint of the certificate you are using to either encrypt or verify the digital signature of the token.
The certificate needs to be registered in IIS
The application pool's hosting identity needs to have permission to "read" the certificate to extract the private key information (see the accepted answer here)

Is it possible to read IIS re-write rules from an Azure ServiceConfiguration file?

Is it possible to read the IIS re-write rules from the Azure ServiceConfiguration file instead of the web.config?
The problem that is arising is that we have friendly urls to certain weekly updated pages that are content managed, so a new url is created every week. The old ones are stored in a newslist archive so overwriting is not an option.
We would like to try and avoid having to upload the Azure site files every week, and want to be able to respond quickly (immediately) to possible link changes by altering values in the serviceconfig.
Anyone have any idea if this is possible or wether there is another solution?
Thanks
Yes, you can change your role to modify the web.config at runtime using the Configuration editor classes in the IIS Admin api. I haven't tried this, but it should enable you to load the settings from Azure config during startup then apply to the runtime instance of your role. So you would set this likely in your Application_start section of the web role's global.asax.
Alternatively, you could programitically build up the web.config at role start time using a Startup Task.
For the 1st approach:
Do some research at iis.net and then read this IIS forum post:
http://forums.iis.net/t/1150481.aspx
Take a sample from user ruslany (give credit where due, but pasting so you see it):
using(ServerManager serverManager = new ServerManager()) {
Configuration config = serverManager.GetWebConfiguration("Default Web Site");
ConfigurationSection rulesSection = config.GetSection("system.webServer/rewrite/rules");
ConfigurationElementCollection rulesCollection = rulesSection.GetCollection();
ConfigurationElement ruleElement = rulesCollection.CreateElement("rule");
ruleElement["name"] = #"MyTestRule";
ruleElement["stopProcessing"] = true;
ConfigurationElement matchElement = ruleElement.GetChildElement("match");
matchElement["url"] = #"foo\.asp";
ConfigurationElement conditionsElement = ruleElement.GetChildElement("conditions");
ConfigurationElementCollection conditionsCollection = conditionsElement.GetCollection();
ConfigurationElement addElement = conditionsCollection.CreateElement("add");
addElement["input"] = #"{HTTP_HOST}";
addElement["pattern"] = #"www\.foo\.com";
conditionsCollection.Add(addElement);
ConfigurationElement actionElement = ruleElement.GetChildElement("action");
actionElement["type"] = #"Rewrite";
actionElement["url"] = #"bar.asp";
rulesCollection.Add(ruleElement);
serverManager.CommitChanges();
}

How to change FormsCookieName at runtime in ASP.NET

We would like to have the FormsCookieName of FormsCookiePath change per instance of our application. We have an application which has multiple instances on 1 server/domainname. Because of this we can only work in 1 application at the same time, since the cookies will overwrite eachother. Same for the Sessions btw.
Is there a way to dynamicly, for example in the Global.asax Application_Start, change this name? This would be usefull as we keep a license name in each application which could be used as the basis for the CookieName.
We already work with Web.config and extra files to overwrite Web.config values in external files using: <appSettings file="Web.AppSettings.Config">
But this requires manual actions which can be forgotten and are redundant since the settings can be retrieved from the database.
Thanks.
I had similar situation, I did the following. In the Application_Start, I checked to see if my cookie name needed change. This would occur after a new deployment for all applications where I have the same web.config for all.
protected void Application_Start(object sender, EventArgs e)
{
// determine unique cookie name per application
string cookieName = ...
// Get the web.config forms settings
Configuration c = WebConfigurationManager.OpenWebConfiguration("~");
AuthenticationSection auth = c.GetSection("system.web/authentication")
as AuthenticationSection;
// See if we have mismatch in web.config or in Forms cookiename
if (auth != null && auth.Forms != null &&
(auth.Forms.Name != cookieName
|| FormsAuthentication.FormsCookieName != cookieName
)
)
{
// Assign value in web.config for future restarts
auth.Forms.Name = cookieName;
// would be nice if this restarted the app, but it doesn't appear to
c.Save();
// This seems to restart the app
System.Web.HttpRuntime.UnloadAppDomain();
}
...
}
The web.config is modified on the application start and then the web app is restarted. Next time the web app comes up, cookie names are in sync and the reset code is skipped.
I have been struggling with Cookies with quite a few days. It has been an awesome learning experience.
So wanted to share the possible ways I found & discovered: There are several HACKs to modify Forms Authentication Cookie name:
You can automate the modification of cookie name under Authenticaiton secion of Web.Config file in Application_Start event in Global.asax. Thanks to Ron for sharing this. But I could not guarantee that the user whose identity would be used to run application domain have enough privileges to modify the file on disk or not. Hence I needed an improvised solution, so I devised following.
Thanks to ILSpy for letting me see inside the FormsAuthentication class, and many thanks to Reflection to let me modify the private field of a class. I used following code to modify the cookie name on run-time with following small piece of code and this worked like a charm !!!
protected void Application_Start(Object sender, EventArgs e)
{
// This will enforce that FormsAuthentication class is loaded from configuration settings for the application.
FormsAuthentication.Initialize();
// The new cookie name whatever you need can go here, I needed some value from my application setting to be prefixed so I used it.
string newCookieName = string.Format("{0}.ASPXAUTH", ConfigurationManager.AppSettings["SomeSettingThatIsUniquetoSite"]);
// Modifying underlying baking field that points to FormsAuthentication.FormsCookieName
Type type = typeof(FormsAuthentication);
System.Reflection.FieldInfo field = type.GetField("_FormsName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
field.SetValue(null, newCookieName);
}
Suggestions, loopholes are requested as this is my first answer on this forum.
According to MSDN, the FormsAuthentication.FormsCookieName property that stores the cookie name is a read-only property. This property must be read from the web.config.
Each instance will need a separate name in the web.config. I suggest including the name of the authentication cookie in your existing change management system.

Resources