Why does the same-origin policy exist
concept
There was a security policy introduced by Netscape in 1995 that is now used by all browsers. It restricts one source from requesting resources from another and is used to isolate potentially malicious files.
What are the different sources
We all know that a general address consists of the following three parts
- The agreement is the same
- Domain name is the same
- The same port
As long as one of the addresses is different, the two addresses are different sources.
For example
/ / address http://www.address.com/item/page.html: http:// domain name: www.example.com port: 8080 (HTTP) / 443 (HTTPS) (default port omitted) homologous http://address.com/item/other.html: http://www.address.com/item2/other.html: Different source (domain name) different source http://v2.www.address.com/item/other.html: (domain name) different source http://www.address.com:81/item/other.html: (port)Copy the code
Homologous purpose
The goal is to keep user information safe and prevent malicious sites from stealing data, otherwise cookies can be shared. Some websites generally store some important information in cookies or LocalStorage, then if other websites can get access to this data, it is conceivable that there is no security at all.
limits
There are currently three types of behaviour that are restricted
- Cookie, LocalStorage, and IndexDB cannot be read
- DOM not available
- AJAX requests cannot be sent
The solution
1. Cross domains through JSONP
The principle of
The SRC attribute of script, IMG, iframe and other tags has the ability to request resources across domains. We can put js, CSS, img and other resources on a server with an independent domain name. Then, by dynamically creating a script tag and requesting the url of a callback function, the server inserts the parameters to be passed into the callback function, and we execute the function in the JS code to get the parameters you want.
Front-end native implementation
<script>
window.xxx = function (value) {
console.log(value)
}
var script = document.createElement('script')
script.src = 'https://www.address.com:433/json?callback=xxx'
document.body.appendChild(script)
</script>
Copy the code
Jquery implementation
$.ajax({
type: "get",
url: "https://www.address.com:433/json",
dataType: "jsonp",
jsonp: "callback",
jsonpCallback:"xxx"// Define the name of the callback function success:function(res){
console.log(res)
},
error: function(){
console.log('fail'); }});Copy the code
The json plug-in
NPM install jsonp const jsonp = require('jsonp');
jsonp('https://www.address.com:433/json', {parma:'xxx'}, (err, data) => {if (err) {
console.error(err.message);
} else{ console.log(data); }});Copy the code
node.js eggThe service side
/ / need to see an egg's official website to build a simple framework for an egg - init -- type = simple / / router. Js https://eggjs.org/api/Config.html with an egg built-in JSPNP method#jsonp
module.exports = app => {
app.get('/json', app.jsonp({ callback: 'xxx' }), app.controller.json.index)
}
Copy the code
disadvantages
- Only GET requests are supported. POST requests are not supported
- Call failed without HTTP status code
- Not safe enough.
2, CORS
The principle of
Cross-origin Resource Sharing (CORS) is shared across resources, the browser cannot be lower than Internet Explorer 10, and the server supports any type of request.
Be familiar with several background fields to be set
- Access-Control-Allow-Origin
The * field is mandatory, indicating that requests of any domain name are allowed. When cookies need to be passed, you need to specify the domain name.
- Access-Control-Allow-Credentials
The field is optional and defaults to false, indicating whether cookies are allowed to be sent. If yes, notify the browser to also enable the transfer of cookie values.
- Access-Control-Expose-Headers
Field Optional. If you want the browser to get the getResponesHeader() other fields, specify them here.
- Access-Control-Request-Method
A required field that is not set for simple requests, such as a PUT request.
- Access-Control-Request-Headers
Specifies additional send header information to split the string with commas.
Front-end native code
Var XHR = new XMLHttpRequest() // Sets the carrying cookie xhr.withcredentials =true;
xhr.open('POST'.'https://www.address.com:433/json'.true);
xhr.setRequestHeader('Content-Type'.'application/x-www-form-urlencoded')
xhr.send(null)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText).msg)
}
}
Copy the code
The back-end code
module.exports = app => {
class CrosController extends app.Controller {
* index(req) {
this.ctx.set('Access-Control-Allow-Origin'.'https://www.address.com');
this.ctx.set('Access-Control-Allow-Credentials'.'true')
this.ctx.body = { msg: 'hello world'}}}return CrosController
}
Copy the code
advantages
- All types of HTTP requests are supported.
disadvantages
- Not compatible with IE10 below.
3. Combine iframe with the locaction.hash method
The principle of
Iframe can be used to pass values between different fields, and location.hash can carry parameters, so iframe is used as a bridge between different fields.
Concrete implementation steps
- 1. Insert the IFrame tag of the domain name B into the domain name A page.
- 2. Then make an Ajax request to the server of the same domain name in the IFrame page of domain B.
- 3. The iframe page takes the data and passes it as a hash using the # tag.
- 4. This way you can use window.onhashchange to listen for the data you want on the A domain page.
A Domain name Page
var iframe = document.createElement('iframe')
iframe.src = 'http://www.B.com:80/hash.html'
document.body.appendChild(iframe)
window.onhashchange = function() {// handlehash
console.log(location.hash)
}
Copy the code
B Domain name Page
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var res = JSON.parse(xhr.responseText)
console.log(res.msg)
parent.location.href = `http://www.A.com:80/a.html#msg=${res.msg}`
}
}
xhr.open('GET'.'http://www.B.com:80/json'.true)
xhr.send(null)
Copy the code
disadvantages
- Iframe can solve the problem, but security risks are still important.
- Hash pass-throughs are cumbersome to handle.
4. Iframe combines with the window.name method
The principle of
The principle is the same as the above method, but the difference is that window.name can pass more than 2MB of data.
A Domain name Page
var iframe = document.createElement('iframe')
iframe.src = 'http://www.B.com:80/name.html'
document.body.appendChild(iframe)
var times = 0
iframe.onload = function () {
if (times === 1) {
console.log(JSON.parse(iframe.contentWindow.name))
destoryFrame()
} else if (times= = = 0) {times= 1}} // Delete iframe;function destoryFrame() {
document.body.removeChild(iframe);
}
Copy the code
B Domain name Page
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
window.name = xhr.responseText
location.href = 'http://www.A.com:80/a.html'
}
}
xhr.open('GET'.'http://www.B.com:80/json'.true)
xhr.send(null)
Copy the code
5. PostMessage crosses domains
The principle of
PostMessage is H5 native API support for passing data between two or more pages and between different source pages. To be able to transfer data between Windows, we must obtain the target window object from one window to another. For example, if we open another window with an iframe, we must obtain the contentWindow of this iframe. Or opening another window with window.open() returns the window object for that window.
Parameter passing
/** data The data to be passed, using json.stringify to serialize origin set toThe '*'Is passed to all Windows. You can also specify the address. In the same-source scenario, set this parameter to'/'
**/
postMessage(data,origin)
Copy the code
http://localhost:8069window
Var popup = window.open('http://localhost:8080'); /// wait for the new window to loadsetTimeout(function() {popup.postMessage({popup.postMessage();"age": 10},'http://localhost:8080');
}, 1000);
Copy the code
http://localhost:8080window
// Set the listener and print window.addeventListener ('message'.function(e) { console.log(e); // Determine if it is the destination addressif(e.origin ! = ='http://localhost:8069')return;
// console.log(e.source === window.opener); // true// return data to e.ource. PostMessage ({"age":20}, e.origin);
});
Copy the code
Other solutions
These five are common cross-domain solutions, each with its own advantages and disadvantages. There is no absolute optimal solution, only the most suitable application scenario.
Two common agents cross domains
- Nginx reverse proxy Cross-domain Node middleware proxy
Configuration will not speak, in fact, I am not familiar with, usually work with less than so lofty. Let’s talk about principles and ideas.
What is agency
Since the Proxy is cross-domain, Proxy Server is a very important point. The Proxy here refers to the Server Proxy, which is a very important Server security function and a very common design pattern to isolate different modules and decouple modules. Life is easy to see this pattern, we buy a house (can’t afford to buy ah) buy a car, is just like dealing with a large server, others are big boss, nature won’t be so easy to receive you in person, by this time have a mediation in the middle, to help you sort out good ideas, flow, and then the communication will be more behind the shun tong efficiently. There is a limit to how many servers our browsers can access from different sources, but proxies like Nginx and Node middleware have no cross-domain limit, so we can trust them to do things for us that we can’t.
Why is the agency inverse
We know that the processing capacity of a single server is limited. For example, It is impossible for China to have only one automobile manufacturer. As China is such a big market, it naturally needs many manufacturers to satisfy it. The user need to save time and effort when the choose and buy, between cars would take such a role, and distributing the tens of thousands of user requirements, nginx could hand out the user’s request to the free server, then the server returned to their service to the load balancing device, then speak the server load balancing machine service returns to the user, So we don’t know why the service is sent from which server, which is a good way to hide the server. There is an incisive saying: “Reverse proxy is flow divergence, proxy is flow convergence.”
Finally, attach a very ugly drawing
If you want to continue to discuss or learn more knowledge, welcome to join QQ or wechat: 854280588