Viewstate Validation fails in web-farm - Usual suspects eliminated - asp.net

I think that I've tried all of the standard responses to this problem, and I know that I've read hundreds of questions and posts about this problem, but none of them seem to have resolved it or shed any light on what the cause is in my scenario. (I'm 5 hours down and no nearer :-( )
I have a web-farm of 2 servers.
I have set the machine key and validation key in machine.config on both machines
Encryption: SHA1, Decryption: AES - These are the defaults, could it help to change them?
I have verified that no other config files in the chain (web.cfg, apphost etc.) have a setting for these values.
I have added a page to the site (based on this SO) that spits the machine key values back out, and verified that they are the same across requests to both machines and match the values that are in machine .config
The server side session state is in a shared state-server, I have verified that sessionid remains constant between requests to the 2 servers.
I have verified that the page is completely loaded and the __EVENTVALIDATION hidden field has been rendered into the page before initiating the post. The viewstate size is not too bad at 7.64kb
When a page is rendered from a request to server 1 and then posted back to server 2, I get the dreaded...
Error Message:
Unable to validate data.
at System.Web.Configuration.MachineKeySection.GetDecodedData(Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Int32& dataLength)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) HttpApplication.RecordError => HttpApplication.RaiseOnError => global_asax.Application_Error
The post is triggered by a standard, unadulterated asp linkbutton, there is no ajax going on on the page.
Any and all help will be greatly appreciated.
Setting enableViewStateMAC = false is not a solution :-)

Having inherited the servers in the state that they were configured, I never questioned the validity of the keys!!! ...Just checked that they matched on both servers...
Leaving all the encryption / decryption and validation algorithm settings as they were, I generated new keys using this tool which has a few more options than the others.
Problem solved
Moral of the story: If in doubt, generate new keys
... but why and how? Some postbacks with viewstate were working just fine with the old keys, it was only when the postback was to a different server that the problem became evident. If the keys were invalid - missing a character or something - then every postback should have failed - I think

If you've established that the machine keys are the same on both boxes, could it be the encryption/decryption thereof ?
Have you tried using Triple DES and setting the decryptionKey in the machine.config on both servers?
Check here

Also a easy way of making sure the machineKeys are the same is to add a line like this in the web.config.
NB: Assuming you have the same web.config on both servers and making sure that the validationKey and decryptionKey is valid
You can use http://aspnetresources.com/tools/machineKey to generate it.
<system.web>
<machineKey validationKey="*D9B0EDEA69D81A89BF5FBA2B08BAF691013F86B89A1F6BA8068C6ECC9539074" decryptionKey="*AE2B1966AF65D08F03EDFB" validation="SHA1" decryption="AES" />

Related

ASP.NET_SessionId cookie disappearing between request on a specific server

I have differing behavior between a test server and a dev server - on my dev server everything works fine but on the test server the ASP.NET_SessionId cookie disappears after a flow of events and hence so does the servers session. Testing was done in the same browser on the same machine & the code bases are virtually identical. The only significant difference is that the pages are being served from two different pcs.
The flow of pages (all https) that causes this is such:
Load page from domain A that contains an iframe (session cookie exists at this point).
Domain B is loaded into the iframe.
A second page from domain B is loaded into the iframe triggered from the first page.
The second page does a form post to back to domain A where the session cookie is now absent.
EDIT
Forgot to say - we're using SqlInMemoryProvider as our session state.
You could share the session state between two servers using the below ways:
1)Using SQLServer Session:
In this mode of session state, the session objects are stored into SQL Server.
The benefit of using this technique is that all the data in the session will be stored together in a different location or you can say a centralized location in SQL Server, to get it working we just need to configure the SQLServer to store session data.
2)Using the StateServer Session:
In this mode of session state, the session objects are stored in a separate server handled by a Windows Service running on that server.
The benefit of using this technique is that all the data in the session will be stored together in a different location. In this case, the server to be handled by the Windows Service is named "aspnet_state"; this will become the centralized location for session data. To get it working we just need to configure the StateServer to store Session data.
when you share the session state between two servers make sure ASP.NET state service is installed on all the servers and the settings are as below:
Also, the service cannot be accessed remotely by default. To enable that option you need to set the value of the following registry key to 1: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnection. Don’t forget to restart the asp.net state service after the registry key change.
You need to declare the session management options within the system.web node. Example:
<sessionState mode="StateServer" stateConnectionString="tcpip=machinename:42424">
</sessionState>
If you want to use the SQL Server type then this section may look like the following:
<sessionState mode="SQLServer" allowCustomSqlDatabase="true"sqlConnectionString="the connection string name to the server">
</sessionState>
Where SQL connection string refers to the name of the connection string in the connectionStrings section of web.config which holds the details of the state table. The connection string itself may take up the following format:
<add name="ASPStateConnectionString" connectionString="Data Source=[DB machine name where state DB is stored];Initial Catalog=ASPState;User ID=[db admin user name];Password=[db admin password]"providerName="System.Data.SqlClient" />
we also need to add a machine and a validation key within the system.web node, that may look something like this:
<machineKey
validationKey="some long hashed value"
decryptionKey="another long hashed value"
validation="SHA1"/>
The default setting for the validation key is AutoGenerate which does exactly what the name applies: the key will be generated automatically by IIS. The default generation mode for the decryption key is IsolateApps. It generates a unique key for each application by using the application ID.
We need this common machine key as we want to run this on several machines so we don’t want the machine key to be automatically generated.
For more information you could refer this below links:
https://dotnetcodr.com/2013/07/01/web-farms-in-net-and-iis-part-5-session-state-management/
https://www.c-sharpcorner.com/UploadFile/25c78a/load-balancing-session-state-configuration/
It's because cookies are not stored if domains are different.
It's treated as 3rd party cookies.
You need to use same domain as parent site to iframe site.
Or else you need to use cookieless session.
I have recently gone through this problem and come across the concept of cross-site cookies. If you want to share and use the cookie across the different domains then you have to set your cookie samesite attribute to None (SameSite=None). It must be secure otherwise it will be ignored and not send back to the server by browser (Chrome). To use a secure tag for your cookie you have to enable the HTTPS for your website.
For more detail you visit: https://web.dev/samesite-cookies-explained/

Why might my users be being logged out after a minute or so?

I have a Asp Mvc 2 site using forms authentication. When I run it locally I can log in and stay logged in indefinitely.
However when I put it on the server I seem to only stay logged in for a few minutes and then seems to be logged out. I have looked at the cookies and there are 2 which seem relevant:
.ASPXAUTH which is a session cookie
.ASPXANONYMOUS which expires in 3 months.
When I refresh the page the cookies stay the same until I get logged out, when I seem to get a new .ASPXANONYMOUS cookie, but the .ASPXAUTH seems to be the same.
It seems that I might be able to stay logged in until I do something after a certain amount of time. If I submit a form as soon as I am logged in then it works ok, but if I keep submitting data again and again then after a minute or so, one of the submits will happen as a logged out user and not as the user who was logged in, which all the other submits worked as.
What might cause this behaviour and how can I track down what is different & change it so that I can stay logged in indefinitely?
EDIT,
its a single server, but after some more investigation and searching the likely candidate seems to be that I am using more than 100mb on the server and the application pool is getting recycled. I suppose now i need to know
How can I check how much memory I'm using.
What advice there is to reduce that.
Could it be that the ASP.NET application is being re-cycled or shutdown (e.g. due to idle timeout, or newly built/changed assemblies)?
When an ASP.NET web application starts up it will, by default, generate encryption keys for view state and session cookies. This will invalidate any such data originally served from an earlier run of the application (or from a different system).
To have sessions survive ASP.NET application cycles (and multi-server farms) you can specify the keys in your web.config:
<system.web>
...
<machineKey
decryption="AES"
validation="SHA1"
decryptionKey="..."
validationKey="..."
/>
where decryptionKey and validationKey are hex strings of length depending on the algorithm (with AES: 64 digits and SHA1: 128, for other algorithms check MSDN).
These keys should be cryptographically generated, and .NET has the types to do this which can be used from PowerShell:
$rng = New-Object "System.Security.Cryptography.RNGCryptoServiceProvider"
$bytes = [Array]::CreateInstance([byte], 16)
$rng.GetBytes($bytes)
$bytes | ForEach-Object -begin { $s = "" } -process { $s = $s + ("{0:X2}" -f $_) } -end { $s}
For AES use the above array length, for SHA1 use a length of 64.
It is quite likely that Session Timeout on the web server is configured to a much smaller timespan than you have set in your Form Authentication configuration in web.config.
The default Session Timeout is 20 minutes for IIS6 and IIS7.
If you have access to the web server's admin interface, you can raise the timeout via the GUI, but it can also be set from the config file if your IIS7 using the <sessionState> and <sessionPageState> sections:
http://msdn.microsoft.com/en-us/library/cc725820(v=ws.10).aspx
Check the webconfig authentication section
<authentication mode="Forms">
<forms name="UniqueName" loginUrl="login.aspx" path="/" >
</forms>
</authentication>
Ensure that the authentication cookie name for each hosted site is unique.
Came here with a similar issue, following the suggestion by #Richard, I looked at the Application Pools' recycling settings. What I found was the settings were changed and the Regular time intervals (in minutes) value was set to 1 minute. This meant that the app pool was being recycled each minute.
To change that, Right-click on the application pool, select the Recycling option, change the value under Regular time intervals (in minutes). I set it to the same value as the other Application Pools were using.
This change fixed the issue, turns out it was set to a low value a while back while during some misguided troubleshooting with an expired SSL certificate.
If none of these work, check in the Application Pools and ensure that the Idle Timeout is set to 20+ minutes. Click on the application pool, select the Advanced Settings link to the right, find the Process Model section, and increase the Idle Timeout value there.

Unable to validate data. at System.Web.Configuration.MachineKeySection.GetDecodedData

I have several websites which get approximately 3000 pageviews in total per day, and I get this viewstate error roughly 5-10 times per day, caught in global.asax:
System.Web.HttpException: Unable to validate data. at System.Web.Configuration.MachineKeySection.GetDecodedData(Byte[] buf, Byte[] modifier, Int32 start, Int32 length, Int32& dataLength) at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
I have tried:
hard-coding the machine key in web.config for all websites
hard-coding the machien key in machine.config
adding items to the pages section of the web.config for all websites.
Machine key looks like:
<machineKey validationKey="key goes here" decryptionKey="key goes here" validation="SHA1" decryption="AES" />
Pages section looks like:
<pages renderAllHiddenFieldsAtTopOfForm="true" validateRequest="false" enableEventValidation="false" viewStateEncryptionMode="Never">
The errors are not related to application pool recycling as best I can tell, as the pool is set to recycle at every 100,000 requests. I am not running a web farm or web garden. Quite often I get two or three of these errors in a row, as if a user is getting an error, going back, and then clicking the link again.
Anyone have any ideas?
I have seen "random" ViewState errors before caused by slow internet connections. The slow connections would cause the page to be visibly rendered to the user, however it hadn't completely loaded. The user would then take action on the form and thus "random" issues would occur.
See if you can correlate the exception timestamps to specific pages being requested in the IIS logs. You could then try to re-create the low bandwidth scenario with something like Firefox Throttle.
Similar question below confirms my experiences and probably what your are seeing as well:
ASP.NET: Unable to validate data

ViewState and Security Settings generating errors

I have an odd reoccurring error that I believe is related to View State and security settings. This error appears on one of my client’s site between 1 to 6 times a day:
Source: System.Web
Error in: /detail.aspx?CaseID=1852
Error Message: Unable to validate data.
Stack Trace: at System.Web.Configuration.MachineKeySection.**EncryptOrDecryptData(**Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo)
at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
Researching online has lead to a deadend. I believe it has do with security and ViewState. Because this is an ecommerce site, I took the extra steps of protecting against a number of treats, includign XSS and CSFR. Here are the steps I took:
Turned on HTTPOnly Cookies (Protects against XSS Style Attacks)
Turned on Secure Cookie Flag (Protects against XSS Style Attacks)
Created a BasePage which all the pages inherit instead of Page, in the Basepage I overrides OnInit and set ViewStateUserKey to SessionID (Protects against certain CSFR Style Attacks)
Explicitly enabled validateRequest (On by default, but can be overwritten)
ViewState Encryption Enabled
The website is hosted on a Win2003 Virtual Server, using ASP.NET 3.5 SP1 and AJAX. The page is not using caching, which some articles I found suggested was a problem when you set the ViewStateUserKey key to a unique value, such as SessionID. I can duplicate this exact error if I turn off cookies in my browser and try to view one of the pages that creates the error.
Notes, The error message does NOT mention MAC has failed
My theory is that those that experience this error are on networks that have a Proxy/Caching Server. My solution was to only set the ViewStateUserKey when it was a secure connection. Most Proxy/Caching Servers are only set to cache HTTP connections, not secure connections.

Why is ASP.NET accepting externally created session identifiers?

I have an ASP.NET 3.5 Web Site using the standard SQL Membership Provider.
The application has to pass the IBM Rational AppScan before we can push to production.
I am getting the error:
Severity: High
Test Type: Application
Vulnerable URL: http://mytestserver/myapp/login.aspx
Remediation Tasks: Do not accept externally created session identifiers
What can I do to fix this?
I am using SQL Membership Provider. Is this related? I am using the standard login controls too. I have the "Remember Me" turned off, and hidden.
Thanks.
This isn't a vulnerability (and I really don't like AppScan because of its false positives - the number of times I've had to explain CSRF cookies need not be linked to a session on my little open source project is getting annoying).
All that will happen in this case is the first time anything is stored in session state with a created session identifier a new session will be opened on the server, with nothing in it. If you're worried about session fixation then you can clear the cookie after authentication.
Session.Abandon();
Response.Cookies.Add(new HttpCookie("ASP.NET_SessionId", ""));
But with forms authentication the authentication details are not held in the session and so fixation is not a problem at all.
Frankly if you must pass security scans without anyone evaluating if the results are not false positives then that's a whole different problem.
You might need to change the default cookie settings to be unique to you app
Try setting a unique cookie path:
<forms name="YourAppName"
path="/FormsAuth" ... />
http://msdn.microsoft.com/en-us/library/ms998310.aspx#paght000012_additionalconsiderations
More reading...
http://msdn.microsoft.com/en-us/library/ms998258.aspx
It would seem RegenerateExpiredSessionId property is controlling this.
Do set it to true. Also keep time-out to a and low value, the tightest acceptable by users (e.g. 10 - 15 minutes).

Resources