Writing in the front

Recently, Xiaofeng met a problem at work. After a few days of thinking and exploring, she finally found the problem. She wrote this article to record it and share it with those who love learning and are willing to think.

Without further ado, let’s begin!

The problem

Xiaofeng is developing A platform recently, which is collectively called Platform A; Platform A consists of two parts:

  • The front part
  • The backend part

It can be seen that this is the development mode of front and back end separation. The formal environment of front and back end is: http://bin.ruofee.cn(. Irrespective: SN team is great, hope to hold the glory of LPL again next year. PS: The domain names in this article are fictitious. If they are similar, they are coincidental. (-) -)

Because there are many platforms in the company, considering the security of user information, it is necessary to unify the Login platform for Login status management, so there is also a unified Login platform: http://login.ruofee.cn, which is collectively referred to as the Login platform.

The login process of the platform is as follows:

  1. When the browser opens Platform A, the user status is first judged: Determine whether there is an AUTH_TOKEN (AUTH_TOKEN is A cookie set by the Login platform to the browser for Login status maintenance). If there is no AUTH_TOKEN, it means that platform A has not logged in (of course, it may have logged in, but the cookie has expired). Inform the browser to jump to the Login platform for account and password Login, such as (4); If auth_token exists, it means that platform A has already logged in and proceed to the next step.
  2. A platform for the backend interface according to the business provides an interface: http://bin.ruofee.cn/api/validate, is used to verify whether auth_token effective, effective is returned if the user’s personal information, if the invalid inform browsers skip the Login platform log back in, such as (3). / validate the logic of the interface is very simple, direct access to the Login platform provide validation of the interface we validate auth_token (http://login.ruofee.cn/auth).
  3. If the browser does not have an auth_token or if the auth_token is invalid, it will jump to the Login platform for account and password Login. When the Login is successful, the Login platform will set the new auth_token as a cookie and save it in the browser for maintaining the current Login status.

The above is the general process of platform Login. It can be seen that if the platform wants to access the unified Login service, the key point lies in whether the front end of A platform can automatically bring the cookie (auth_token) set by the Login platform when accessing the back end of A platform, so as to carry out the following auth_token verification process.

So let’s do a simple analysis:

When the Login platform is successful, the browser sets the Cookie through the set-cookie in Response Headers:

Cookie set-cookie: auth_token= XXX; domain=ruofee.cn; path=/;

As can be seen from the structure of Set-Cookie:

  • The domain of the auth_token is http://ruofee.cn, not login.ruofee.cn;
  • The path is /;

Because the auth_token domain is set to http://ruofee.cn, it will be automatically included when accessing the sub-domain of ‘or’. However, due to the restriction of the same-origin policy on cookies, there are two cases as follows:

  1. Origin: The request will be automatically carried with the corresponding cookie, no need to do other Settings;
  2. Non-homologous: Cross-domain processing is required, and Response Headers is configured as follows:
# Response Header access-control-allow-origin: Origin is the Origin Headers Headers Headers Headers Headers Headers Headers Headers Header access-control-allow-origin: Allow receiving Request Headers # to set Access-Control-Allow-Credentials: true as needed

In Ajax you need to set the WithCredentials to true as follows:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true);
xhr.withCredentials = true;
xhr.send(null); 

Access-Control-Allow-Credentials are explained as follows in MDN:

Access-Control-Allow-CredentialsHead work with
XMLHttpRequest.withCredentialsOr in the FETCH API
Request()In the constructor
credentialsOptions are used in combination. The Credentials must be configured on both the front and back ends (that is, the)
Access-Control-Allow-CredentialsHeader and XHR or Fetch Request are configured) for CORS requests with Credentials to succeed.

After the above Settings, you can automatically bring cookies!

address agreement Host Port
http://bin.ruofee.cn HTTP bin.ruofee.cn 80
http://bin.ruofee.cn/api HTTP bin.ruofee.cn 80

As can be seen from the above table, the front end and back end of A platform belong to the first situation: satisfy the same origin policy; Therefore, theoretically speaking, when the front end of A platform requests the backend interface of A platform, it will automatically bring A cookie (AUTH_TOKEN). And in fact indeed also successful, small maple therefore decided to eat a McDonald’s reward themselves. (^ __ ^)

In order to facilitate the development, Xiaofeng decided to deploy the front end of the platform to the local (it can not be developed on the server), open the service: localhost:8080.

address agreement Host Port
http://localhost: 8080 HTTP localhost 8080
http://bin.ruofee.cn/api HTTP bin.ruofee.cn 80

As can be seen from the above table, there is cross-domain between the front-end service opened locally and the back-end service online. Therefore, it is necessary to set the cross-domain correlation Headers by referring to the non-homology situation mentioned above. After all the Settings were completed, everything was normal for the local development. Cookie could be brought smoothly. Xiaofeng accelerated the pace and gradually completed the development.

At this point the reader must be depressed, said the question? Don’t worry, let’s get down to business!

On one day in May 2020, Xiao Feng opened the local front-end service as usual, ready to start a busy day, but suddenly has been repeatedly logged in; Open chrome devtools see HTTP requests, only to find that the local front end request interface (http://bin.ruofee.cn/api/validate), auth_token did not automatically take, thus the back-end judgment front platform for the unknown state, Then redirected to the Login platform to log in, the Login platform Login successful jump back to the local front end, again access interface (http://bin.ruofee.cn/api/validate), auth_token didn’t automatically bring, then redirected to the Login platform to log in again…

Xiao Feng scratched his head and began to check step by step and found that the problem was stuck in the process (5). Although the login was successful, the Response Headers returned is as follows:

Set-Cookie: auth_token=xxx; domain=ruofee.cn; path=/; 

Response Headers is normal, but there is no cookie automatically brought when requesting the backend interface. Xiaofeng got into thinking and found that there are two possibilities:

  1. Cookie is not set in the browser;
  2. Cookie is set successfully, but it is not automatically brought when the interface request due to some reasons;

In order to verify whether the cookie is successfully set in the browser, Xiao Feng first cleared all the cookies in Chrome (starting from zero) and carried out the local Login operation. At this time, the platform kept logging in repeatedly. Then, she opened the online platform A and found that platform A did not jump to the Login platform. The Login platform auth_token has been set to the browser at this time. Therefore, it can be concluded that the cookie is set successfully, but it is not automatically brought when the interface requests for some reasons. Starting from this direction to think and explore, finally found the reason!

Here, let’s first popularize the properties of cookies:

attribute describe value The default value
domain Domains specify which hosts can accept cookies. If not specified, it defaults to origin and does not include subdomains. If a Domain is specified, it typically contains subdomains Current Origin or parent Origin The current origin
path The PATH identifier specifies which paths under the host can accept cookies Any value The current path
SameSite Samesite cookies prevent Cross-Site Request Forgery (CSRF) attacks by allowing a server to require that a Cookie not be sent during a cross-site request (where a Site is defined by a registrable domain). 1. None. The browser will continue to send cookies on same-site requests and cross-site requests. If the browser is set to None, Secure must be set to True to take effect. 2. Strict. Browsers will only send cookies when visiting the same site; 3. Lax. Similar to Strict, except when the user navigates from an external site to a URL (for example, via a link). In the new version of the browser, as the default option, same-site cookies will be reserved for cross-site sub-requests, such as image loading or frames calls, but will only be sent if the user navigates to the URL from the external site. If the link link The default is null, but some browsers are LAX
Expires/Max-Age Cookie life cycle session
Secure Cookies marked as Secure should only be sent to the server over requests that have been encrypted by the HTTPS protocol true/false The default is empty
HttpOnly The document. cookie API in JavaScript cannot access cookies with the HttpOnly attribute; Such cookies only apply to the server true/false The default is empty

If you are smart enough to see the Cookie attribute above, you should already know why.

Cookies are not automatically brought when cross-site interface requests are made via Ajax when Samesite is Strict or Lax. The default value of Samesite is null, but some browsers default to “Samesite = LAX”.

Chrome 80: February 4, 2020 Updates to cookies with SameSite


Starting in Chrome 80, Cookies that don’t specify a SameSite attribute will be treated as if they were SameSite=Lax. Cookies that still need to be delivered in a cross-site context can explicitly request SameSite=None. Cookies with SameSite=None must also be marked Secure and delivered over HTTPS. To reduce disruption, the updates will be enabled gradually, so different users will see it at different times. We recommend that you test critical sites using the instructions for testing.

The Chinese translation is:

Chrome 80: February 4, 2020Update Samesite for cookies


Starting with Chrome 80, cookies that do not specify a SameSite attribute will be treated as SameSite = LAX. Cookies that still need to be passed across sites can be set to SameSite = None. Cookies with SameSite = None must also be set to Secure and sent over HTTPS. To reduce interruptions, updates will be progressively enabled, so that different users will see it at different times. We recommend that you follow the test instructions to test the key sites.

So until May 2020, cross-site cookies will still be able to carry as normal. After the Chrome update after May 2020, Chrome 80 will set the cookie’s Samesite as LAX by default. Therefore, when locally deployed platforms access cross-site online back-end interfaces, Cookies will no longer be automatically carried in HEADERS.

Here’s what SameSite=Lax does:

When sameSite = LAX, the browser sends cookies only when visiting the SameSite, except when the user navigates from an external site to a URL (for example, through a link). In the new version of the browser, as the default option, same-site cookies will be reserved for cross-site sub-requests, such as image loading or frames calls, but will only be sent if the user navigates to the URL from the external site. If the link link

In fact, if you Set cookies across sites, Chrome will even prevent set-cookies from working:

Set up a simple Node server using the Express online server and provide an interface to set cookies:

app.use('/cookie', (req, res) => { res.append('Set-Cookie', 'cookie=test_cookie; domain=ruofee.cn; path=/; '); res.send('success'); });

After solved the problems of cross-domain, platform, in the front of the local structures, access the online interface (http://bin.ruofee.cn/api/cookie), from chrome devtools – network to view the Response Headers Set – Cookie, Found to have such a paragraph:

This Set-Cookie didn’t specify a “SameSite” attribute and was defaulted to “SameSite=Lax” and was blocked because it came from a cross-site response which not the response to a top-level navigation. The Set-Cookie had to have been set with “SameSite=None” to enable cross-site usage.

The Chinese translation is:

When “sameSite” in a Set-Cookie is not Set, the default is “sameSite = LAX”, and the Set-Cookie is blocked because the Set-Cookie came from a cross-site response. If you want to Set cookies across sites, the Set-Cookie must be Set to “SameSite=None”.

Chrome Tips

Cross -site and cross-origin cross-site

  • Cross-site, meaning cross-site; Site refers to ETLD+1 (a subdomain to the left of a valid top-level domain, such as http://ruofee.cn is an ETLD+1). If the site of two URLs is different, it means cross-site.
  • Cross-origin, meaning cross domain; Origin is a combination of protocol header, host name, and port, so if one of the two URLs differs from the other, it means a cross-domain.

Post a summary of the cross-site, cross-origin article:

Understanding “same-site” and “same-origin”​web.dev

conclusion

The root cause of the repeated logins in the local environment encountered by Xiao Maple is that Chrome 80 has changed the default value of Samesite to LAX, which prevents cookies from being sent across sites. The reason Chrome has changed cookies is because of security concerns. See this article for details:

Back2Wild: Chrome’s upcoming new Cookie policy zhuanlan.zhihu.com

Samesite =Strict/Lax The user is largely protected from CSRF attacks and avoids tracking of user behavior because cookies can be sent across sites.

In summary, the Cookie default setting “SameSite=Lax” is a browser behavior and is an update to Chrome 80; Perhaps in the future, all browsers will follow suit and improve web security so that users can have real privacy. Or perhaps in the future, Chrome will go the way of Internet Explorer instead of the dragon slayer.

The solution

  1. By proxy or by modifying the Host file, change the ETLD+1 of the local front-end address to http://ruofee.cn; Cookie set to “sameSite = LAX” cannot be sent cross-site, so simply avoid cross-site.
  2. A forwarding server is built locally to forward the requests sent by the local front end to the online back-end service; Also avoid cross-site. The site of the local forwarding server and the local front-end platform are both localhost, so there is no cross-site phenomenon.
  3. Change the browser; Currently, only Chrome 80 has changed the value of Samesite by default, other browsers remain the same, so there is no case that cookies cannot be sent across sites;

At the end

Thank you for reading this book. That’s about me starting to explore cookies because I failed to log in.

“Long press thumb up can be a key three consecutive oh! “

(^ __ ^)