How can I share cookies between two subdomains of herokuapp.com? - heroku

I am currently trying to host a website as an experiment on Heroku, I deployed the back end which you can consider yyyy.herokuapp.com and the front end with you can consider xxxx.herokuapp.com,
Now, here's the issue, I need to set cookies between xxxx and yyyy, I know this will be a massive security issue but since this is an experimental website I am not willing to get a custom domain, I tried to set the cookies' domain to: herokuapp.com, .herokuapp.com, *.herokuapp.com, xxxx.herokuapp.com, yyyy.herokuapp.com.
Yet it doesn't work, chrome denies the cookies and gives this message:
This attempt to set a cookie via a Set-Cookie header was blocked because its Domain attribute was invalid with regards to the current host url.
So, how do I approach this issue without the need for a custom domain?
this is my configuration to set cookies (on the back end which uses flask)
response.set_cookie("example_cookie", value="cookie value",
max_age=900, expires=datetime.datetime.utcnow() +
datetime.timedelta(seconds=900), secure=True, domain=".herokuapp.com",
samesite='none')

If herokuapp.com were not a public suffix (a.k.a. an effective top-level domain or eTLD), then in the case of a cookie set by xxxx.herokuapp.com with Domain=herokuapp.com, browsers would send that cookie to yyyy.herokuapp.com
However, there is a snag: in order to isolate its different tenants, Heroku required herokuapp.com be added to the public-suffix list a while back. Most browsers refuse to set a cookie for a public suffix:
For security reasons, many user agents are configured to reject Domain attributes that correspond to “public suffixes”. For example, some user agents will reject Domain attributes of “com” or “co.uk”.
Therefore, attempts to set a cookie with Domain=herokuapp.com will be rejected by browsers, as you've experienced.
Note: adding a leading dot in the Domain attribute of the Set-Cookie HTTP header has no effect, at least in modern browsers.
To get out of this difficulty, you could simply buy a cheap domain name (say infinityvive.com) to serve both your frontend and backend from subdomains of it. Then you'd be able to use Domain=infinityvive.com because your domain would not be a public suffix.

Related

How do I set cookies within Heroku Review App?

I am managing two separate apps through two different Heroku pipelines.
App 1 - Handles my auth, this is a login landing page.
App 2 - The main app, can access after authenticating via App 1.
I have separate review apps running for each app. The reasoning was so I can have both Review
Apps under the .herokuapp.com domain.
App 1 takes Username, Password, and sets a JWT. In App 1, a query param is set and it contains a callbackUrl to App2. The JWT is set as a cookie in App 1 and sent to App 2 via a cookie (a token).
This is a problem with the new Same-Site Rules in Chrome. However, I have read various articles and workarounds for this, and my Cookies are still blocked. Here is the error:
the Set-Cookie was blocked because its domain attribute was invalid with regards to the current host url.
I believe they are blocked because the domain .herokuapp.com is on the Public Suffix List, so no matter what I do, they will always be blocked.
Is there a workaround for this? Can I use my own domain with a review app? Ideally:
app1.helloworld.com
app2.helloworld.com
.helloworld.com would be the domain.
Indeed they are blocked due to the domain being on suffix.
But you can block chrome from registering that you are on the suffix list through creating a library with automated deployments similar to hstspreload and then also providing a mechanism that any HTTP library can update the packaged list via their own fetching mechanism.
sadly you cannot reliably exclude .herokuapp.com from the suffix list or any other website for that matter.
for those wanting to see more about attempting to remove from suffix, here are the pros and cons and other theorized attempts:
https://forum.blocsapp.com/t/remove-html-suffix/1643

Share session across subdomains with multiple domains

I have 2 Asp.Net Core 2.2 applications and I want to share session between them.
I've set up session in a SQL database and both connect ok.
They are on different sub domains.
I understand that I can set the Cookie.Domain the startup file, which would solve the problem at a basic level, so each application would create the cookie such that it can be accessed.
e.g.
Domain 1. "www.website.com"
Domain 2. "dashboard.website.com"
At present these sites can't access each others session cookie.
If I set the domain cookie to ".website.com", both should be able to access this.
The problem is that we have multiple domains that use this website, so it could be:
www.domain1.com
dashboard.domain1.com
www.domain2.com
dashboard.domain2.com
www.domain3.com
dashboard.domain3.com
I need to be able to inject the current host name into the startup cookie domain, in order to have it dynamically set, depending on the domain of the active website.
Is this at all possible?
Thanks in advance,
David
No, it's not possible. Cookies are domain-bound. You can set a wildcard for the subdomain portion on the cookie, which would then allow it to be seen by example.com, www.example.com, foo.example.com, etc. but you can cannot share with an entirely different domain altogether, such as example2.com.
Your only option in this case is an Identity provider like IdentityServer, Auth0, Azure AD, etc. The way these work is that the auth cookie is set at the provider, and then each individual app is authorized against that provider. As such, they can receive the user principal from the provider, without having the actual auth cookie or their own login functionality.
UPDATE
If you just need to share between sites on the same primary domain, then follow the instructions in the docs. That's focused on auth cookies. If you need to share sessions as well, the same procedure applies, but you must additionally have a true distributed cache setup (Redis, SQL Server, etc.). There's a distributed memory cache, but that's just a default implementation, and it's not actually distributed.

Session is specific to what? Why not treat ip and domain name session as same?

I want to know session is specific with what? This is not restrict to one language. Bellow is just use php as an example.
I use php session, it works well when I use the my website domain name. To test the website in my local vmvare ubuntu on the windows OS, I change the hosts of my windows to make the DNS to my local ip. When testing local, I use domain name, it also works well. But when I change the url in the browser to Ip, the session is lost.
You may confuse why I do this, because I want to also test the page on my android device, for I cannot change my android device's hosts file without android root, so I have to use ip.
You may also confuse why I not use the ip all the way? Because I use a third open login in my web app. The third open login mast use the domain name as the redirectback url, so when I loged in, it will redirect to the url in the domain name format.
Why the php session is the same when the domain name and the ip?
To make sure php session is not the same with domain name and ip? I also tryed my admin system, upper is user system.
I also try my administration system, I can use ip to login all the way. But when I change ip to the domain name in the url, the session also lose.
Since you mention PHP, I'll include information from PHP manual.
I believe other languages behave similarly.
In the server, a session is specific to a cookie.
From PHP manual:
Session IDs are normally sent to the browser via session cookies and the ID is used to retrieve existing session data. The absence of an ID or session cookie lets PHP know to create a new session, and generate a new session ID.
In the user agent (the client, usually a browser), a cookie is specific to a domain and path.
From RFC6265, section 4.1.2.3:
The Domain attribute specifies those hosts to which the cookie will be sent. For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com.
Section 4.1.2.4:
The user agent will include the cookie in an HTTP request only if the path portion of the request-uri matches (or is a subdirectory of) the cookie’s Path attribute, where the %x2F ("/") character is interpreted as a directory separator.
So, if you move back and forth from domain name to IP address, for instance, example.com and 12.34.56.78,
a session cookie created by the server for example.com will not be sent back by the user agent
if you later make a request to 12.34.56.78, even if both are the same server.
With the later request, because the server sees no session cookie, a new session is created and a new cookie is sent.
That's why using both domain name and IP address will use separate sessions.
If you need to use the same session when using both domain name and IP address, you have to preserve the session ID between requests.
A common method is to pass the session ID in the query string.
PHP session management, in fact, can also be configured to use this method but I never need to use it, so I can't tell you how that's gonna go.
Continuing my example, you can use this for subsequent requests:
http://12.34.56.78/?sessionId=abcdef0123456789
Where abcdef0123456789 is an example session ID.
In the PHP code, set the session ID before calling session_start().
Example code:
if(isset($_GET['sessionId']))
session_id($_GET['sessionId']);
#session_start();
Of course, you don't have to use sessionId.
You can use foobar or anything else.
You can also change it daily or even hourly to prevent session hijacking.
Update: To use foobar, modify the PHP code to this:
if(isset($_GET['foobar']))
session_id($_GET['foobar']);
#session_start();
With that code, you can pass the session ID like this:
http://12.34.56.78/?foobar=abcdef0123456789
If you want to use xyz, the PHP code would be:
if(isset($_GET['xyz']))
session_id($_GET['xyz']);
#session_start();
You can pass the session ID like this:
http://12.34.56.78/?xyz=abcdef0123456789
The point is, it is really up to you.
The reason of this behavior is the following:
When a session is created, its session id is stored in a cookie. The value of the cookie is sent by the server in the HTTP field Set-Cookie.
At the next request from the client to the server, this session id is sent back to the server in the HTTP field Cookie. But the user agent (browser) should send the cookie only under certain conditions. Basically the domain stored with the cookie must match with the domain of the server. But in fact, the rule is much more complex and is defined in the RFC 6265 as follow:
The user agent MUST use an algorithm equivalent to the following
algorithm to compute the "cookie-string" from a cookie store and a
request-uri:
Let cookie-list be the set of cookies from the cookie store that
meets all of the following requirements:
Either:
The cookie's host-only-flag is true and the canonicalized
request-host is identical to the cookie's domain.
Or:
The cookie's host-only-flag is false and the canonicalized
request-host domain-matches the cookie's domain.
The request-uri's path path-matches the cookie's path.
If the cookie's secure-only-flag is true, then the request-
uri's scheme must denote a "secure" protocol (as defined by
the user agent).
NOTE: The notion of a "secure" protocol is not defined by
this document. Typically, user agents consider a protocol
secure if the protocol makes use of transport-layer
security, such as SSL or TLS. For example, most user
agents consider "https" to be a scheme that denotes a
secure protocol.
If the cookie's http-only-flag is true, then exclude the
cookie if the cookie-string is being generated for a "non-
HTTP" API (as defined by the user agent).
If you have not the courage to read all the RFC6265 and related RFC's, you can make some experiments in your browser and look at the HTTP headers and the stored cookies in different situations. In Firefox, you can observe this, by :
hitting CTRL+SHIFT+K
click on the network tab
reload the page
click on a request

Use Sinatra session variables across multiple domain names?

I'm building a Sinatra app which needs to use a session variable for one very specific thing. The session variable is set when the user is looking at an SSL enabled page.
I'm using Heroku's piggyback SSL, so the SSL url is something like https://myapp.heroku.com
However, the app itself is hosted at my url, myapp.com
Is there a way to make my session variable, which is set while on the ssl / heroku domain name, available to my app while while on my domain name?
Unfortunately no, since the cookie is tied to the domain. What you'll have to do is either allow authenticated users to use the https://foo.heroku.com domain, and reserve your nice domain for the landing page & other unauthenticated pages.
That, or pay $20 for heroku's SSL add-on.
(I ran into this exact problem in http://appkickstand.com and I chose to just deal with the heroku url for logged in users)
You should look for cross-domain cookies manuals, check this.
But i don't see many reason in setting cookie through secured channel and transmitting it later via raw HTTP, where everyone could sniff it.

ASP .NET Cross Site Forms Authentication works in Dev but not production

I have two MVC3 sites, both hosted on the same server that I've configured to use the same authentication cookies.
The first site is an intranet site using Windows authentication. This site has one simple Action that checks to see if the user was authenticated, if the user has been, it creates a FormsAuthentication cookie that it adds to the response. This cookie is created for a generic user that I determine from the User's AD groups. The response then redirects the user to a second site that uses Forms Authentication.
When I run this on my local machine, everything works as described above. When I deploy this to our local web server, it doesn't. I've tested to see if the user's group is correctly determined and that it creates a valid user for the cookie, and I have verified that this is correct on the web server.
Here is how I'm doing all of the above:
First, I made both sites use the same same Machine Key for encryption and decryption.
When I create the cookie in Site1, I ensure that it has the same name and Domain as the cookies created on Site2.
var cookie = FormsAuthentication.GetAuthCookie(userName, false);
cookie.Domain = FormsAuthentication.CookieDomain; //This is the Domain of my 2nd site as they are different
HttpContext.Response.Cookies.Add(cookie); //Add my cookie to the response
HttpContext.Response.RedirectPermanent(urlForSite2);
Again, when I run this on my local machine it works without a problem. But when deployed, it's either not passing the cookie in the request, or the response is ignoring it, but I'm not sure how to verify either of these cases.
Feel free to ask any question regarding more details as to how I'm doing this if it will help in getting an answer I need.
Cross domain cookies are not allowed. If you have two separate domains; one cannot access the others cookies. Two separate virtual directories/applications will work when using the same machine key. http://blogs.technet.com/b/sandy9182/archive/2007/05/07/sharing-forms-cookie-between-asp-net-web-application.aspx
If you want to share login cookies between sub-domains you need to edit the Domain property of the login cookie to the 2nd level domain "abc.com" so that "www.abc.com" and "ww2.abc.com" will have access to the cookie. http://forums.asp.net/t/1533660.aspx
String usrName = User.Identity.Name.ToString();
HttpCookie authCookie = Security.FormsAuthentication.GetAuthCookie(usrName, false);
authCookie.Domain = "abc.com";
Response.AppendCookie(authCookie);
Actually, it is possible, but isn't as simple as the domain/sub-domain cookie sharing.
http://www.codeproject.com/KB/aspnet/CrossDomainSSOModel.aspx
While the example given in this article didn't apply directly to what I was doing, I could use some of the ideas expressed there to get what I needed working. It ended up being my configuration settings in site2 web.config.
My URLs are as follows
Site1 = http://site.stage
Site2 = http://site.stage.MyCompanyName.com
Site 1 requires a host entry addressing it to a specific IP address of the hosting machine. It's also an entry in my IE Security settings - Local Intranet Sites.
I should note that these applications are both virtual directories running under the same default website.
I thought I had solved my problem but setting the Domain in the config file to and empty string, but this didn't work. I'm not sure what can be done now. This still works when I run it on my local machine, but not when I run it on my server. The only difference is the urls.
My dev machine is using the urls
Site 1: http://localhost/CompanyName.TVAP.IntranetSite
Site 2: http://localhost/TVAPDev/
I hope this adds some clarification. This Answer should really be posted as an edit to my question, but when I originally posted it, I thought I had it working.
UPDATE: I think my answer is in my URLs above. My dev machine URLS both are using the same domain name, which in this case is localhost. I think if I alter my deployed websites to use the same domain, I will be OK. I'll post an update when I get it worked out.

Resources