What is cross-domain?

1. First you need to understand the same-origin policy

The same origin policy is the core and basic security function of the browser. It refers to the same protocol, domain name, and port. Even if two different domain names point to the same IP address, they are not of the same origin. Without the same origin policy, browsers are more vulnerable to XSS, CSRF, and other attacks.

The same origin policy limits the following contents

  • LocalStorage, IndexedDB and other storage contents are segmented by source. Each source has its own storage space, and Javascript scripts in one source cannot read or write data belonging to other sources. Cookies are more special. A page can set cookies for the local field and any parent field, as long as the parent field is not a public suffix. So when a homologous web page reads a cookie, it doesn’t know where it came from.
  • DOM not available
  • AJAX request failed to be sent (it could be sent, but the browser blocked it)

There are exceptions where resources can be loaded across domains

  • <script src="..." ></script>But syntax error messages can only be captured in the same origin script.
  • <link rel="stylesheet" href="..." >Tags are embedded in CSS.
  • <img>Embed images. Supported image formats include PNG,JPEG,GIF,BMP,SVG…
  • < video > and < audio >Embed multimedia resources.
  • @font-faceIntroduced fonts.
  • The < frame >, and < iframe >Any resources loaded.
  • The < object >, < embed > and < applet >The plug-in.

2. Common cross-domain scenarios

If a protocol, subdomain name, main domain name, or port number is different, the domain name is counted as different. Requests for resources between different domains are “cross-domain.” The common cross-domain scenarios are as follows:

Two points in particular:

  • If protocols and ports are causing cross-domain problems, the “foreground” cannot help.
  • For cross-domain problems, only the “head of URL” is used to identify the domain name rather than whether the CORRESPONDING IP address is the same. The protocol, domain name and port must match. And just because your two domain names map to the same IP at the same time, you are not considered the same source, you are still different sources!

The request is cross-domain, so is the request sent at all?

Cross-domain does not mean that the request cannot be sent out, the request can be sent out, the server can receive the request and return the result normally, but the result is blocked by the browser. You may be wondering why Ajax can’t make cross-domain requests when you can make them with forms. Because ultimately, cross-domain is about preventing the user from reading content under another domain name, Ajax can get a response that the browser considers unsafe, so it blocks the response. But the form doesn’t get new content, so it can make a cross-domain request. It also shows that cross-domain does not prevent CSRF completely, because the request is made after all.

What exactly are CSRF and XSS?

  • CSRF attack: An attacker steals your identity and sends malicious requests on your behalf. For example, the front end constructs a malicious page, collects sensitive information from the server side of the trusted website, and then requests the user to trust the website interface. So the server will mistake the malicious page for the user, and then… Solution: Verify the source of the invocation of the interface (Referer), the server determines whether the Referer is whitelisted, or deploy random tokens to defend against it.
  • XSS holes:The page was injected malicious code by attackers, data leakage

    For example: not rigorouscontent-typeCause XSS vulnerability, imagine JSONP is what you requesthttp://youdomain.com?callback=douniwanAnd then returndouniwan({ data })If requesthttp://youdomain.com?callback=<script>alert(1)</script>Don’t return<script>alert(1)</script>({ data })Is it? If it’s not strictly definedContent-type (content-type: application/json), with no filter callback arguments, it is a naked XSS when the HTML is parsed.

    Solution: strictly define content-Type: application/json, then strictly filter the parameters after callback and limit the length (character escape, e.g. < < for &lt, > for &gt), so that the script Content returned will be text format and the script will not be executed. And for link jumps, such as< a href = "XXX" or location. The href = "XXX", to test its contents, prohibit tojavascript:Opening links, and other illegal onesscheme.

Cross-domain solutions

1.CORS

CORS requires both browser and backend support. Internet Explorer 8 and 9 need to be implemented through XDomainRequest. The browser will automatically carry out CORS communication, the key to achieve CORS communication is the back end. As long as the backend implements CORS, cross-domain is achieved. To enable CORS, set access-Control-allow-Origin on the server. This attribute indicates which domain names can access resources. If a wildcard is set, all websites can access resources. Although setting up CORS has nothing to do with the front end, solving cross-domain problems in this way can result in two cases of simple and complex requests being sent.

A simple request

It is a simple request condition 1 if both conditions are met: use one of the following methods:

  • GET
  • HEAD
  • POST

Condition 2: The value of the content-Type is limited to one of the following:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

Or none of the XMLHttpRequestUpload objects in the request are registered with any event listeners; The XMLHttpRequestUpload object can be accessed using the xmlHttprequest.upload attribute.

Complex request

A request that does not meet these criteria is definitely a complex request. Because most of our Content-Types are application/ JSON, most of our daily requests are complex. CORS requests for complex requests add an HTTP query request, called a “precheck” request, before formal communication. The browser first issues the OPTIONS method to the server to know if the server will allow the actual request.

So with all of this, let’s do the last example

InitPost () {// Common requests require cross-domain say({callback: "dudu" }).then(data => (console.log(data))); }Copy the code
// cors. Js (node) let express = require("express"); let app = express(); let whitList = ["http://localhost:8088"]; Use (function(req, res, next) {let origin = req.headers. Origin; Res.setheader (" access-Control-allow-origin ", origin); if (whitlist.includes (origin)) {// If (whitlist.includes (origin)) {// If (whitlist.includes (origin)); Res. setHeader(" access-Control-allow-headers ", "sessionno"); * res.setheader (" access-control-allow-methods ", "GET"); SetHeader (" access-Control-allow-credentials ", true); Res.setheader (" access-Control-max-age ", 6); Res. setHeader(" access-Control-expose-headers ", "sessionno"); if (req.method === "OPTIONS") { res.end(); } else {next(); }}}); app.get("/say", (req, res) => { let { wd, callback } = req.query; console.log(wd); console.log(callback); res.setHeader("sessionno", "sakura"); Res.end (' ${callback}('hello world') '); }); app.use(express.static(__dirname)); app.listen(3000);Copy the code

The above code from http://localhost:8088/index.html to http://localhost:3000/ cross-domain request, as we mentioned above, the backend is the key to the realization of CORS communication.

2. Nginx reverse proxy

Implementation principle: build a relay NGINx server for forwarding requests.

Nginx reverse proxy is the simplest way to cross domains. Nginx only needs to change the configuration to solve the cross-domain problem, support all browsers, support sessions, no code changes, and do not affect server performance.

Nginx is used to configure a proxy server (the domain name is the same as that of Domain1, but the port is different) as a jumper. The reverse proxy accesses the interface of Domain2.

Nginx/nginx/nginx/nginx/nginx/nginx/nginx/nginx.conf

# proxy server
    server {
        listen 81;
        server_name localhost;

        #charset koi8-r;

        #access_log logs/host.access.log main;Location / {proxy_pass http://10.1.21.20:4444/;# Reverse proxy
            index index.html index.htm;
            # When accessing Nignx using middleware proxy interfaces such as Webpack-dev-server, there is no browser participation, so there is no source restriction, the following cross-domain configuration can not be enabled
            add_header Access-Control-Allow-Origin http://localhost:8088; # If the current end is cross-domain only without cookies, the value can be *
            add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
            add_header Access-Control-Allow-Credentials true; }}Copy the code

Restart nginx on nginx -s reload (or start nginx)

// index.html
// nginx
initNginx() {
    let xhr = new XMLHttpRequest();
    xhr.withCredentials = true; // Whether the browser reads and writes cookie xhr.open("get"."http://localhost:81/? user=admin".true);
    xhr.send();
    let that = this;
    xhr.onload = functionConsole.log (data) {console.log(data); console.log(data.currentTarget.response); that.nginx = data.currentTarget.response; }; }Copy the code
// nginx.js (node side)let http = require("http");
let server = http.createServer();
let qs = require("querystring");
let count = 0;
server.on("request", (request, response) => {
    var params = qs.parse(request.url.substring(2));
    console.log(params);
    response.write(JSON.stringify(params) + count++);
    response.end();
});
server.listen("4444");
console.log("Server is running at port 4444...");

Copy the code

3.Node middleware proxy (cross domain twice)

Implementation Principle: The same origin policy is a standard that the browser must comply with. However, the same origin policy is not required if the server requests the same origin policy to the server.

The principle is similar to nginx reverse proxy

For proxy servers, you need to do the following steps:

  • Accept client requests.
  • Forwards the request to the server.
  • Get the server response data.
  • The response is forwarded to the client.

Next we use the interface used in daily work through the proxy server to our backend server!

// index.html // Node middleware forward_msgSend() {
    const params = {
    	mobile: "13333333333",
    	tmCode: "3001"
    };
    msgSend(params).then(res => {
    	console.log(res);
    });
},
Copy the code
// middleware.js (node) const HTTP = require("http"); Const server = http.createserver ((request, response) => { Response. writeHead(200, {"Access-Control-Allow-Origin": "*"."Access-Control-Allow-Methods": "*"."Access-Control-Allow-Headers": "Content-Type, sessionno"}); console.log(request.url); // Step 2 forward the request to the server const proxyRequest = http. request({host:"xxx.xxx.xxx.xxx", port: 8082, url: request.url, path: request.url, // You must set path method: request.method, headers: Request. Headers}, serverResponse => {// Step 3 Receive a response from the server. Var body ="";
                serverResponse.on("data", chunk => {
                    console.log("Receive");
                    body += chunk;
                });
                serverResponse.on("end", () => {// Step 4 forward the response result to the browser console.log(body); response.end(body); }); } ) .end(); }); server.listen(3000, () => { console.log("The proxyServer is running at http://localhost:3000");
});

Copy the code

The code crosses domains twice, once when the browser sends the request to the proxy server, and the second time when the proxy server forwards the response to the browser

4.JSONP

The json principle

Web pages can get JSON data dynamically generated from other sources by taking advantage of the

JSONP vs. AJAX

JSONP, like AJAX, is a way for a client to send a request to the server and get data from the server. But AJAX is a same-origin policy, JSONP is a non-same-origin policy (cross-domain request)

The json pros and cons

JSONP has the advantage of simple compatibility and can be used to solve the problem of cross-domain data access in mainstream browsers. The disadvantage is that only support for get methods is limited and insecure and may be subject to XSS attacks.

JSONP implementation process

  • Declare a callback function whose name (such as show) is passed as a parameter value to the server requesting data across domains, and whose parameter is to fetch the target data (the data returned by the server).
  • To create a<script>Tag, which assigns the address of the cross-domain API data interface to script SRC, and passes the function name to the server at that address:? callback=show).
  • When the server receives the request, it needs to do something special: concatenate the name of the function passed in with the data it needs to give you into a string, for example: the name of the function passed in is show, and the data it prepares isShow (' I don't love you ').
  • Finally, the server returns the data to the client through HTTP protocol, and the client invokes and executes the previously declared callback function(show)To operate on the returned data.

During development, you may encounter multiple JSONP requests with the same callback function name, and you may need to wrap your own JSONP function.

// index.html

// JSONP
jsonp({ url, params, callback }) {
    return new Promise((resolve, reject) => {
    	let script = document.createElement("script");
    	window[callback] = function(data) { resolve(data); document.body.removeChild(script); }; params = { ... params, callback }; // wd=b&callback=showlet arrs = [];
    	for (let key in params) {
    		arrs.push(`${key}=${params[key]}`);
    	}
    	script.src = `${url}?${arrs.join("&")}`;
    	document.body.appendChild(script);
    });
},

// init
initJsonp() {
    this.jsonp({
    	url: "http://localhost:3000/say",
    	params: { wd: "Iloveyou" },
    	callback: "show"
    }).then(data => {
    	console.log(data);
    });
},
Copy the code
// jsonp.js (node side)let express = require("express");
let app = express();
app.get("/say", (req, res) => {
    let { wd, callback } = req.query;
    console.log(wd);
    console.log(callback);
    res.end(`${callback}('hello world') `); }); app.listen(3000);Copy the code

The above code to http://localhost:3000/say? Wd =Iloveyou&callback=show, return show(‘hello world’), run show(), print ‘hello world’

Jsonp form of jQuery

JSONP is all GET and asynchronous requests, there is no other way to request or synchronous requests, and jQuery clears the cache for JSONP requests by default

$.ajax({
    url:"http://crossdomain.com/jsonServerResponse",
    dataType:"jsonp".type:"get"// You can omit jsonpCallback:"show",//-> custom function names passed to the server, instead of using jQuery automatically generated, can omit jSONp:"callback"Callback (); // callback ();function (data){
    console.log(data);}
});
Copy the code

5.WebSocket

6.postMessage

例 句 : Strange techniques left over from ancient times


Reference article (capitalized thanks)

Nine Cross-domain Implementation Principles (Full version)