ASP.NET FormsAuthentication: have to log in again when restarting application - c#

I have an ASP.NET application using FormsAuthentication. Whenever I restart the application or web server, my authentication token is invalid and I have to log in again. What's going wrong?

By default, FormsAuthentication validates authentication data on every request by having the client store an encrypted copy of the data. The encryption key is stored in Machine.config. The specific key to use is in <machineKey decryptionKey="YOUR KEY HERE">.
If you do not provide a decryption key, one is automatically generated on application startup. Since it is randomly generated, it will be different each time you restart the application. On the validation phase, FormsAuthentication attempts to decrypt the authentication data and fails. Then the user is no longer logged in.
There are two ways of resolving this problem.
Providing a machineKey in Machine.config will give FormsAuthentication a consistent key to use, so validation will succeed with the encrypted cookie from previous application runs.
Using <forms protection="None" ... /> in Web.config will disable authentication data encryption and validation. This is insecure and only appropriate for development, since it will be trivial for users to impersonate each other.

The default session state mode in asp.net is in-proc (cached in-memory) unless you specify otherwise. When the application shuts down, memory is cleared and the in-proc session cache is therefore lost.
#dhasenan The machinekey config will only be an issue if the application is deployed across a web farm or the cloud. The idea of overriding the machine-level config of the Machinekey element is to ensure that multiple machines are using the exact same keys.
Therefore, the machine key shouldn't be an issue because if one is not provided at the application level, the machine key in the machine.config will be used instead, which is persisted and static, so it will not be regenerated between sessions.

Related

.net + Sharing session over multiple servers with redissessionstateprovider + sessionstate custom mode

I want to use a session created in one server from a another server. Which means i need to share session between two asp.net applications hosted in 2 different servers using Session State Custom mode by RedisSessionStateProvider.
I haven't used the Redis session state provider, but, by default, ASP.Net uses a cookie to persist te sessionid to the browser. This cookie has the user session id encrypted, using the "MachineKey" entry in Machine.config to get the encryption key.
See Microsoft Docs for reference.
If the key is specified in web.config file, it should override the machine key just for your application. You should set the same machinekey entry in both web configs of the two servers.

ASP.NET MVC: How do SimpleMembership, SQLSession store, Authentication, and Authorization work?

I have been struggling with these elements for about 2 months.
The first problem arise when my MVC4 application was recycled. The current logged-in user suddenly cannot access any controller actions which are marked [Authorize]. Also, any successful access to the controller action which requires database connection produces this error:
Cannot open user default database. Login failed. Login failed for user
'IIS APPPOOL\DefaultAppPool'.
This is weird because if I clear my authentication cookies, it works fine. So there is a problem with the ASPXAUTH and .ASPNET_SessionId cookies.
Later I figure out that those errors are caused by session invalidation after server restart or recycle. My session setting was in InProc mode. This means the session is lost every time the server is restarted or recycled.
Then I change my session config into Custom Session SQLStore which described in
https://msdn.microsoft.com/en-us/library/ms178588.aspx
and
https://msdn.microsoft.com/en-us/library/ms178589.aspx
The purpose is to store the session data in SQLServer, but the problem seems to not go away. After the server is restarted or recycled, the currently logged-in user still having the problem accessing the controller action.
My thought is that the SimpleMembership is not storing the login session in the database. This is how I do login:
WebSecurity.Login(userName, model.Password, persistCookie: true)
If I am correct, the system will try to match authentication cookies with login session data and determine if the authentication is still valid. This is why my user is kept having the problem because the matching between session and cookies produce some weird things.
I did a lot of research for the past 2 months, I found many similar problems with mine, but I did not find a proper solution.
The temporary solution that I am using is to logged-out the user if the server is getting recycled or restarted. This is not a good solution because if the user is in the middle of important transaction or submission, the data can be lost, and the user is redirected to login page again.
Update
I have my machine key set:
<machineKey validationKey="685DD0E54A38F97FACF4CA27F54D3DA491AB40FE6941110A5A2BA2BC7DDE7411965D45A1E571B7B9283A0D0B382D35A0840B46EDBCE8E05DCE74DE5A37D7A5B3"
decryptionKey="15653D093ED55032EA6EDDBFD63E4AAA479E79038C0F800561DD2CC4597FBC9E"
validation="SHA1" decryption="AES" />
I try to debug my custom SQL session store, I found out that there is no authentication session is stored in the database. I can only find "__ControllerTempData" retrieved from my SQL session, and nothing else.
Please correct me if I am wrong, the way the website reuse the authentication cookies and validates it is by comparing authentication cookie and the authentication session, am I right?
Apparently, SimpleMembership Login() does not store the authentication session into the SQL state server.
Then which session key is used for the comparing?
Make sure you've added a machineKey setting to your web.config, otherwise your site uses an auto-generated machine key. If the machine key changes, anything encrypted with the previous key can't be decrypted, which will cause (in part) the error you're seeing.
I posted an answer to a different question that covers adding a machineKey to your web.config, and how to generate the keys yourself, or you can use code from this app I made.
The gist is thus:
1) Add a machine key, like so (filling in the appropriate values)"
<machinekey compatibilitymode="Framework45"
validation="HMACSHA256"
validationkey="YOURVALIDATIONKEYHERE"
decryption="AES"
decryptionkey="YOURDECRYPTIONKEYHERE" />
2) Restart the app pool. You'll have one more round of users potentially having issues accessing the site (unless you also change the cookie name), but clearing their cookies will solve that problem.
This is so silly for me. I did not put:
if (!WebSecurity.Initialized)
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: false);
in my application intialization (global.asax or any initialization code called from global.asax).
I only call WebSecurity.InitializeDatabaseConnection() when the code need it and somehow the web misses WebSecurity.InitializeDatabaseConnection() when I made request while the server restarted.
There is no connection between session and auth cookie which perform some validation. There is no validation between them. The login auth is purely hold by cookies.
I still need custom sql store session tho. Because TempData becomes persistence. This will not causing form submission to fail while the server is restarted.

Using in memory repo for data protection when running in IIS

I'm running a production server (Windows Server 2012) with an AspNet Mvc Core RC1 website.
I'm seeing the following in the logs:
Neither user profile nor HKLM registry available. Using an ephemeral key repository. Protected data will be unavailable when application exits.
After inspecting the source code for DataProtection, I tracked the problem to the following method call:
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
This is probably returning null on the server for some reason. I don't have any special custom configuration in place and I've read the docs so I thought the default would work.
I think the problem is with the IIS website not running in a certain user's context but I have no idea how to confirm or fix this. My website is configured with its own pool.
As an aside: the result of running an in memory repository for storing keys causes them to recycle whenever the application exits which is very annoying and not even intended for use in production environments.
User profile should be loaded in IIS configuration.
Open IIS, right click on Application Pools then Advanced Settings. And set "Load user profile" to true. Restart your app and it should work perfectly.
Data Protection keys used by ASP.NET applications are stored in registry hives external to the applications. When running your application as an AppPool Identity you have to create a registry hive for every AppPool used with an ASP.NET Core application.
For standalone IIS installations, you may use the Data Protection PowerShell script for each application pool used with an ASP.NET Core application. The keys will be persisted in the registry.
Like clearly stated in the logs since the registry hive that Data Protection looks for does not exist, keys will not be persisted to disk. Instead, they will be ephemeral and live in-memory only.
In web farm scenarios, an application can be configured to use a UNC path to store its data protection key ring. By default, the data protection keys are not encrypted. You can deploy an x509 certificate to each machine to encrypt the key ring.
See the official ASP.NET Core doc about data-protection for more information
Those who are on the hosted environment where the access rights are very limited can use PersistKeysToFileSystem instead.
Adding the following listing into the Startup.cs will resolve your issue:
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"\\server\share\directory\"));
}
You can change the path string acording to your needs.
Please also check ProtectKeysWith if you want to configure the system to protect keys at rest by calling any of the ProtectKeysWith* configuration APIs.
Take a look at this from the DataProtection Git repository
In short, there is a bug in IIS that may never be corrected that prevent the correct registry setup for DataProtection keys. There is a powershell script to setup manually the registry correctly so that it works for AspNet Core. After you run the script for each application pool you use for AspNet Core applications, those applications will then work as intended.

Synchronizing machine keys in ASP.NET web application [duplicate]

We (our IT partner really) recently changed some DNS for a web farmed site we have, so that the two production server have round-robin DNS switching between them. Prior to this switch we didn't really have problems with WebResource.axd files. Since the switch, when we hit the live public URL, we get an error:
CryptographicException
Padding is invalid and cannot be removed.
When we hit the specific servers themselves, they load fine. I've researched the issue and it seems since they're sharing assets between two servers, we need to have a consistent machineKey in the web.config for each server so they can encrypt and decrypt consistently between the two. My questions are:
Can I generate a machineKey via a tool on the server, or do I need to write code to do this?
Do I just need to add the machineKey to the web.config on each server or do you think I'll need to do anything else to make the two server work together? (Both web.config's currently do not have a machineKey)
This should answer:
How To: Configure MachineKey in ASP.NET 2.0 - Web Farm Deployment Considerations
Web Farm Deployment Considerations
If you deploy your application in a Web farm, you must ensure that the
configuration files on each server share the same value for
validationKey and decryptionKey, which are used for hashing and
decryption respectively. This is required because you cannot guarantee
which server will handle successive requests.
With manually generated key values, the settings should
be similar to the following example.
<machineKey
validationKey="21F090935F6E49C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7
AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281B"
decryptionKey="ABAA84D7EC4BB56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
validation="SHA1"
decryption="AES"
/>
If you want to isolate your application from other applications on the
same server, place the in the Web.config file for each
application on each server in the farm. Ensure that you use separate
key values for each application, but duplicate each application's keys
across all servers in the farm.
In short, to set up the machine key refer the following link:
Setting Up a Machine Key - Orchard Documentation.
Setting Up the Machine Key Using IIS Manager
If you have access to the IIS management console for the server where
Orchard is installed, it is the easiest way to set-up a machine key.
Start the management console and then select the web site. Open the
machine key configuration:
The machine key control panel has the following settings:
Uncheck "Automatically generate at runtime" for both the validation
key and the decryption key.
Click "Generate Keys" under "Actions" on the right side of the panel.
Click "Apply".
and add the following line to the web.config file in all the webservers under system.web tag if it does not exist.
<machineKey
validationKey="21F0SAMPLEKEY9C2C797F69BBAAD8402ABD2EE0B667A8B44EA7DD4374267A75D7
AD972A119482D15A4127461DB1DC347C1A63AE5F1CCFAACFF1B72A7F0A281B"
decryptionKey="ABAASAMPLEKEY56D75D217CECFFB9628809BDB8BF91CFCD64568A145BE59719F"
validation="SHA1"
decryption="AES"
/>
Please make sure that you have a permanent backup of the machine keys and web.config file
If you are using IIS 7.5 or later you can generate the machine key from IIS and save it directly to your web.config, within the web farm you then just copy the new web.config to each server.
Open IIS manager.
If you need to generate and save the MachineKey for all your applications select the server name in the left pane, in that case you will be modifying the root web.config file (which is placed in the .NET framework folder). If your intention is to create MachineKey for a specific web site/application then select the web site / application from the left pane. In that case you will be modifying the web.config file of your application.
Double-click the Machine Key icon in ASP.NET settings in the middle pane:
MachineKey section will be read from your configuration file and be shown in the UI. If you did not configure a specific MachineKey and it is generated automatically you will see the following options:
Now you can click Generate Keys on the right pane to generate random MachineKeys. When you click Apply, all settings will be saved in the web.config file.
Full Details can be seen # Easiest way to generate MachineKey – Tips and tricks: ASP.NET, IIS and .NET development…
Make sure to learn from the padding oracle asp.net vulnerability that just happened (you applied the patch, right? ...) and use protected sections to encrypt the machine key and any other sensitive configuration.
An alternative option is to set it in the machine level web.config, so its not even in the web site folder.
To generate it do it just like the linked article in David's answer.

Uses for MachineKey in ASP.NET

What different ways are Machine Keys useful in asp.net?
I think the following are correct but thought there may be more.
Multiple applications can use the same cookie
Multiple servers can work with the same viewstate
MachineKey is used for:
ViewState encryption and validation
Forms Authentication (or Federated Authentication) uses this key for signing the authentication ticket
Having a Web App installed on multiple servers requires same Machine Key configured on all of them in order for Load Balancing to work.
To see all details, please refer to: MSDN How To: Configure MachineKey in ASP.NET 2.0
Machine key is also used to encrypt/decrypt the webresources.axd parameters.
Even on a single server the machine key should be configured, because any recycle of the app domain will generate a new key when it is set to auto. This causes the next postback just for pages rendered before the recycle, to cause a viewstate validation error, and also issues with the resources during that time.
Encryption - very common.

Categories