Asp.Net Core - Prevent Session cookie conflict between same domain applications - asp.net

I'm using ASP.Net Core 2.2.
By default, session cookie is stored in a cookie named .AspNetCore.Session on a specific domain (e.g: mydomain.com).
In my case I have multiple .net core applications under the domain. mydomain.com/Module1, mydomain.com/Module2, etc...
With this scenario, all the applications share the same cookie for their session. The consequence is that an application try to read the session of the other and generate a warning in the logs:
Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key {...} was not found in the key ring.
Although It's just a warning and session seems to working fine on each application, I wanted to know the proper way to handle this situation.
Thx.

A solution that I've found is to change the session cookie name for each application:
In Startup / Configure() :
app.UseSession(new SessionOptions() { Cookie = new CookieBuilder() {
Name = ".AspNetCore.Session.MyApp1"}});

When you have .AddAuthentication defined in Startup / ConfigureServices(), to fix this add cookie options this way. Worked for my case.
services.AddAuthentication(CookieScheme) // Sets the default scheme to cookies
.AddCookie(CookieScheme, options =>
{
options.LogoutPath = "/logout";
options.LoginPath = "/login";
options.Cookie = new CookieBuilder()
{
IsEssential = true,
SameSite = SameSiteMode.Lax,
SecurePolicy = CookieSecurePolicy.SameAsRequest,
Name = ".AspNetCore.Session.yourAppName"
};
});

Related

Net Core 6: Session ID Changes After Redirect to AuthenticationHandler.AuthenticateAsync()

:: Using A Custom DistributedCache (Redis Implementation) ::
On all Redirect(url) calls, the session changes. I know the official MS Docs says that IAuthenticationHandler "Created per request to handle authentication for a particular scheme". Meaning even redirects cause a new session
public async Task<AuthenticateResult> AuthenticateAsync() { }
The issue I am having is that during the new session ALL CONTEXT is lost. Everything I saved in the Context (including the ClaimsPrincipal of the user) gets lost. I cannot even fetch transients or singletons attached to my service through:
var SessionProvider = Context.RequestServices.GetService(typeof(ISessionProvider)) as SessionProvider;
Because there is no context. Here is the implementation I followed::
ASP.NET Core 2.0 authentication middleware
Please guide me on any assistance on how to persist Session during AuthenticationAysnc() calls.
Edit :: Here is my service code
service.AddAuthentication(options => {
options.DefaultAuthenticateScheme = "CoreAuthScheme";
options.DefaultChallengeScheme = "CoreAuthScheme";
options.DefaultScheme = "CoreAuthScheme";
}).AddCustomAuth(o => {})
And With Web App
//Register Session Security (Goes before Routing)
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
Thank you
Solution ::
Proper Implementation of these two library srcs are needed if you are using a custom IDistributedCache. Obviously The IDistributedCache here is Redis Implementation, but the same goes for SQL, and other DB caching (get the proper src implementation of IDistributedCache)
Session Management
https://github.com/dotnet/aspnetcore/tree/c85baf8db0c72ae8e68643029d514b2e737c9fae/src/Middleware/Session/src
IDistributedCache (Redis)
https://github.com/dotnet/aspnetcore/tree/c85baf8db0c72ae8e68643029d514b2e737c9fae/src/Caching/StackExchangeRedis/src
The reason why I was losing session is because the default implementation of DistributedSession uses Offsets and special encodings to process values returned from the IDistributedCache Redis I implemented. See below:
DistributedSession.Deserialize(...)
var expectedEntries = DeserializeNumFrom3Bytes(content);
_sessionIdBytes = ReadBytes(content, IdByteCount);
for (var i = 0; i < expectedEntries; i++)
{
var keyLength = DeserializeNumFrom2Bytes(content);
var key = new EncodedKey(ReadBytes(content, keyLength));
var dataLength = DeserializeNumFrom4Bytes(content);
_store.SetValue(key, ReadBytes(content, dataLength));
}
Once you have those two libraries properly sourced and implemented. Session Management Works :). AuthenticateAsync calls the Distributed Session which calls DistributedCache and data is properly serialized and deserialized
----------------------------------------------------------- alimaslax

ASP.Net Cannot set cookie with SameSite=None

I'm using MVC5 on IIS with .NET Framework 4.8.
I have the latest quality rollup installed(1) which is supposed to resolve some issues with samesite cookies.
I create three cookies as follows:
var now = DateTime.Now.ToLongTimeString();
var expiry = now.AddSeconds(30);
var cookieSameSiteNone = new HttpCookie("My.SameSite.None", $"sameSite None [{now}]")
{
Secure = true,
SameSite = SameSiteMode.None,
Expires = expiry
};
var cookieSameSiteLax = new HttpCookie("My.SameSite.Lax", $"sameSite Lax [{now}]")
{
Secure = true,
SameSite = SameSiteMode.Lax,
Expires = expiry
};
var cookieSameSiteStrict = new HttpCookie("My.SameSite.Strict", $"sameSite Strict [{now}]")
{
Secure = true,
SameSite = SameSiteMode.Strict,
Expires = expiry
};
Response.Cookies.Add(cookieSameSiteStrict);
Response.Cookies.Add(cookieSameSiteLax);
Response.Cookies.Add(cookieSameSiteNone);
These cookies are set in the Application_EndRequest of the Global.asax. The application also uses OWIN for authentication.
Using FireFox (v72.0.2) I get the following cookies:
Note the cookie where SameSite was set to None has been received as "Unset"
Any idea how to set a cookie with SameSite=None?
I have seen other SO questions that suggest applyin patches to the .NET Framework(2), but I already have these installed
(1) https://support.microsoft.com/en-gb/help/4534132/kb4534132-cumulative-update-for-net-framework
(2) How to set SameSite cookie attribute to explicit None ASP NET Core
This may be an issue with FireFox's display of Cookies. Chrome does not appear to suffer with the same problem.
I've logged a bug with Mozilla(1).
(1) https://bugzilla.mozilla.org/show_bug.cgi?id=1613622

How do I issue the corresponding Bearer and Cookie identity in ASP.NET with multiple Authorization schemes?

This documentation describes in part how to use more than one authentication scheme:
In some scenarios, such as Single Page Applications it is possible to end up with multiple authentication methods. For example, your application may use cookie-based authentication to log in and bearer authentication for JavaScript requests. In some cases you may have multiple instances of an authentication middleware. For example, two cookie middlewares where one contains a basic identity and one is created when a multi-factor authentication has triggered because the user requested an operation that requires extra security.
Example:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "Cookie",
LoginPath = new PathString("/Account/Unauthorized/"),
AccessDeniedPath = new PathString("/Account/Forbidden/"),
AutomaticAuthenticate = false
});
app.UseBearerAuthentication(options =>
{
options.AuthenticationScheme = "Bearer";
options.AutomaticAuthenticate = false;
});
However it only describes how to use Bearer or Cookie auth. What isn't clear is what other combinations are valid, or how to properly issue bearer or cookies to the client.
How can that be accomplished?
One common use case for this which large sites like Facebook, Google etc. use is to use multiple cookie authentication middleware's and set one of them to be the default using AutomaticAuthenticate
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "InsecureLongLived",
LoginPath = new PathString("/Account/Unauthorized/"),
AccessDeniedPath = new PathString("/Account/Forbidden/"),
AutomaticAuthenticate = true
});
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "SecureAndShortLived",
LoginPath = new PathString("/Account/Unauthorized/"),
AccessDeniedPath = new PathString("/Account/Forbidden/"),
AutomaticAuthenticate = false
});
The default one is long lived and used for non-critical auth scenarios e.g. on Facebook, this may be to view your profile page.
The more secure and short lived on is used for security critical user actions like changing your password or profile information.
This gives you the convenience of not having to login all the time with a long lived cookie but as soon as you need to do something potentially dangerous, you switch to doing auth with a much shorter lived and thus more secure cookie which requires the user to login again.

ASP .NET Core Cookie Authentication expiration changes from timestamp to "Session" upon return

I am using ASP .NET Core RC1 with Facebook-authentication and silding window cookie expiration set up like this:
app.UseIdentity();
app.UseFacebookAuthentication();
and
services.AddIdentity<ApplicationUser, IdentityRole>((options =>
{
options.Cookies.ApplicationCookie.CookieName = "myauthcookie";
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(5);
options.Cookies.ApplicationCookie.SlidingExpiration = true;
}))
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
This works fine when the user first logs in - the cookie expiration is set correctly. However, when the user returns to the page, the expiration of the cookie is set to "Session", so in practice the user has to re-authenticate every other visit.
Why is this happening? Have I not configured it correctly?
Update:
I have now done some testing without SlidingExpiration, and the issue remains the same. Upon returning to the page, the expiration of the cookie is changed to "Session". I am using Chrome.
Also, I am not running on https. Might this be a factor?
Short Answer
Set isPersistent: true when calling SignInManager.ExternalLoginSignInAsync.
Details
In the ASP.NET Core Web Application template, the AccountController.ExternalLoginCallback method contains this code:
_signInManager.ExternalLoginSignInAsync(
info.LoginProvider,
info.ProviderKey,
isPersistent: true); <------ set a persistent cookie.
If we set isPersistent: true when calling ExternalLoginSignInAsync , this startup configuration...
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Cookies.ApplicationCookie.CookieName = "MyApplicationCookie";
options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(5);
options.Cookies.ApplicationCookie.SlidingExpiration = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
...results in this application cookie...
...which persists across browser sessions.

Dot Net Client and IIS hosted SignalR with Win auth

Is there a way to configure the .NET client so that it will work with a IIS hosted SingalR that uses Windows authentication?
If I disable windows authentication it works, but this is not an option
setting connection.Credentials = CredentialCache.DefaultCredentials does not help.
The code
public EventProxy(IEventAggregator eventAggregator, string hubUrl)
{
typeFinder = new TypeFinder<TProxyEvent>();
subscriptionQueue = new List<EventSubscriptionQueueItem>();
this.eventAggregator = eventAggregator;
var connection = new HubConnection(hubUrl);
connection.Credentials = CredentialCache.DefaultCredentials;
proxy = connection.CreateHubProxy("EventAggregatorProxyHub");
connection.Start().ContinueWith(o =>
{
SendQueuedSubscriptions();
proxy.On<object>("onEvent", OnEvent);
});
}
ContinueWith triggerst directly after Start and when the first subscription comes in I get a
The Start method must be called before data can be sent.
If I put a watch on the DefaultCredentials I can see that Username, Domain and Password are all String.Empty. Its a standard Console program, Enviroment.Username returns my username
Sure, set connection.Credentials = CredentialCache.DefaultCredentials. More details about credentials here http://msdn.microsoft.com/en-us/library/system.net.credentialcache.defaultcredentials.aspx.

Resources