1. What is cross-domain
The same origin policy restricts how documents or scripts loaded from the same source can interact with resources from another source. This is an important security mechanism for isolating potentially malicious files. Same-origin: The protocol, domain name, and port number must be the same.
The same origin policy controls interactions between different sources, such as when using XMLHttpRequest orTags are bound by the same origin policy. These interactions generally fall into three categories:
- Cross-origin writes are generally allowed. Examples include links, redirects, and form submission. A small number of HTTP requests require adding preFlight.
- Cross-origin embedding is generally allowed.
- Cross-origin reads are not normally allowed. However, it is often possible to cleverly read access through embedded resources. For example, you can read the height and width of an embedded image, call methods of embedded scripts, or availability of an Embedded Resource.
The following are examples of tags that allow cross-domain resource embedding, that is, tags that are not affected by the same origin policy:
<script src="..." ></script>
Tag embedding across domain scripts. Syntax error messages can only be captured in cognate scripts.<link rel="stylesheet" href="..." >
Tags are embedded in CSS. As a result of the CSSLoose grammar rules, CSS cross-domain needs a set up correctlyContent-Type
The message header. Different browsers have different restrictions:IE.Firefox.Chrome.Safari 和 Opera.- Embed image. Supported image formats include PNG,JPEG,GIF,BMP,SVG
- Plugins for
- @font-face The introduced font. Some browsers allow cross-origin fonts, some require same-Origin fonts.
<frame>
and<iframe>
Any resources loaded. The site can be usedX-Frame-Options
Message headers to prevent this form of cross-domain interaction.
2. Cross-domain solutions
jsonp
A scheme that makes use of script tags without cross-domain constraints.
// index.html
function jsonp({url, param, cb}){
return new Promise((resolve, reject)=>{
let script = document.createElement('script')
window[cb] = function(data){ resolve(data); document.body.removeChild(script) } params = {... params, cb}let arrs = [];
for(let key in params){
arrs.push(`${key}=${params[key]}`)
}
script.src = `${url}?${arrs.join('&')}`
document.body.appendChild(script)
})
}
jsonp({
url: 'http://localhost:3000/say',
params: {wd: 'haoxl'},
cb: 'show'
}).then(data=>{
console.log(data)
})
Copy the code
//server.js
let express = require('express')
let app = express()
app.get('/say'.function(req, res){
let {wd,cb} = req.query
console.log(wd)
res.end(`${cb}('hello')`)
})
app.listen(3000)
Copy the code
Disadvantages: Only GET requests are supported, but post, PUT, and DELETE are not supported. Insecure and vulnerable to [XSS][18] attacks.
cors
Cross-domain resource sharing standards have added a new set of HTTP header fields that allow servers to declare which source sites have access to which resources. In addition, the specification requires that HTTP request methods (especially HTTP requests other than GET, or POST requests paired with certain MIME types) that may have adverse effects on server data, The browser must first issue a preflight request using the OPTIONS method to know whether the server will allow the cross-domain request. The actual HTTP request is made only after the server confirms that it is allowed. In the return of the precheck request, the server side can also inform the client whether it needs to carry identity credentials (including Cookies and HTTP authentication related data).
<! --index.html--> <body> Nice to meet you </body>Copy the code
<script>
letxhr = new XMLHttpRequest; Cookie document.cookie ='name=haoxl'
xhr.withCredentials = true
xhr.open('GET'.'http://localhost:4000/getData'.true); // set the custom request header xhr.setrequesTheader ('name'.'haoxl')
xhr.onreadystatechange = function() {if(xhr.readyState === 4){
if(xhr.status>=200 && xhr.status < 300 || xhr.status === 304){ console.log(xhr.response); Console. log(xhr.getresponseHeader (xhr.getresponseHeader))'name'));
}
}
}
xhr.send()
</script>
Copy the code
// server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000)
Copy the code
// server2.js
let express = require('express');
let app = express();
let whiteList = ['http://localhost:3000']
app.use(function(req, res, next){
let origin = req.headers.origin;
if(whitelist.includes (origin)){// Set the source to be accessible to me. If the parameter is *, it allows anyone to access me, but does not use res.setheader with the cookie credentialresponse header.'Access-Control-Allow-Origin', origin); // Allow request headers with name to access res.setheader ('Access-Control-Allow-Headers'.'name'); // Set which request methods can access res.setheader ('Access-Control-Allow-Methods'.'PUT');
// 设置带cookie请求时允许访问
res.setHeader('Access-Control-Allow-Credentials'.true); // Set res.setheader (); // Set res.setheader ();'Access-Control-Expose-Headers'.'name'); // Precheck survivability time -options res.setheader ('Access-Control-Max-Age',3) // Set nothing to be done when a pre-request is sentif(req.method === 'OPTIONS'){ res.end(); }} next(); }); app.put('/getData'.function(req, res){
console.log(req.headers)
res.setHeader('name'.'hello');
res.end('hello world');
}
app.get('/getData'.function(){
res.end('Nice to meet you')
})
app.use(express.static(__dirname));
app.listen(3000)
Copy the code
postMessage
Scripts for two different pages can only communicate with each other if the page executing them is on the same protocol (usually HTTPS), port number (443 is the default value for HTTPS), and host (the module document.domain of the two pages is set to the same value). The window.postmessage () method provides a controlled mechanism to circumvent this limitation and is safe as long as it is used correctly.
When the window.postmessage () method is called, a MessageEvent message is sent to the target window after all page scripts have been executed (e.g., events set after the method, timeout events set before,etc.).
Syntax: otherWindow.postMessage(message, targetOrigin, [Transfer]);
- OtherWindow: Specifies the target window, that is, the window to which the message is sent, either as a member of the window.frames property or as a window created by the window.open method.
- The message attribute is the message to be sent. The type of the message is String or Object (not supported by Internet Explorer 8 and 9).
- TargetOrigin: Property that specifies which Windows can receive message events. The value can be the string “*” (for unrestricted) or a URI.
- Transfer: A string of Transferable objects that are transferred simultaneously with Message. Ownership of these objects is transferred to the receiver of the message, and ownership is no longer retained by the sender.
The message properties are:
- The data attribute is the first argument to window.postMessage;
- The origin property represents the current state of the page when the window.postmessage () method is called;
- The source property records information about the window in which the window.postmessage () method is called;
Example: A.HTML sends messages to B.HTML
// a.html
<iframe src="http://localhost:4000/b.html" id="frame" onload="load()"></iframe>
<script>
function load(params){
let frame = document.getElementById('frame'); / / get the window of the iframe, send message to embed in the iframe window frame. The contentWindow. PostMessage ('hello'.'http://localhost:4000') // Receive the return message window.onmessage =function(e){
console.log(e.data)
}
}
</script>
Copy the code
// b.html <script> // listen for message window.onmessage =function(e){console.log(e.ata) // Send a message back to the sending source.'nice to meet you',e.origin)
}
</script>
Copy the code
window.name
A page may change its source due to certain restrictions. A script can set the value of document.domain to its current domain or to the superdomain of its current domain. If it is set to the superdomain of its current domain, the shorter domain is used for subsequent source checks.
A and B are codomain http://localhost:3000, and C is independent http://localhost:4000. A uses iframe to introduce C, c puts the value in window.name, and then points its SRC to B, which is in the same domain as A.
// a.html
<iframe src="http://localhost:4000/c.html" onload="load()"></iframe>
<script>
let first = true
function load() {if(first){
let iframe = document.getElementById('iframe'); // redirect the iframe in a to b iframe.src='http://localhost:3000/b.html';
first = false;
}else{/ / are available in the b c send window messages console. The log (iframe. ContentWindow. Name); } } </script>Copy the code
// c.html
<script>
window.name = 'nice to meet you'
</script>
Copy the code
//server.js
let express = require('express')
let app = express();
app.use(express.static(__dirname));
app.listen(4000);
Copy the code
location.hash
The window.location read-only property returns a location object that contains information about the current location of the document. **window.location: All letters must be lowercase! ** As soon as you assign a new value to the location object, the document will be loaded with the new URL, just as window.location.assign() was called with the modified URL. Be aware that security Settings, such as CORS (Cross-domain resource sharing), may limit the actual loading of new pages.
Case: A and B are in the same domain, and C is in a separate domain. A now wants to access C: A passes a hash value to C using an iframe. C then creates an iframe after receiving the hash value and passes the hash value to B, and B puts the hash result into A’s hash value.
// a.html
<iframe src="http://localhost:4000/c.html#iloveyou"></iframe> <scripthashValue window. Onhashchange =function(){
console.log(location.hash)
}
</script>
Copy the code
// c.html //hashConsole. log(location.hash) // Create an iframe to pass the reply message to Blet iframe = document.createElement('iframe');
iframe.src='http://localhost:3000/b.html#idontloveyou';
document.body.appendChild(iframe);
Copy the code
/ / b.h HTML < script > / / a.h HTML of c, c and b, so p. arent. The parent is a window. The parent, the parent. The location. The hash = location. The hash < / script >Copy the code
window.domain
Window.domain: Gets/sets the original domain part of the current document. Example: Resolve communication between a level 1 domain and a level 2 domain. During the simulation, you need to create two different domain names for the test. Open C:\Windows\System32\drivers\etc to find the hosts file and create a level-1 domain name and a level-2 domain name at the bottom. To:
127.0.0.1 www.haoxl.com
127.0.0.1 test.haoxl.com
Copy the code
Default a.html = www.haoxl.com, b.html = test.haoxl.com
// a.html
<iframe src="http://test.haoxl.com" onload="load()"></iframe>
<script>
function load(){// tell the page its main domain name, the same as the main domain name of B.html, so that you can access the value of b document.domain = in a'haoxl.com'
function load(){console.log(frame.contentwindow.a); console.log(frame.contentwindow.a); } } </script>Copy the code
// b.html
document.domain = 'haoxl.com'
var a = 'hello world'
Copy the code
websocket
The WebSocket object provides an API for creating and managing WebSocket connections and for sending and receiving data over that connection. It is full duplex communication based on TCP, that is, the server and client can communicate bidirectionally and allow cross-domain communication. The basic protocols are WS ://(non-encrypted) and WSS ://(encrypted)
//socket.html
let socket = new WebSocket('ws://localhost:3000'); // Send a message to the server socket.onopen =function() {
socket.send('hello server'} // Socket. Onmessage =function(e) {
console.log(e.data)
}
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws'); // NPM I ws // Set server domain to 3000 portletwss = new WebSocket.Server({port:3000}); Check / / connection WSS.'connection'.function(ws){// Receive messages from the client ws.on('message'.function(data){ console.log(data); // The server replies with the message ws.send('hello client')})})Copy the code
Nginx
Nginx (Engine X) is a high-performance HTTP and reverse proxy server, as well as an IMAP/POP3/SMTP server.
Example: Create json/ A.son in the nginx root directory and put whatever you want inside
// client.html
let xhr = new XMLHttpRequest;
xhr.open('get'.'http://localhost/a.json'.true);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304 ){ console.log(xhr.response); }}}Copy the code
// server.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
Copy the code
// nginx.conf location / {// indicates that the default is to open the root HTML folder in the root directory. index index.html index.htm; } location ~.*\. Json {// represents any. Json to open the json folder root json; add_header"Access-Control-Allow-Origin" "*";
}
Copy the code
http-proxy-middleware
NodeJS http-proxy-middleware implements cross-domain proxy. The principle is roughly the same as nginx, which starts a proxy server to realize data forwarding. You can also set the cookieDomainRewrite parameter to modify the domain name in the cookie in the response header to write cookies to the current domain for interface login authentication.
- Vue framework: Cross-domain using node + Webpack + Webpack-dev-server agent interface. In the development environment, since both the Vue rendering service and the interface proxy service are Webpack-dev-server, there is no need to set Headers cross-domain information between the page and the proxy interface.
module.exports = {
entry: {},
module: {},
...
devServer: {
historyApiFallback: true,
proxy: [{
context: '/login',
target: 'http://www.proxy2.com:8080', // Proxy cross-domain destination interface changeOrigin:true,
secure: false// Use cookieDomainRewrite when brokering an error for some HTTPS service:'www.domain1.com'/ / can befalse}], noInfo:true}}Copy the code
- Non-vue framework cross-domain (twice cross-domain)
<! -- index.html --> <! DOCTYPE html> <html lang="en">
<head>
<meta charset="UTF-8"> <title>nginx cross-domain </title> </head> <body> <script> var XHR = new XMLHttpRequest(); // Front-end switch: whether the browser reads and writes cookies xhr.withCredentials =true; // Access http-proxy-middleware proxy server xhr.open('get'.'http://www.proxy1.com:3000/login?user=admin'.true);
xhr.send();
</script>
</body>
</html>
Copy the code
Var express = require("express");
var proxy = require("http-proxy-middleware");
var app = express();
app.use(
"/", proxy({// proxy cross-domain target interface target:"http://www.proxy2.com:8080",
changeOrigin: true// Modify the response header to cross-domain and allow cookie onProxyRes:function(proxyRes, req, res) {
res.header("Access-Control-Allow-Origin"."http://www.proxy1.com");
res.header("Access-Control-Allow-Credentials"."true"); }, // Modify the cookie domain name in the response message cookieDomainRewrite:"www.proxy1.com"/ / can befalse})); app.listen(3000);Copy the code
// server var HTTP = require("http");
var server = http.createServer();
var qs = require("querystring");
server.on("request".function(req, res) { var params = qs.parse(req.url.substring(2)); // Write cookie res.writeHead(200, {"Set-Cookie": "l=a123456; Path=/; Domain=www.proxy2.com; HttpOnly"// HttpOnly: script cannot read}); res.write(JSON.stringify(params)); res.end(); }); server.listen("8080");
Copy the code