Front-end cross-domain issues

preface

I am a front-end xiaobai, combined with my own understanding and reading of relevant blog experience, if there is a summary is not in place, please leave a message to correct and supplement, so far only two cross-domain solutions

Refer to the blog

Cross-domain and CSRF

directory

The background,

  1. What is homology?
  2. What is the purpose of the same origin policy?

Second, the performance of cross-domain problems

  1. What is cross-domain?
  2. What is CSRF?

Common solutions to cross-domain problems

  1. JSONP
  2. CORS cross-domain resource sharing

The background,

1. What is homology?

If two pages have the same protocol, domain name, and port, they belong to the same source. If one of them is different, it is a different source. Assume that the user page url:www.example.com/dir2/other….

URL Whether the same Whether to allow communication instructions
Example.com/dir/other.h… Example.com/dir/other2…. is allow The protocol, domain name, and port are the same (the default port is port 80), but the path is different
Example.com/dir/other.h… no Don’t allow Agreement is different
Example123.com/dir/other.h… no Don’t allow Domain name is different
Example.com: 81 / dir/other. H… no Don’t allow Different ports

2. What is the purpose of the same-origin policy?

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.

The same origin policy of the browser is to prevent malicious attacks such as XSS and CSRF, to ensure user information security, and to prevent malicious websites from stealing data. The original same-origin policy refers to the Cookie set by website A on the client, and website B cannot be accessed.

With the development of the Internet, the same origin policy is becoming more and more strict. In the case of different sources, one of the stipulations is that Ajax requests cannot be sent to non-same origin addresses. If a request is made, the browser will report an error.There are three interaction modes for the same origin policy:

  • Cross-domain write operations, such as linking, redirecting, and form submission, are generally allowed.
  • It is generally possible to nest resources across domains, such as IMG, script tags, and so on.
  • Cross-domain read operations are generally not allowed.

Second, the performance of cross-domain problems

1. What is cross-domain?

Cross-domain refers to the process of sending a request to a destination address that is not the origin(protocol, domain name, or port). This problem is caused by the same Origin policy of the browser. It looks like the same origin policy affected the smoothness of our development. In fact, the same origin policy exists in order to isolate attacks.

2.CSRF

CSRF, also known as cross-site request forgery, refers to an attack in which an illegal website enlists a user’s cookie to perform illegal operations on the logged website. This is based on the practicability of using cookies to avoid Posting on the website and retain user information. Next, we will talk about the normal website free Posting request process. The request flow is as follows:

  1. We go to a website and send a login request to the back end
  2. The back end accepts the login request and determines whether the login information is accurate
  3. After verifying that the information is correct, the backend sends a response to the browser and adds a set-cookie field to the Response header
  4. The browser receives the response back to the user and saves the cookie in the header
  5. After the user closes the current website window and opens it again, the browser automatically adds the cookie to the Request header

Let’s imagine a scenario like this

  • Little A logged in the online banking website, and the browser of little A recorded the cookies returned by the online banking
  • At this time he qq received a link, what Macao casino, beauty officer, online money to send the website B
  • After he clicks that link, website B can send a request to the online banking system with a cookie set by the browser

The result is self-evident, information leakage at a light level, money loss at a heavy level, and the normal storage time of cookies is until the browser is closed, not the website. Therefore, many users will think that it is safe to open the Website of Macao emmmm after closing the website. In some sites with high security requirements, the same origin policy is still necessary. It is also best to set restrictions on requests that need to be implemented across domains, such as setting the specified whitelist Origin.

Common solutions to cross-domain problems

1.JSONP

The browser allows cross-domain requests to be sent through the SRC request path in the script tag when parsing the script tag, without the impact of the same origin policy, so the first solution to the cross-domain problem can be started with the native script tag.

  • We write a script tag in the front-end code, place the url of the cross-domain request address in the SRC attribute of the Script standard, and when the browser renders to this script tag it will send the request to the target address
    <! -- declare fn function -->
    <script>
        function fn(data) {
            console.log(data);
        }
    </script>
    <! Place non-homologous request paths in the SRC attribute of script tags -->
    <script src="http://localhost:3001/test1"></script>
Copy the code
  • The server at the destination address receives our request and processes it, returning a string in which we simply place the processed data around the parameters of a function, enclose the function in quotes, and return it to the client
/* NPM install ExpressCopy the code
    // Introduce the Express framework
    const express = require('express');
    // Create Web server
    const app = express();
    // Process /test request route
    app.get('/test'.(req, res) = > {
    / / fn in
    res.send("fn({username:'andy'})");
});
Copy the code
  • This function is called when the client parses the string that receives the response from the server. This function needs to be declared in script tag generation and is a global function (it can be mounted under the global object Windom).

Abstract this idea and encapsulate it into a native JSONP function (which does not allow for request failures and needs to be improved)

    // Encapsulates the JSONp function
    / * parameter options: Type :Object{url:{type:String, requied:true, description: address for cross-domain requied, success:{type:Function, requied:true, Data :{type:Object, required:false, description: sent request parameters}} */
    function jsonp(options) {
    // Request path
    var script = document.createElement('script');
    // Concatenate a string variable
    var params = ' ';
    // Loop over data object concatenation parameters
    for (let attr in options.data) {
        params += '&' + attr + '=' + options.data[attr];
    }
    // Generate function names randomly to avoid overwriting functions with the same name when multiple JSONP functions are triggered for example: myfnName0.121212 =>myfnName0121212
    var fnName = 'myfnName' + Math.random().toString().replace('. '.' ');
    // To solve the problem that functions must be declared globally, mount the function to the global object Windom
    window[fnName] = options.success;
    // Place the cross-domain request address in the script tag SRC
    script.src = options.url + '? callback=' + fnName + params;
    // Insert the script tag into the document
    document.body.appendChild(script);
    // The script tag is created
    script.onload = function () {
        // Remove the generated script tags to optimize the structure of the document
        document.body.removeChild(this); }}Copy the code

The code on the server side is as follows:

    app.get('/better'.(req, res) = > {
	// Receive the name of the function passed by the client
	// const fnName = req.query.callback;
	Return the function calling code corresponding to the function name to the client
	// const data = json.stringify ({name: "zhang3 "});
        // Concatenate the response content
	// const result = fnName + '('+ data +')';
	// res.send(result);
        The Express framework has already saved us the above steps by using the jSONp method under the Response object
	res.jsonp({name: 'lisi'.age: 20});
});
Copy the code

2.CORS cross-domain resource sharing

CORS: Cross-Origin Resource Sharing, or Cross-domain resource sharing, allows browsers to send Ajax requests to cross-domain servers, overcoming the limitation that Ajax can only be used in the same source. By configuring access-Control-allow-Origin and access-Control-Allow-Origin in the response header on the server, that is, configuring the whitelist, the browser can accept the response data of the cross-domain request, and the ajax request code can be normally written on the client.

    // Set the middleware to intercept all requests set their response headers
    app.use((req, res, next) = > {
     // Tell the server which clients can access me * to allow all clients to access me
     res.header('Access-Control-Allow-Origin'.The '*');
     // Tell the server how the client can access me
     res.header('Access-Control-Allow-Methods'.'GET, POST');
     // This step is so critical that it is easy to omit this step and the server cannot handle client requests
     // Release the request to be processed by subsequent middleware
     next();
 })

Copy the code

CSRF mentioned above, now we need to do cross-domain login authentication to verify that the user is logged in, The withCredentials attribute of the Ajax object and the access-Control-allow-credentials attribute in the response header can be configured on the server side.

HTML code:

    <form id="loginForm">
            <div class="form-group">
                <input type="text" name='username' class="form-control">
            </div>
            <div class="form-group">
                <input type="password" name="password" class="form-control">
            </div>
            <input type='button' class="btn btn-default" id="loginBtn" value="Login"></input>
            <input type='button' class="btn btn-default" id='checkLogin' value="Check login status"></input>
        </form>
Copy the code

JS code:

    // Get the element
        var loginBtn = document.querySelector('#loginBtn');
        var checkLogin = document.querySelector('#checkLogin');
        var loginForm = document.querySelector('#loginForm');
        loginBtn.addEventListener('click'.function () {
            // Create the FormData object
            var form = new FormData(loginForm);
            // Create Ajax objects
            var xhr = new XMLHttpRequest();
            // Configure the Ajax object
            xhr.open('post'.'http://localhost:3001/login');
            // Send an Ajax request
            xhr.send(form);
            // Listen for the onload event
            xhr.onload = function () {
                console.log(xhr.responseText);
            }
        })
        checkLogin.addEventListener('click'.function () {
            // Create the FormData object
            var form = new FormData(loginForm);
            // Create Ajax objects
            var xhr = new XMLHttpRequest();
            // Configure the Ajax object
            xhr.open('get'.'http://localhost:3001/checkLogin');
            // Send an Ajax request
            xhr.send();
            // Listen for the onload event
            xhr.onload = function () {
                console.log(xhr.responseText);// {"message":" not logged in "} Cookies exist across domains and are not carried}})Copy the code

Node server code: set a registered user name lisi password 123456 for authentication

    // Resolve the problem of cross-domain login carrying cookies
app.post('/login'.(req, res) = > {
    // Create a form resolution object
    var form = formidable.IncomingForm();
    // Parse the form
    form.parse(req, (err, fields, file) = > {
        // Receive the user name and password from the client
        const { username, password } = fields;
        // User name and password comparison
        if (username == 'lisi' && password == '123456') {
            / / set the session
            req.session.isLogin = true;
            res.send({ message: 'Login successful' });
        } else {
            res.send({ message: 'Login failed, wrong username or password'}); }})}); app.get('/checkLogin'.(req, res) = > {
    // Check whether the user is logged in
    if (req.session.isLogin) {
        res.send({ message: 'Logged in'})}else {
        res.send({ message: 'Not logged in'}}}));Copy the code

The results are shown below:

Figure for the first time, we can know sends a request to the server, the server returns a unique cookie value and pass the login successful response data but to us, whether we are testing for the login, send a request to the server, found no access to the corresponding server client cookie object, The response is not logged in.

Set the withCredentails property of the Ajax object to true in javascript:

    // Clients are allowed to carry cookie information
     xhr.withCredentials = true;
Copy the code

Set the access-Control-allow-credentials attribute in the response header to true on the Node server

 // Set the middleware to intercept all requests set their response headers
    app.use((req, res, next) = > {
     // Tell the server which clients can access me * to allow all clients to access me
     res.header('Access-Control-Allow-Origin'.The '*');
     // Tell the server how the client can access me
     res.header('Access-Control-Allow-Methods'.'GET, POST');
     // Allow clients to send cross-domain requests with cookie information
     res.header('Access-Control-Allow-Credentials'.true);
     // This step is so critical that it is easy to omit this step and the server cannot handle client requests
     // Release the request to be processed by subsequent middleware
     next();
 })
    
Copy the code

Do the login test again: