Cross-domain refers to the restriction of interaction between two different domains (websites) due to the same origin policy of the browser. Cross-domain does not mean that the request is not sent or responded to. The browser sends the request and the server responds normally after receiving the request, but because the browser’s same-origin policy intercepts the returned response, it returns us a cross-domain error.
The same origin policy of the browser
The same origin policy is an important security policy. It is the core and basic security function of the browser. It is used to restrict how documents from one source or scripts loaded by it can interact with resources from another source. It can help block malicious documents and reduce the number of vectors that can be attacked.
homologous
According to the RFC – 1738
In general, URLs are written as follows: <scheme>:<scheme-specific-part>
In reality, a URL on a browser usually consists of the following
// protocol: protocol // host: host // domain: domain name // port: port // path: resource path/request path // query: Parameters (get) protocol: / / host. Domain: port/path? queryCopy the code
If the protocol, host + domain name, and port of two urls are the same, the two urls are the same. This scheme is also called “protocol/host/port tuple”. Internet Explorer has the following two differences in the same origin policy:
- Credit scope: Two domain names with high mutual trust are not restricted by the same Origin policy
- Port: The Internet Explorer does not include the port in the same-origin policy check, that is, the same protocol, host and domain name means same-origin.
URL | performance | why |
---|---|---|
www.test.com/page1 www.test.com/page2 | homologous | Different paths |
www.test.com/page1 www.test.com/page1 | Different source | Agreement is different |
www.test.com/page1 test.test.com/page1 | Different source | The host different |
www.test.com/page1 www.qq.com/page1 | Different source | Domain name is different |
www.test.com/page1 www.test.com:8080/page1 | Different source | Different ports |
http://localhost/page1 http://127.0.0.1/page1 | Different source | The host different |
The setting of the source
Scripts executed on a page with about:blank(opening a browser blank page) or javascript:URL(pseudo-protocol) inherit the document source that opens the URL, because these types of urls do not contain information about the source server. In some cases, you can change the source of a page:
- This can be set by script
document.domain
Is the current domain or the parent domain of the current domain. If set to the parent domain of the current domain, the parent domain is used for subsequent source check - any
document.domain
Will cause the port number to be overwritten to NULL
When you set document.domain to communicate with the parent domain, the parent and child domains must be set to the same value (domain name + port).
Cross-domain network access
- Cross-origin writes are generally allowed, such as links, redirects, and form submissions
- Cross-origin embedding is generally allowed, such as script, IMG, video, and iframe
- Cross-origin reads: generally not allowed, such as DOM, JS objects, cookies, LocalStorage, IndexDB, ajax requests
Block cross-source access
- Cross-domain writes are prevented by simply detecting an unguessed token (CSRF token) in the Request, known as the Cross-site Request Forgery token
- To prevent cross-domain reading of a resource, ensure that the resource is not embeddable. Blocking embedded behavior is necessary because embedded resources often expose information to them
- Prevent cross-site embedding and ensure that your resources are not in the permitted embedding resource format described above
So how do you solve cross-domain problems
window.name
In the life cycle of a window, all pages loaded by the window share a window.name, and each page has read and write permission to window.name. Window. name can persist in all pages loaded by a window, and can store a string of 2M.
Drop the domain
Domain is set to achieve cross-domain, but only applicable to the domain of the same secondary domain name, used to realize the interaction between different subdomain frameworks. Refer to the source Settings above.
JSONP
JSON with Padding, because of the same-origin policy, the data on the different fields in the Ajax request cannot be retrieved (cross-origin reads), but (cross-origin reads) Embedding) cross-domain resource embedded still is possible, so we can by calling the cross-domain dynamically generated js format file on the server, to get the cross domain data on the server, but this is just to download the data, how to provide the data to our memory to call, this needs to define a callback function, the server dynamically generated js, Kevin The file contains a callback(response), which is executed to add cross-domain data to memory after the JS load is complete. It works like this: the client defines a callback function, and the server calls this function and takes the response as an argument to complete the callback to retrieve cross-domain data.
# html
<script>
function callAlert(data){
alert(data,'-------data')
}
const url = 'http://www.test.com/search?callback=callAlert'
const script = document.createElement('script')
script.src = url
document.body.append(script)
</script>
# php
exit($_GET['callback'].'({errNo:0,data:"success"})')
Copy the code
- Advantages: Good compatibility with JSONP
- Disadvantages: Only support for GET(essentially implemented through resource embedding, root XMLHttpRequest irrelevant); Can only solve the cross-domain request, can not solve the communication problem of different domain pages or IFrames; JSONP generates JS dynamically from other domains and may carry malicious code; If you encounter a server-side error and cannot handle it (XMLHttpRequest has a better error handling mechanism than JSONP)
Empty iframe + Form
JSONP can only implement GET requests across domains. For POST requests across domains, we can use an empty IFrame + form form to implement cross-domain requests without the same origin policy restriction.
const iframe = document.createElement('iframe') iframe.name = 'test' iframe.style.display = 'none' Document. The body. The appendChild (iframe) / / submit successful, callback to handle iframe. OnLoad () = = > {the console. The log (' success ')} / / form cross-domain const operation form = document.createElement('form') const input = document.createElement('input') input.name = 'data' input.value = 'xxx' Iframe form.target = 'test' form.action = url form.method = 'post' = 'none' form. Style. Display the document. The body. The appendChild (form) form. Submit () / / cross domain is completed, remove the form document. Body. RemoveChild (form)Copy the code
CORS(Cross-Origin Resource Share)
Cross-domain resource sharing is a mechanism based on HTTP headers (a new set of HTTP header fields is added). It allows the server to declare which source sites can access which resources through the browser, so that the browser can access cross-domain networks, and cross-domain data transmission can be carried out safely, overcoming the restriction of the same Origin policy. There is also a mechanism to check whether the server will allow real requests to be sent. For HTTP requests that may have adverse effects on server data, the browser must first initiate a preflight using the OPTIONS method Request), so as to know whether the server allows the cross-domain request. After confirming the permission, the actual HTTP request can be launched. In the return of the pre-check request, the server can also inform the client whether the identity certificate needs to be carried.
- The whole CORS communication process is completed automatically by the browser without user participation. Once the browser finds that ajax requests cross domains, it will automatically add some additional header information. Therefore, the key lies in the server, which needs to process new request headers and response headers to realize THE CORS interface.
- Cors requests fail to generate an error, but for security, there is no way to know what went wrong at the JS code level, only through the browser console
- Scenarios supported by CORS: cross-domain HTTP requests initiated by XMLHttpRequest or Fetch; Web fonts; WebGL map; Draw Images/video Images to canvas using drawImag
Browsers classify CORS requests into two types: simple and complex
- Simple request (does not trigger CORS precheck request)
- The request method can be GET, POST, or HEAD
- In addition to header fields automatically set by the user agent and other headers defined as disabled header names in the Fetch specification, HTTP headers include :Accept, Accept-language, Content-Language, Content-Type, (DPR, Downlink, Sav E-data, viewport-width, Width —- unknown)
- Content-type is one of the following: Text /plain, multipart/form-data, Application/X-www-form-urlencoded
- Not used in the request
ReadableStream
Object (unknown) - Any of the requests
XMLHttpRequestUpload
Objects are not registered with any event listeners,XMLHttpRequestUpload
Can be achieved byXMLHttpRequest.upload
Access (unknown)
GET /resource/public-data/ HTTP/1.1 HOST:bar.other... Origin: / / http://foo.example suggested that request source/head/response HTTP / 1.1 200 OK... Access-control-allow-origin: * // Indicates that the resource can be accessed by any external domain. This field indicates the accepted source access-Control-allow-credentials: True // Indicates that cORS is allowed to Access with cookie access-Control-expose-headers: cache-control. // The response header that cORS can Access is content-Type: application/ XMLCopy the code
- Complex request: All non-simple requests are complex and trigger cORS precheck requests
- Precheck request: browser usage
OPTIONS
Method sends a request to the server to know whether the server will allow the actual request, avoiding the unexpected impact of a cross-domain request on the server’s user data.
- Precheck request: browser usage
// Request header OPTIONS /resources/post-here/ HTTP/1.1 Host: bar.other... Origin: http://foo.example access-Control-request-method: POST // Informs the server that the actual Request is made using the POST Method access-Control-request-headers: X-pingother, content-type // Tell the server the actual request, carrying two custom header fields, x-pingother and Content-Type // response header HTTP/1.1 200 OK... Access-control-allow-origin: http://foo.example // Source access-control-allow-methods: Access-control-allow-headers: access-control-allow-headers: X-pingother, content-type // The server allows custom request headers access-Control-max-age: 86400 // The validity period of the precheck request, during which no precheck request needs to be sent for the same request // Actual request // request header POST /resources/post-here/ HTTP/1.1 Host:bar.other... origin: http://foo.example X-PINGOTHER:pingpong Content-Type:text/xml; Charset = utF-8 // Response header HTTP/1.1 200 OK... Access-Control-Allow-Origin: http://foo.example ...Copy the code
Note that:
- Most browsers do not support redirection of prechecked requests. The server can either remove the prechecked request redirection or turn the actual request into a simple request
- XMLHttpRequest or Fetch can initiate credential CORS access based on Cookies and HTTP authentication information, but it needs to be in the script
XMLHttpReuest.withCredentials
Set to true, otherwise the browser will not carry it automatically, and the server needs to set it in the response headerAccess-Control-Allow-Credentials:true
Otherwise, the browser will not return the response - The server may not set requests that carry credentials
Access-Control-Allow-Origin:*
Otherwise, the request will fail and must be set to a specific domain
PostMessage (new html5 feature)
IE8, Chrome, Firefox, Opera and other browsers support sending messages to other Window objects (whether the window object is cognate or not).
- Data transfer between a page and its open window
- Data communication between multiple Windows
- Page with nested IFrame message delivery
// otherWindow: reference to otherWindow objects // message: data to be passed // target: window or address to be sent, can be a string "*" or a URI // transfer: PostMessage (Message, Target,[Transfer]) is a string of Transferable objects that are passed with Message. Ownership of these objects is transferred to the receiver of the message. The sender no longer owns otherWindow.postMessage(Message,target,[Transfer]) // to receive the message Windiw.addeventlistener ('message',({source,origin,data}) => {// source: message window // origin: message destination url // data: message... })Copy the code
WebSocket
WebSocket is a communication protocol that enables full-duplex communication over a single TCP connection. WebSocket makes it easier to exchange data between the client and the server, allowing the server to actively push data to the client. In the WebSocket API, the browser and server only need to complete a handshake to establish a persistent connection and two-way data transfer.
Different from HTTP protocol, the client can only initiate a request and the server can respond. WebSocket can realize two-way communication between the client and the server
- Based on TCP protocol, the server is easy to implement
- It has good compatibility with HTTP protocol. The default ports are 80 and 443. HTTP protocol is used in the handshake phase, which is not easy to shield and can pass various HTTP proxy servers
- The data format is lightweight and the performance cost is low. When the client and server exchange data, the data header from the server to the client is only 2-10 bytes, and the client to the server needs to add a 4-byte mask. However, the Http protocol carries a complete header each time
- Better binary support, can send text and binary data
- There is no homology restriction
- The protocol identifier WS (Encryption: WSS), the request address is the backend webSocket-supporting API
The client initiates an Http handshake, notifies the server to use the WebSocket protocol for communication and the WebSocket protocol version, and the server confirms the protocol version and upgrades it to the WebSocket protocol. After the upgrade, subsequent data exchanges follow the Websocket protocol.
// Handshake phase // request header connection: upgrade // Upgrade protocol: upgrade websocket // Upgrade to websocket sec-websocket-version: 13 // The updated protocol version, if not supported by the server, returns the response header containing sec-websocket-versionheader, including the version number supported by the server sec-websocket-key: Bwb9SFiJONXhQ /A4pLaXIg== // Sec-websocket-accept corresponds to the server response header. Since there is no origin restriction, the WebSocket client can support WebSocket service any time. This field is equivalent to the identifier to avoid unnecessary connections . // The response header... Connection: upgrade // Upgrade protocol upgrade: websocket // Upgrade to websocket sec-websocket-accept: 2 jrbcwscplzptxarlgtp4y8xd20 = / / agreed to launch a connection to inform the client server, calculate according to the request header Sec - websocket - Key value.Copy the code
WebSocket API
- Create a connection
const ws = new WebSocket('wss://echo.websocket.org')
- Websocket. readyState: indicates the current status of webSocket connections
- CONNECTING = 0, where a connection is being established.
- OPEN = 1, the connection is successful and communication can be performed;
- ClOSING = 2, ClOSING;
- CLOSED = 3, the connection fails to be CLOSED or opened
- The connection was successfully established
ws.onopen = () => {... }
- Connection establishment failure callback
ws.onclose = () => {... }
- The server data is received. Procedure
ws.onmessage = ({data}) => {... }
- Sends data to the server
ws.send(data)
- How many bytes of binary data are left unsent, and determine if the sending is over,
ws.bufferedAmount
- An error correction
ws.onerror = (evt) => {... }
Nginx | Node | Apache proxy server (reverse proxy) cross-domain
CSRF(Cross-Site Request Forgery)
Cross-site request forgery, in which requests are made to the server by masquerading as a trusted user.
Defense:
- Referer: Forged requests are generally initiated from third-party websites, so as long as the referer in the request header is not the site, it is judged as CSRF (only cross-site CSRF can be defended, not the site CSRF).
- Verification code: The third-party website cannot obtain the verification code
- Token: Each web page contains tokens generated by the server, which will be passed to the server for judgment upon submission
- Post: A POST request is more secure than a GET request.