We have a collection of .NET sites which are hosted on two effectively identical webservers, with a simple load balancer splitting requests between the two. Everything was working fine until we had a hardware failure on one server and replaced it. Now, we're having session problems as people are being logged out of the applications whenever the load balancer switches the server they're connecting to.
Applications on both servers are configured to use SQLServer for session state, and have identical machineKey and sessionState values in web.config. e.g:
<configuration>
<system.web>
<machineKey validationKey="..." decryptionKey="..." validation="SHA1" decryption="AES" />
<sessionState mode="SQLServer" stateNetworkTimeout="30" stateConnectionString="..." allowCustomSqlDatabase="true" sqlConnectionString="..." cookieless="false" timeout="1441" />
</system.web>
</configuration>
The paired applications are also setup identically in IIS as far as I can tell: same URL, same application pool name, even same path on disk.
However, a request to the same site on each server (by IP) creates two unique SessionID values (with the same cookie name in the browser).
Is there something else I should be setting/checking to generate matching Session IDs on both servers?
Eventually found my answer on serverfault (why oh why are these all separate sites and user accounts?): https://serverfault.com/questions/288981/load-balanced-iis-7-5-web-server-asp-net-session-state-problem
In short: under Advanced Settings of each site in IIS, there's a numeric ID which is configurable but apparently auto-incremented from 1 in order of site creation on that server. These IDs are used in the ASPStateTempApplications table, and were different between our servers, resulting in different Session IDs.
Related
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/
We currently have an application which is used against multiple regional databases. The codebase is exactly the same but it is rolled out on the webserver in 3 different directories each with its own web.config (to hit the correct database and get correct app settings). Each with its own IIS environment.
However, my manager wants this changed i.e. One IIS application which will dynamically load up the correct web.config file for each region.
I will attempt to load the correct web.config file based on a query parameter when logging in but I have no idea on how to load the web.config file when logging in.
Anyone with experience doing this .... is there a better solution?
Based on your comment here's a different approach. You have a little work to do.
Routing all the domains to the same web site
I'm assuming you have one domain name per region (e.g. Region1.WebSite.com, Region2.WebSite.com, etc.) Combining these into one physical web site is a little tricky because of SSL certificate required. Has to match.
Two options:
Drive all three domains to the same web server via three different internal IP addresses. This means three sets of bindings in IIS and three different certs.
Use SSL offloading and terminate SSL at the load balancer. Direct all three sites to the same internal IP address on IIS. Make sure you have configured the LB to forward the original host header.
Detect where the request came from
In ASP.NET code, you can use the host header to see what domain the request was submitted over, e.g.
var siteRequested = Request.Headers["Host"];
Use the host header to pick a connection string
You will need several entries in web.config, one for each connection string. Format the name of the connection string to include the host name, so that you can obtain the right string by using something like this:
var configItemName = "ConnectionString." + Request.Headers["Host"];
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings[configItemName].ConnectionString;
Your web.config connection strings should look something like this:
<connectionStrings>
<add name="ConnectionString.Region1.WebSite.com" connectionString="Data Source=serverNameForRegion1;Et Cetera" />
<add name="ConnectionString.Region2.WebSite.com" connectionString="Data Source=serverNameForRegion2;Et Cetera" />
<add name="ConnectionString.Region3.WebSite.com" connectionString="Data Source=serverNameForRegion3;Et Cetera" />
</connectionStrings>
Store any remaining region-specific configuration in the database
Each database will have its own copy of configs, so you just need to retrieve them using the correct connection string and you'll get the right configs.
You can keep a common web.config, but then move a portion of it to a separate file, using ConfigSource. See this question for details.
Once you have some configs in a separate file, you can choose a different file at runtime:
In ASP.NET applications, at run time you can assign to the ConfigSource property the name of an alternative configuration file.
Link
CASE 1: StateServer
<system.web>
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42626" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" />
...
</system.web>
CASE 2: SQL Server
<sessionState mode="SQLServer" stateConnectionString="tcpip=127.0.0.1:42626" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" />
Question:
1. In case 1 and 2 appropriate location of sql or state server have to be configured in web.config for each of the web server in farm.
Can we have some servers configured as state and some as sql?
Can we have some cookieless and some as withcookie
Suppose if we use only <sessionState cookieless="true" />, then by default which of the modes is used? Can this be done in a multiserver farm, or is it necessary to specify the IP?
1.) Can we have some servers configured as state and some as sql?
No, you should not. Suppose when a user makes a request, then one of the server from your Web Farm will store the session in a StateServer. now in case the same user makes another request ( by clicking some links etc...), then image what will happen if your load balancer send this request to the 2nd Web server ? There will be NO session for the same user as you configured SqlServer mode for the same and the session for the user was stored on a state server on First request.
2.) Can we have some cookieless and some as withcookie ?
Again NO, for a very similar understanding as pointed above. One of the server will use cookies to track the session and the other one Cookieless ( hence URI ) to track the same session and thus, if the request gets forwarded to different servers, NO session will be detected.
3.) Suppose if we use only <sessionState cookieless="true" />, then by default which of the modes is used? Can this be done in a multiserver farm, or is it necessary to specify the IP?
Understand that this setting: cookieless="true|false", is just used to TRACK the session for a Particular user between the Client side and server side.
The Actual session DATA is there stored on SqlServer/State Server, which is defined in your mode settings as:
<sessionState mode="StateServer|SqlServer" ... />
if you don't specify any mode setting, default value of InProc is used.
Additional Note:
The Cookie or the URI have a SessionID associated with them. SessionID is a unique string, used to TRACK individual visitor between visits to website.
As a result of cookieless="true", SessionID will be embedded in all page URLs. The drawback is that you'll end up with ugly URLs, which are not so good for SEO (search engine optimization) and visitor definitely will not remember it. Here is an example URL of website which uses ASP.NET cookieless sessions:
http://samplewebsite.com/(45f8c4zyybphaw2mt3dfgnjk4j)/Home.aspx
Bolded part represents session id, which is used to recognize a visitor.
Your question is a bit vague. If you're hosting one app across multiple servers I would recommend sticking to one method. What if one user first connects to a server with one mode, and the next request is handled by another one? The session state would not be accessible/known to the other server.
As to your questions, the documentation is really quite clear.
cookieless does not affect mode. If you don't specify mode, the default is InProc. If cookieless is true, ASP will use the query string.
I have four different server and a load balancer. I want to use captcha control. I did something with it this way:
I created a handler.ashx to create the captcha image. This handler is used in the Main page. I keep the captcha control password in session while creating the captcha control. Then I compared password typed by the user with the password in the session. It works very well, but only on one server.
It doesn't run correctly with four servers. Although the user enters the correct password every time, it sometimes matches with the session password and sometimes doesn't match. I think the problem reason is this:
For Example :
A,B,C and D are the four servers. The load balancer routes the first request to A server. Which opens the main page from A server and creates password '123456'. This is stored in session on A server. Then user typed in the password and clicked button. Now the load balancer routes this request to the B server. Because session in B Sever is null, the passwords don't match.
My web.config has this,
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424"/>
But It still doesnt work.
What should I do ?
So first thing (just to make sure) - I believe that this connection string is just an example because 127.0.0.1 is localhost and it wouldn't have chance to work ;).
Now I will assume that you have chosen server A for you state server. Please check following things:
"ASP.NET State Service" is up and running on the server A (it's disabled by default, you can check that in Administrative Tools --> Services)
the stateConnectionString in servers B, C and D is "tcpip=[Server A IP Address or Network Name]:42424" (it can be 127.0.0.1 only on server A)
servers can communicate between each other using TCP/IP via port 42424 (firewalls etc.)
Please remember that if you have changed configuration of "ASP.NET State Service" on server A to not use default port (42424), you must reflect that in your connection strings.
Sometimes it's easier to configure "SQL Server Mode" instead of "State Server Mode" so you might want to consider that. You can find more details here.
You need to use StateServer or SqlServer for managing the session state and they should be out of your firewall network that is used to balance the load.
http://www.hanselman.com/blog/LoadBalancingAndASPNET.aspx
When using Session State Server, there are few things which need to setup.
Setup ASP.Net State Service on the machine which you want as a StateServer.
net start aspstate
Change Session Mode in Web.Config File for all web applications and point to a StateServer
<system.web>
<!-- ... -->
<sessionState
mode="StateServer"
stateConnectionString="tcpip=your_server_ip:42424"
cookieless="false"
timeout="20" />
<!-- ... -->
</system.web>
3 . All Web Server the use same <machinekey> configuration
<machineKey
validationKey="1234567890123456789012345678901234567890AAAAAAAAAA"
decryptionKey="123456789012345678901234567890123456789012345678"
validation="SHA1"
decryption="Auto"
/>
(Note:To maintain session state across different Web servers in the Web farm, the application path of the Web site (for example, \LM\W3SVC\2) in the Microsoft Internet Information Services (IIS) metabase must be the same for all of the Web servers in the Web farm. The case also needs to be the same because the application path is case-sensitive.
[http://support.microsoft.com/kb/325056])
I read thousand of doc but nothing work for me.
1) What I want : on my server-side I used the following variable :
(string)Session["myData"]
2) When I changed the subdomain
www.myDomain.com/myPage.aspx
OR
myDomain.com/myPage.aspx
OR
myUser.myDomain.com/myPage.aspx
My problem : I loose the Session data when I go from one of those domain to another.
3) I want to keep the session-state only with cookie and inproc mode :
<sessionState mode="InProc" cookieless="UseCookies" cookieName="myDomain.com" timeout="10000"> </sessionState>
<authentication mode="Windows"/>
I added in the web.config :
<httpCookies domain="myDomain.com" />
or
<httpCookies domain=".myDomain.com" />
or
<httpCookies domain=".myDomain.com" httpOnlyCookies="true" />
But nothing worked.
Thanks for any advices.
Short answer, you can't fulfill all of your criteria.
Possible solutions:
Redirect any request with an incoming domain of "xxx.myDomain.com" to a common "www.myDomain.com". This may involve changing "myUser.myDomain.com" to "www.myDomain.com/default.aspx?&user=myUser". Because it's a redirect, your user will see the address in his bar change, and will therefore gain some knowledge of the sausage-making behind your website (useful to attackers).
NEVER refer to your domain explicitly from within your own site. All URIs should be relative to the root of your web structure. This should allow you to avoid changing domains and thus losing your session state.
Use SQLServer to manage session state: http://support.microsoft.com/kb/2527105. This will require changing your session handling from InProc with cookies to SQLServer, as well as some other config changes.