Cors cross domain: solution vs. jsonp Cors

If you don't practice martial arts, you'll lose everything.
This article has been https://yourbatman.cn Collection; Enjoy 1G super large capacity programmer dedicated network disk for free https://wangpan.yourbatman.cn ; The public account backstage replies to the "column list" to obtain all small and beautiful original technical columns

✍ preface

Hello, I'm YourBatman.

Excavator technology which strong, Shandong technical school looking for Lanxiang; How to solve the cross domain problem, CORS or JSONP?

As for the solution to the cross domain problem of browsers, there have been "rumors" about two solutions: JSONP and CORS. Due to the different historical background of the article and the different preferences of the author, many students are confused. This is often the case when they go to Baidu in Google to search for answers.

As a responsible "technical school" (the technical column of the person in charge), this article thoroughly explains to you today and gives you definite answers to help you quickly choose the right path to solve problems.

Column

Outline of this paper

Version Convention

  • JDK: 8
  • Servlet: 4.x
  • tomcat: 9.x

✍ text

Homology policy is the core and basic security function of browser. When scripts that are doubted by the browser run in the sandbox, they should only be allowed to access resources from the same site, not those from other sites that may be malicious. However, in the current Internet scenario, cross domain access is a must, so there is a solution to the cross domain problem.

Two major schemes: JSONP and CORS

There are two solutions for sharing resources across domains

  • JSONP: an older generation browser solution
  • CORS: a new set of standard solutions

JSONP scheme


Unlike iPhone 7 and iPhone 7P, JSONP is not equal to JSON Plus. Its full name is JSON with Padding. JSON is a text-based data exchange format, and JSONP is a usage mode that allows web pages to access resources from other domains, so as to complete cross domain resource sharing.

The first article in this series Let's say that the src of the < script > tag does not cross domain. Based on this, we can realize the cross domain of Get requests.

The basic principle of cross domain implementation of JSONP is to complete cross domain access by using src of script tag without cross domain restriction + callback.

Code implementation example

Front end page: hosted on port 63342

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONP Cross domain request</title>
    <!--Import Jquery-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<script>
    // This function will be called back after the request is completed
    function jsonpCallback(result) {
        console.log("This is JSONP Response result of request:" + result);
    }
</script>
<!--Note: this script It must be on it function Below-->
<script type="text/javascript" src="http://localhost:8080/jsonp?callback=jsonpCallback"></script>
</body>
</html>

Note: the src of script is used to send http requests to the server, so this script tag must be placed under the function (because the browser renders from top to bottom)

Server code: hosted on port 8080

/**
 * Add notes here
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @site https://yourbatman.cn
 * @date 2021/6/9 10:36
 * @since 0.0.1
 */
@Slf4j
@WebServlet(urlPatterns = "/jsonp")
public class JSONPServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String callback = req.getParameter("callback");
        resp.getWriter().write(callback + "('hello jsonp...')");
    }
}

Note: you can see that the code on the server side is very refreshing and does not involve any request header / response header

Open the page and send a JSONP request. The results are as follows:

Requested response body:

Browser console output:

Perfect. Through JSONP, we can access resources in different domains and cross domains.

Sending asynchronous JSONP requests with jQuery's ajax

In the above example, the src attribute of < script > tag is used to send synchronous cross domain requests. In actual development (especially the separation of front and back ends), Ajax asynchronous requests are sent in most cases. Let's try.

Note: whether asynchronous requests are sent in native XMLHttpRequest or Ajax or Promis, the underlying principle is the same

Sending asynchronous JSONP requests using jQuery is very simple. You don't even need to write < script > and functions:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JSONP Cross domain request</title>
    <!--Import Jquery-->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<!--<script>-->
<!--    // This function will be called back after the request is completed -- >
<!--    function jsonpCallback(result) {-->
<!--        console.log("This is JSONP Response result of request:" + result);-->
<!--    }-->
<!--</script>-->
<!--&lt;!&ndash;Note: this script It must be on it function Below&ndash;&gt;-->
<!--<script type="text/javascript" src="http://localhost:8080/jsonp?callback=jsonpCallback"></script>-->
<script>
    $.ajax({
        // type: "get", / / there is no need to write a method, because JSONP only supports GET requests
        url: "http://localhost:8080/jsonp ", / / Ajax using jQuery is followed by no parameters
        dataType: 'jsonp',
        success: function (data) {
            console.log("This is JSONP Request response results( jQuery Ajax): " + data);
        },
    });
</script>
</body>
</html>

Through jQuery, the writing method of js code is greatly improved, making the structure more elegant and intuitive. This is jQuery's greatest syntax sugar ability~

Description: JsonP only works with type: GET. In other words, even if you write type as post, jQuery will convert it to get

The server does not change and sends an asynchronous request. The results are as follows:


Focus:

  1. The callback callback function name of Ajax is generated dynamically and ensures uniqueness
  2. Since the server does not care about the callback function name, the length of the callback function name does not matter (the browser can recognize it)

The influencing factors are as follows:

Browser console print:

Perfect. For you who are technology sensitive, you should find that the underlying principle is still script src, but the writing method is different, that's all.

Advantages and disadvantages

As an "old" method, JSONP cross domain scheme has the following advantages and disadvantages:
advantage:

  • It has very good compatibility with old browsers (such as IE8, 7, etc.)
  • It is simple to write and easy to understand (after all, there are not so many request headers and response headers to consider)

Disadvantages:

  • Only get requests can be sent. POST, PUT and other request methods are not supported. This is a hard injury
  • The degree of safety is not high. Because JSONP uses function callbacks to execute object functions by the browser, the host web is actually more vulnerable to various attacks

In general, with the formal confirmation of the CORS specification in 2014, modern browsers 100% support the CORS specification. Due to the upgrading of browsers, the biggest advantage of JSONP (compatible with old browsers) no longer exists. Therefore, the suggestion for use in actual development is: do not use JSONP, but embrace CORS.

CORS scheme


Because JSONP scheme has some shortcomings (for example, only supporting Get request is hard injury), it can not well meet the needs of cross domain resource sharing. Therefore, there is a mainstream cross domain specification: CORS (cross origin resource sharing)

Different from the JSONP scheme, the CORS scheme is more powerful and practical, but it is a little complicated. The basic idea behind it is to use a custom HTTP header to "communicate" with the browser, so that the browser and the server can "understand" each other, so as to determine whether the request or response is successful or not.

Note: CORS does not appear to solve the security problem of the server, but to solve how to call resources across domains. As for how to design a secure and open API, this is the security category (for example, token verification, request validity, ip source verification and other means can be added)

The WD (working draft) of CORS began on March 17, 2009 and entered the REC (recommended standard) stage on January 16, 2014, which can be described as formal graduation. At first, the main obstacle to the promotion of CORS was that the old browsers on the market did not support it (such as IE 6, 7 and 8, which had a great market share at that time). After all, this specification is new and can only be supported by the upgraded new browser.

However, the wheel of history is always rolling forward. Now it is 2021. The support of browsers on the market for CORS specification is shown in the figure below (data source: http://caniuse.com):

Seeing this figure, it should be impolite to say that all browsers (including mobile phones, pads and other browsers) have supported CORS specification

Take Chrome browser as an example: the version I use now is 91.0 xxxx. XXX, perfect support:
At this stage, there is no need to consider browser compatibility, so the advantages of JSONP no longer exist. You can rest assured and actively embrace CORS. Since you want to use CORS, as a programmer, you can't just stay at the conceptual level. Next, let's talk about what you do and see what specific practices are implemented in CORS from the practical level?

The core meaning of CORS is to communicate with the server and browser. The server architecture is generally layered. Theoretically, communication can be completed at any level. From the level of being responsible for completing communication, it is generally divided into these two categories:

  1. The proxy server / gateway is responsible for
  2. The Web application is responsible for itself

Proxy server / gateway mode

As we all know, the general architecture will not be browser - > back-end service point-to-point, but will design (many) middle layers, such as proxy servers, gateways, etc. Like this:

In that case, we have more means to deal with Cors.

From the perspective of "distance", we can solve the cross domain problem of Cors at the place closest to the browser (traffic entrance, such as Nginx, Gateway, etc.), so that the back-end Web Server doesn't need to worry anymore, which is very convenient.

Let's take Nginx as an example to see how to land?

#
# Wide-open CORS config for nginx ### Unprotected (subtext: security risk) NG Cors configuration
#
location / {
	
	 ### In the Ng layer, all Options requests are intercepted and will not be transferred to the following web applications
     if ($request_method = 'OPTIONS') {
     
        ### Use the * wildcard to indicate that all Origin sources are allowed
        add_header 'Access-Control-Allow-Origin' '*';
        #
        # Om nom nom cookies
        #
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; ### If necessary, PUT, DELETE and other requests can be added

        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        ### Allow custom request headers (delete as needed)
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        ### Allow pre check requests to be cached for 20 days (adjust as needed)
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
     }
	
	 ### Because above OPTIONS Only allowed GET/POST So only two are listed here. Increase or decrease according to your needs ###
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
}

This is a "famous" and general configuration of Nginx to solve the Cors problem. This configuration can basically solve most cross domain request case s, but because of its universality, it has the following shortcomings:

  1. Access control allow Origin is a wildcard *, which means that all origins can access the resources of this site, and the security is low
  2. Only one access control allow origin response header is allowed (an error will be reported if there are multiple), and it is written into NG, so that the back-end Web application cannot finely control it
  3. The value of access control allow credentials is set to true. In this series Second article It is mentioned that when cross domain requests are required to carry cookie s and other authentication information, the value of access control allow origin header is not allowed to be * and the NG layer restricts this

In short, there are advantages and disadvantages in dealing with Cors nearest to the browser. The advantage is that it has good universality and "experience" is the best (web server does not need to be perceived), but we should also know its disadvantages, such as low security and poor personalization (because we can't perceive the business needs). Everything has two sides. Don't cut it across the board, but adjust measures to local conditions.

Generally speaking, the cross domain resource sharing of pure front-end static resources can be handled in the form of Ng. However, for the API interface resource management of server-side (back-end) Web applications, due to the complex scenario and high security requirements, it is more appropriate to leave it to the application to manage itself

Gateway gateway mode

Gateway can also be considered as a proxy server, which belongs to one of the middle layers. However, compared with Nginx, its programmability is stronger. Therefore, it is more flexible to put Cors logic in the gateway layer (especially intranet gateway) and has a compromise effect.

Web application mode

Web application is the "farthest" place from the browser. Solving Cors here is the most invasive to the application. However, because we can perceive the existence of services (such as knowing which interfaces and functions there are), we can achieve fine control, with the highest security and personalization. Therefore, there are many specific landing processing methods.

1. Hard coding

As the name suggests, it is solved by hard coding before / during / after the actual processing of the requested code. The code examples given in the previous articles in this series are hard coded in this way for ease of understanding.

/**
 * Add notes here
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @site https://yourbatman.cn
 * @date 2021/6/9 10:36
 * @since 0.0.1
 */
@Slf4j
@WebServlet(urlPatterns = "/cors")
public class CorsServlet extends HttpServlet {

    @Override
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doOptions(req, resp);
        setCrosHeader(resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        String method = req.getMethod();
        String originHeader = req.getHeader("Origin");
        log.info("Request received:{},method:{}, Origin Head:{}", requestURI, method, originHeader);

        resp.getWriter().write("hello cors...");
        setCrosHeader(resp);
    }

    private void setCrosHeader(HttpServletResponse resp) {
        resp.setHeader("Access-Control-Allow-Origin", "http://localhost:63342");
        resp.setHeader("Access-Control-Expose-Headers", "token,secret");
        resp.setHeader("Access-Control-Allow-Headers", "token,secret"); // Generally speaking, let the value of this header be the [subset] (or the same) of the above one
    }
}

Advantages: highly personalized, different CORS logic can be given according to the interface level, and fine control
Disadvantages: the intrusiveness rises from the application level to the business code level, which is very bloated, the granularity is too fine, and the later maintenance cost is high

2. Customize Filter/Interceptor

Since it is a Filter, it belongs to the "batch" scheme: unified logical processing of Cors for the whole application

/**
 * Add notes here
 *
 * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>
 * @site https://yourbatman.cn
 * @date 2021/6/14 09:50
 * @since 0.0.1
 */
public class CORSFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.addHeader("Access-Control-Allow-Credentials", "true");
        resp.addHeader("Access-Control-Allow-Origin", "*");
        resp.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
        resp.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");
        if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {
            resp.getWriter().println("ok");
            return;
        }
        chain.doFilter(request, resp);
    }
    
}

Advantages: unified processing at application level, non intrusive to business code. Centralized processing of Cors logic in the application, convenient maintenance
Disadvantages: the interface level granularity cannot be achieved, and there is nothing to do with the fine-grained control of some special requirements

In the final analysis, the custom Filter in the above example is still hard coded (which will affect the related header information of Cors) and is not flexible enough. In fact, it can be optimized to make it more flexible. For this reason, eBay's open source Filter scheme existed as early as N years ago: cors-filter.java For reference.

<dependency>
	<groupId>org.ebaysf.web</groupId>
	<artifactId>cors-filter</artifactId>
	<version>1.0.1</version>
</dependency>

It enables the allowed origins, methods, headers, etc. to be configurable and more flexible.

3. Spring Framework mode

Research: now there is no Java (Web) development without using the Spring Framework, right?

Since version 4.2 (2015-06), Spring has provided comprehensive support for Cors, greatly simplifying the processing of application level Cors problems. Two components are provided for developers to gracefully handle Cors problems:

  • @Cross origin: with this annotation, you can declaratively control resources across domains at the class level and even at the interface level
  • CorsFilter: Spring also provides filters for "global processing", which combines universality and flexibility
    • WebMvcConfigurer: This is a configuration method. Strictly speaking, it is not a solution, but a landing method

Since Java developers have always been dealing with Spring, they can easily use the solution in this scenario by deeply understanding its implementation principle. Therefore, this is also the top priority of this series. About this part, this series will be interpreted separately below, including the use of posture, design ideas, source code analysis

4. Spring Boot mode

As you know, Spring Boot is built on the Spring Framework. In Cors, Spring Boot does not enhance or extend it, so its posture is the same as that of the Spring Framework.

Does this once again verify the saying that how far you can go on Spring Boot depends on your depth of understanding of the Spring Framework

Cors security vulnerability

The browser's homology policy (SOP) is a security cornerstone. SOP is a good strategy, but with the development of Web applications, websites need to realize some cross domain functions due to their own business needs, so that pages in different domains can access the contents of their own pages, which leads to the SOP strategy is not so effective.

Cors is the current standard solution to the cross domain problem of browsers. If it is not used properly, it will bring security vulnerabilities and hidden dangers. The most common one is: access control allow Origin: * to the end. As everyone knows, * is used to indicate that access to any domain is allowed. This configuration is generally only used to share public resources. If it is used for non-public resources, it is equivalent to breaking down the browser's homology policy and authorizing all Origin.

In fact, this is a bit like authorized credit. When the scope of authorization is larger, it is convenient for operation / management, but it is easy to be used and attacked. Therefore, if possible, fine control (especially sensitive resources and interfaces) can be made as small as possible. After all, security is no trivial matter.

Since access control allow origin is not recommended to be configured as *, how to allow multiple domain names? For detailed analysis in the previous article in this series, please refer to: Access-Control-Allow-Origin

Security is relative. There is no absolute security or absolute security. What we can do is try our best to solve the known security problems, and don't let the "intrusion" come easily.

Comparison between JSONP and CORS

JSONP and CORS are used for the same purpose, and both need to be supported by both the server and the client. Although CORS is more powerful in terms of function, let's compare it below

  1. The main advantage of JSONP is its good support for (old) browsers, while CORS is slightly worse due to its late appearance (determined in 2014)~
    1. However, it's the same sentence: now it's 2021, and there's almost no need to think about browser support
  2. JSONP can only be used for Get requests, while CORS can be used for all HTTP methods. At this point, JSONP is completely abused
  3. JSONP's error handling mechanism is not perfect (actually not), and developers cannot handle errors when they occur. CORS can listen to error events through onerror, so you can see the details of the error to facilitate troubleshooting
  4. JSONP will only send a request once, while CORS's non simple request will be sent twice (in most cases, the request will belong to non simple request)
    1. If you don't know what simple requests and non simple requests are, read the first article in this series: Cors cross domain (I): deeply understand the concept of cross domain request and its root causes
  5. In terms of safety, there are also great differences between the two:
    1. JSONP is not a cross domain specification. It has obvious security vulnerabilities. It is manifested in: callback parameter injection (because these elements are exposed) and resource authorization cannot be restricted (that is, it can accept all Origin requests, so it is easy to be unsafe)
    2. CORS is a cross domain specification and can control resource authorization. The access control allow origin response header is the most important response header. Of course, if you set it constant to *, its security will be greatly degraded

Generally speaking, CORS has obvious advantages over JSONP. In actual production and use, forget JSONP

✍ summary

JSONP, once the only solution to cross domain problems, has made great contributions. Now it's time to retire. But we have reason to remember it. After all, heroes hope not to be forgotten (bullshit, mainly because this term is often mentioned in many new / old articles. Be careful not to be confused).

In short, as a developer in the new era, I can think that there is only one solution to cross domain problems: Cors. The next article will be "exciting": talk about the implementation of Cors in the Spring environment, and see how elegant it is

Recommended reading

System.out.println("Is it okay? Collect and see it again, point a praise and share it");
echo("Attention[ BAT Utopia] https://yourbatman.cn");
console.log("Private chat YourBatman: fsx1056342982");

I am YourBatman : a student who graduated as early as 2013 Older programmers . Internet addiction, exam clearance, delayed graduation, real estate agency, delivery of takeout, sales... Are my indelible labels.

  • 2013.08-2014.07 Ningxia Yinchuan intermediary company sold second-hand houses for one year and took the first job after graduation
  • From July 2014 to may 2015, Jingzhou / Wuhan / Beijing, engaged in fried chicken chops, selling insurance, direct selling and delivering takeout, which is the second, third, fourth and fifth job
  • Started to engage in Java development in August 2015, worked part-time, broke through outsourcing and stayed in a large factory! He is now the head of our infrastructure team.
  • Java Architect, Spring open source contributor, blog expert, domain modeling expert. Keen to write code, code cleanliness; Pay attention to infrastructure and believe that efficiency is king
  • Now write a pure technical column (get all the columns from the public account backstage reply column list), and don't make a fuss. If you have resonance, you can make progress with my friend (fsx1056342982) (Note: java)

Keywords: JQuery jsonp

Added by nodi on Mon, 24 Jan 2022 09:10:43 +0200