Why Does the Session Cookie Work When Serving from a Domain But Not When Using an Ip

Why does the session cookie work when serving from a domain but not when using an IP?

This is a "bug" in Chrome, not a problem with your application. (It may also affect other browsers as well if they change their policies.)

RFC 2109, which describes how cookies are handled, seems to indicate that cookie domains must be an FQDN with a TLD (.com, .net, etc.) or be an exact match IP address. The original Netscape cookie spec does not mention IP addresses at all.

The Chrome developers have decided to be more strict than other browsers about what values they accept for cookie domains. While at one point they corrected a bug that prevented cookies on IP addresses, they have apparently backpedaled since then and don't allow cookies on non-FQDN domains (including localhost) or IP addresses. They have stated they will not fix this, as they do not consider it a bug.

The reason "normal" cookies are working but the session cookie is not is that you are not setting a domain for the "normal" cookies (it's an optional parameter), but Flask automatically sets the domain for the session cookie to the SERVER_NAME. Chrome (and others) accept cookies without domains and auto-set them to the domain of the response, hence the observed difference in behavior. You can observer normal cookies failing if you set the domain to the IP address.

During development, you can get around this by running the app on localhost rather than letting it default to 127.0.0.1. Flask has a workaround that won't send the domain for the session cookie if the server name is localhost. app.run('localhost')

In production, there aren't any real solutions. You could serve this on a domain rather than an IP, which would solve it but might not be possible in your environment. You could mandate that all your clients use something besides Chrome, which isn't practical. Or you could provide a different session interface to Flask that does the same workaround for IPs that it already uses for localhost, although this is probably insecure in some way.

Chrome does not allow cookies with IPs for the domain, and there is no practical workaround.

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

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.

Flask-Session cookie works on other browsers for ip address & domain, but for chrome it only works on ip address

I think the problem is with how google chrome manage the cookies. It's the 'SameSite' attribute. Back on July 14th, 2020, Google started gradually rolling out a new browser policy with a few major changes. One that treats cookies as SameSite=Lax by default, if no SameSite attribute is specified. The other deprecates and removes the use of cookies with the SameSite=None attribute that did not include the Secure attribute. That means that any cookie that requests SameSite=None but is not marked Secure is now being rejected. This means that the front-end can’t contact the back-end and the site is not working. To fix it, you just need to make sure that when your _SESSION_ID cookie is created it includes the SameSite=None and Secure attributes.

P.S.1: Based on the article of Caleb. Back-end is Ruby on Rails but i don't think this is an issue.
P.S.2: Before change anything, try other chrome-based browsers like Vivaldi, Comodo or even the new Microsoft Edge.

session_start is not resuming a session when a domain is used

I've discovered the reason I'm having this issue, and I'm going to admit I did something I should not have. I modified my example to 'simplify' the question. While I posted http://local.mydev.com what I should have posted was http://local.myCompanyWebsite.com. It turns out our production website (https://myCompanyWebsite.com) also had a session going in the browser and the cookies were in conflict.

I found that modifying the domain in my hosts file, or visiting the url in an incognito window, caused the test scripts to work as expected.

I'm not sure if there's a way to get these to work together, or if it's better to just use a different domain. I did notice the dev cookies had PHPSESSID and production had __utmc. I'm not sure what causes this since both instances list PHPSESSID as session.name

Flask Session Cookies Expire Almost instantly, Can't Set Samesite Attribte

You need to use a domain name to access the service (https://domain.xxx/) and not the IP-address (https://123.123.123.213).

To avoid a lot of pain and errors, you should aim to use HTTPS, especially if you want cookies to work properly. Both the Secure and SameSite attributes requires HTTPS to work properly in most cases. And to get HTTPS to work you need a domain name and a proper certificate.

Pass a session cookie to another ip?

Cookies are based on domains, so the browser will only send the cookie back to the domain it was set on.

You get the client to send a request to the second server with data allowing the server to create a new cookie. Not sure what kind of security you need.

Why does the session cookie work when serving from a domain but not when using an IP?

This is a "bug" in Chrome, not a problem with your application. (It may also affect other browsers as well if they change their policies.)

RFC 2109, which describes how cookies are handled, seems to indicate that cookie domains must be an FQDN with a TLD (.com, .net, etc.) or be an exact match IP address. The original Netscape cookie spec does not mention IP addresses at all.

The Chrome developers have decided to be more strict than other browsers about what values they accept for cookie domains. While at one point they corrected a bug that prevented cookies on IP addresses, they have apparently backpedaled since then and don't allow cookies on non-FQDN domains (including localhost) or IP addresses. They have stated they will not fix this, as they do not consider it a bug.

The reason "normal" cookies are working but the session cookie is not is that you are not setting a domain for the "normal" cookies (it's an optional parameter), but Flask automatically sets the domain for the session cookie to the SERVER_NAME. Chrome (and others) accept cookies without domains and auto-set them to the domain of the response, hence the observed difference in behavior. You can observer normal cookies failing if you set the domain to the IP address.

During development, you can get around this by running the app on localhost rather than letting it default to 127.0.0.1. Flask has a workaround that won't send the domain for the session cookie if the server name is localhost. app.run('localhost')

In production, there aren't any real solutions. You could serve this on a domain rather than an IP, which would solve it but might not be possible in your environment. You could mandate that all your clients use something besides Chrome, which isn't practical. Or you could provide a different session interface to Flask that does the same workaround for IPs that it already uses for localhost, although this is probably insecure in some way.

Chrome does not allow cookies with IPs for the domain, and there is no practical workaround.

How do browser cookie domains work?

Although there is the RFC 2965 (Set-Cookie2, had already obsoleted RFC 2109) that should define the cookie nowadays, most browsers don’t fully support that but just comply to the original specification by Netscape.

There is a distinction between the Domain attribute value and the effective domain: the former is taken from the Set-Cookie header field and the latter is the interpretation of that attribute value. According to the RFC 2965, the following should apply:

  • If the Set-Cookie header field does not have a Domain attribute, the effective domain is the domain of the request.
  • If there is a Domain attribute present, its value will be used as effective domain (if the value does not start with a . it will be added by the client).

Having the effective domain it must also domain-match the current requested domain for being set; otherwise the cookie will be revised. The same rule applies for choosing the cookies to be sent in a request.


Mapping this knowledge onto your questions, the following should apply:

  • Cookie with Domain=.example.com will be available for www.example.com
  • Cookie with Domain=.example.com will be available for example.com
  • Cookie with Domain=example.com will be converted to .example.com and thus will also be available for www.example.com
  • Cookie with Domain=example.com will not be available for anotherexample.com
  • www.example.com will be able to set cookie for example.com
  • www.example.com will not be able to set cookie for www2.example.com
  • www.example.com will not be able to set cookie for .com

And to set and read a cookie for/by www.example.com and example.com, set it for .www.example.com and .example.com respectively. But the first (.www.example.com) will only be accessible for other domains below that domain (e.g. foo.www.example.com or bar.www.example.com) where .example.com can also be accessed by any other domain below example.com (e.g. foo.example.com or bar.example.com).



Related Topics



Leave a reply



Submit