Solve JS cross-origin problems
Article category: Web Front-endHow to solve JS cross-origin problems
Javascript cross-origin is one of the most common problems for Web developers. The so-called JS cross-origin problem refers to the Access to Data Objects in another different domain through JS on a page in one domain. For security consideration, almost all browsers do not allow this cross-origin access, this causes cross-origin web services to become a problem in some Ajax applications. Currently, there are some ready-made solutions on the client and server to solve JS cross-origin problems, but these solutions cannot solve all problems. Next, let's take a look at some common solutions and provide a space solution based on the Cross-Domain problem requirements of space products. We hope it can be used for reference by other product groups.
Client Solution
Almost all web developers will first consider how to solve JS cross-domain issues on the client. Currently, there are two most common methods: setting document. domain and loading through script labels.
Set document. Domain
The premise of using this method is that the two pages involved in the cross-origin request must belong to a basic domain (for example, both xxx.com and xxx.com.cn) and use the same protocol (for example, all pages are HTTP) and the same port (for example, both 80 ). For example, if a page in aaa.xxx.com needs to call an object in bbb.xxx.com, set the document. domain of both pages to xxx.com to implement cross-origin calls. In addition, you must note that this method can only be used in parent and child pages, that is, it is only useful when using IFRAME for data access.
Load with Script labels
For the browser, the src attribute of the script tag points to the resource, just like the src attribute of the IMG Tag points to the resource, it is a static resource, the browser automatically loads these resources when appropriate, without the so-called cross-origin issue. In this way, we can reference the data object to be accessed through this attribute to the current page and bypass the JS cross-origin issue. For example, in space projects, you need to randomly recommend several popular modules on the Management Center page under the HI domain to users, because the related information of popular modules is maintained by the PHP module in the ACT domain, if you directly obtain information about the list of Recommendation modules in the ACT domain through Ajax requests in the hi domain, the JS cross-origin issue occurs. The simplest way to solve this problem is to access the HTTP interface provided by the Act domain through the script tag in the hi domain:
<script type=”text/javascript” src=”http://act.hi.baidu.com/widget/recommend”><script>
Of course, the premise is that the HTTP interface of the Act domain must return a JS script, such as a script defined by a JSON object array:
modlist = [{“modname” : “mod1”, “usernum” : 200, “url” : ” /widget/info/1”},{“modname” : ”mod2”, “usernum” : 300, ”url” : ” /widget/info/2”},…];
But the script tag also has some limitations and cannot solve all JS cross-origin problems. The src attribute value of the script tag cannot be dynamically changed to meet the needs of obtaining different data under different conditions. More importantly, you cannot correctly access the data organized in XML content in this way.
Server Solution
From the above description, we can see that the client solution has too many limitations and that AJAX cross-origin requests cannot be solved on the client regardless of whether the two domains belong to the same basic domain. That is to say, if we want to access data in other domains in the Ajax request, we can only process the data through the server. The basic principle of the server solution is that the client sends the request to the local server, and then the agent of the local server requests the data and returns the response to the client. The most common server solution is to use the proxy function provided by the Web server, such as the mod_proxy module of Apache and Lighttpd. In Baidu, the transfer function can also solve some cross-domain problems. However, these methods have some limitations. In view of security and other issues, space finally developed a spproxy module dedicated to processing cross-origin request proxy services, it is used to completely solve JS cross-origin problems. Next we will take the open space platform as an example to briefly introduce how to solve this cross-origin problem through the mod_proxy of Apache, the shunting of Transmit, And the spproxy module of space, this section briefly introduces some features and disadvantages of spproxy and the next improvement plan. Before displaying each UWA open module, the space must request the XML source code of the module for parsing. The source code files of each module are stored in the/ow/UWA directory under the Act domain, the JS cross-origin issue occurs when the XML file is requested on the user space homepage (Hi domain. To solve this problem, JavaScript can only request XML files from the Web server of the HI domain, while the HI domain web server uses a certain proxy mechanism (such as mod_proxy, transmit shunting, spproxy) request a file from the web server in the ACT domain.
Use the mod_proxy module of Apache
If Apache is a 2.0 series version, you can add the following configuration in the httpd. conf file:
ProxyRequests Off<Proxy *>Order deny,allowAllow from all</Proxy>ProxyPass /ow/uwa http://act.hi.baidu.com/ow/uwa
The proxyrequests command disables the forward proxy function of mod_proxy and enables the reverse proxy function. The PROXY Command makes this configuration effective for all accesses, the proxypass command converts access to any resources in the/ow/UWA directory of the current domain into a proxy request for resources in the/ow/UWA directory of the act.hi.baidu.com domain.. In this way, JS can directly obtain the 0/1. xml file in the/ow/UWA/10001/0/directory under the Act domain by accessing the http://hi.baidu.com/ow/uwa/0/1/0/10001.xml.
If Apache is a version 1.3 that has been modified by Baidu's product lines, the mod_proxy and mod_rewrite modules must be used together to achieve the same purpose. First, add the following location command in httpd. conf:
<Location /ow/uwa>SetHandler proxy-serverorder allow,denyAllow from all</Location>
In this way, access to any resources under the/ow/UWA directory in the current domain will first be handled by the proxy-server handler (a handler defined in the mod_proxy module, however, this configuration does not work, because the proxy-server does not know how to handle it, but it only needs to be handled by itself. In this case, you also need to add a rewrite rule in the configuration segment:
RewriteRule ^/ow/uwa/(.*)$ http://act.hi.baidu.com/ow/uwa/$1?%{QUERY_STRING} [P,L]
[P, L] at the end of the rewrite rule indicates that the rewrite passes through the mod_proxy proxy instead of the external redirection. If the P Flag is removed, the following rewrite rules are used:
RewriteRule ^/ow/uwa/(.*)$ http://act.hi.baidu.com/ow/uwa/$1?%{QUERY_STRING} [L]
Then, the resource URI returned to the client on time scale will be the redirected URI. In our example, the uri of the act.hi.baidu.com domain will still cause cross-domain JavaScript in the browser. The above is just a simple application of Apache's proxy function. For more powerful introduction, see [1] and [2 ]. Although mod_proxy is powerful, it is not used to solve cross-domain problems. First, each front-end machine must be able to access the Internet, otherwise, the request proxy can only be sent to one of the front-end machines (rewrite or proxy by using the machine name as the Intranet domain name), which is obviously not desirable, because one of our domain names is usually composed of many front-end machines, acting only on one of them will cause the pressure on this machine to be unbalanced compared with other machines, or even unable to support the pressure, adding Internet access permissions to all front-end machines may cause some security policy problems (the specific reasons are unclear, but op and SA obviously do not agree with this approach ). Secondly, because Apache does not have a good anti-DDoS mechanism, once someone uses a proxy to attack the target domain (such as our competitor's website ), from the perspective of the web server in the target domain, the attacker became us. When such a thing happened, we were completely confused.
Use the transmit shunting Solution
The product line that has used transmit should know that in addition to attack prevention, transmit also has an important function of shunting. With the shunting function, we can distribute access to specific URLs to different Apache for cross-origin access. Let's take the example of a spatial open platform as an example. Suppose our act domain is composed of two machines, jx-space-act00.jx and jx-space-act01.jx, In the JX data center. The port of Apache is 8080, as long as the following configuration is added to the transmit configuration file transmit_common.conf:
PP_APACHE_DIR : /ow/uwa/PP_APACHE0 : jx-space-act00.jx:8080PP_APACHE1 : jx-space-act01.jx:8080
After the transmit is restarted, users in the south can access the http://hi.baidu.com/ow/uwa/0/1/0/10001.xml to obtain the issue. If we want to asynchronously obtain other data in the ACT domain, such as the data provided by the/sys/widget/xxx interface, in JS in the hi domain, you only need to add a directory definition in the pp_apache_dir configuration item:
PP_APACHE_DIR : /ow/uwa/, /sys/widget/
Because the old version of transmit only supports one shunting, it cannot be used to simultaneously solve cross-domain requests to multiple external domains. At the same time, it must support the old version of transmit, the back-end Apache requires corresponding code modification and configuration, which also limits our shunting function and cannot solve cross-domain Cross-Domain problem across non-Baidu domains. However, the good news is that the new version of Transmit recently released by GM allows n shunting requests and does not make any modifications to backend Apache. Therefore, the limitations on the old version of Transmit will no longer exist, it can solve the cross-domain problem to a certain extent. The specific configuration method is similar to that of the old version. You can refer to the configuration file of the new version transmit to modify it accordingly.
Use the spproxy Module
However, in space's Open Platform System, we didn't solve cross-origin problems through transmit. As mentioned above, transmit can only solve this problem to a certain extent. Why? Because you need to restart the transmit program after modifying the configuration to increase the traffic distribution, and its performance will decrease as the Traffic Distribution Branch increases, after all, when each request arrives, it needs to traverse all the shunting branches to determine which branch should be taken. For open platforms, any new open module may introduce one or more new external domains, which causes the number of distributed branches of Transmit to linearly increase with the increase of the number of open modules, this will be unacceptable in both op O & M and program performance. Based on this consideration, space introduced a new module, the spproxy module, in the second phase of the open platform project, to provide the cross-origin request proxy service, thus completely solving the JS cross-origin problem. In a sense, spproxy is actually a UI. It receives a request from Apache, processes the request to obtain real page data, and then returns it to Apache, then, Apache returns the result to the client. Spproxy only receives one Apache command number (ac_sys_proxy: 38) and provides two HTTP interfaces:
/Sys/pxy/Ajax? Url = XXXX and/sys/pxy/XML? Url = xxx
Among them,/sys/pxy/can be modified to another directory name through the Apache configuration file. The URL parameter is the URI of the data that JS wants for cross-origin requests (URL encoding is required, if there are parameters in the URL), the only difference between the XML interface and the Ajax interface is that spproxy forcibly sets the Content-Type returned by the former to text/XML, while for the latter, the Content-Type returned by the external Domain Server is the type. The Apache end only needs to add the following two configurations to allow spproxy to process the requests of the above two HTTP interfaces. Of course, the premise is that the apache used is an Apache that has been rewritten by ns, currently, Apache 1.3 is the main version:
CmdNoMap pxy 38CmdHost pxy 10.23.64.185 20540
Pxy is the second directory name in the HTTP interface and can be customized. For example, if proxy is written in the configuration, the HTTP interface is/sys/Proxy/Ajax? Url = xxx and/sys/Proxy/XML? Url = xxx; 38 is the command number that spproxy can process and can be changed to another value during compilation; 10.23.64.185 20540 is the IP address of the machine where spproxy is located and the listening port of spproxy. Through the above configuration, the JS under the HI domain can be accessed through asynchronous http://hi.baidu.com/sys/pxy/xml? Url = http: // container/UWA/0/1/0/10001. xml. If the resource URI for cross-origin access has parameters such as http://act.hi.baidu.com/widget/recommend? Num = 6, then the parameter value needs to be URL encoded during access, such as http://hi.baidu.com/sys/pxy/XML? Url = http % 3A % 2f % 2 fact % 2ehi % 2 ebaidu % 2 ECOM % 2 fwidget % 2 frecommend % 3 fnum % 3d6.
Spproxy Introduction
Spproxy is a single-process module developed based on the epoll network model. It contains a data capture thread and a timed loading thread. It captures the thread and acts as a proxy for cross-origin requests, captures the page content corresponding to the specified URL and returns it to the front-end. This thread uses the epoll model to increase the concurrency of request processing and regularly loads the thread, regularly load the domain name White List and some reload configuration items (such as various time-out times, whether to forcibly specify the cache expiration time, etc) spproxy uses a domain name whitelist to restrict domain names that can be accessed across domains in JavaScript to reduce security risks, you only need to add a line to spproxy's domain name whitelist file spproxy_domainlist.txt when adding a JS external domain that can be accessed across domains. This will take effect after 5 minutes (the specific effective time can be configured. Because the epoll network model is used, spproxy can defend against slow connection attacks. It also has the same powerful anti-attack function as space UI. To reduce requests to external domain servers to improve the response speed of cross-origin requests and reduce the risk of blocking our proxy services by external domain servers, spproxy itself provides a relatively simple cache function. If the cache expiration time is specified in the HTTP header of the page returned by the external Domain Server, spproxy calculates a reasonable expiration value for the page's cache expiration time based on the HTTP header and caches the page; if no cache expiration time is specified in the HTTP header returned by the external Domain Server or the cache is not required, spproxy will continue to cache the page for a short period of time. The expiration time can be configured. In addition, most of the time-out configurations and domain name whitelists involved in the spproxy module can be reloaded at regular intervals, so as to adjust the parameters of online services and increase the trust domain, the Service does not need to be restarted to invalidate the cache. However, spproxy still has some disadvantages: The response body returned to spproxy cannot be compressed and encoded. spproxy will indicate this in the HTTP header when requesting from an external domain, this increases the read response time and bandwidth consumption of external domain websites. Currently, spproxy only calculates the page cache expiration time based on the max-age attribute in the cache-control field in the HTTP Response Header of the external Domain Server, in fact, the cache-control fields returned by many websites do not use Max-age to indicate the cache expiration time. Currently, spproxy only supports the get method and does not support other HTTP methods, spproxy does not support any size of external domain pages, but you can change the configuration to the next step by changing the maximum page data volume it can receive, spproxy will make some improvements in parsing the cache-control field in the HTTP response header to control the cache of the spproxy on the returned page more rationally. In addition, the next step will also support cross-origin requests through the POST method to improve cross-Origin Security of domain requests.
References
[1] http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_proxy.html
[2] http://lamp.linux.gov.cn/Apache/ApacheMenu/rewrite/rewrite_guide.html