ajax and cross-domain
I’ve been trying to organize my knowledge on ajax and cross domains lately. First, I’ll review how ajax is written, so the big guns can bypass it on their own.
ajax
AJAX = Asynchronous JavaScript and XML. It is the art of exchanging data with the server and updating parts of a web page without reloading the entire page.
Basic writing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var xhr = createXHR();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4) {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("request was unsuccesful: " + xhr.status);
}
}
};
xhr.open("post", "postexample.php", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
xhr.send(serialize(form));
// xhr.open("get", url);
// xhr.send(null);
jquery ajax Common Writings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$.ajax({
method: "POST",
url: "example.php",
// method: "GET",
// url: "example.php?number=" + $("#keyword").val(),
dataType: "json",
data: {
name:$("#name").val(),
number:$("#number").val(),
sex:$("#sex").val(),
job:$("#job").val()
}
}).done(function(msg) {
alert("Data saved:" + msg);
}).fail(function(jqXHR, textStatus) {
console.log("Request failed: "+ textStatus);
})
Promise object implementation of Ajax
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var getJSON = function(url) {
var promise = new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open("get", url);
xhr.onreadystatechange = handler;
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
xhr.send();
function handler() {
if(xhr.onreadyState !== 4) {
return;
}
if(xhr.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
}
});
return promise;
};
getJSON("/example.json").then(function(json) {
console.log('Contenes: ' + json); // success
}), function(error) {
console.log("出错了", error); // failure
}
Cross-domain
Homologation strategy
What is cross-domain? What is same-origin policy? Same-origin policy, which restricts “documents” or scripts from different sources, is a security policy implemented by browsers for security purposes. a URL consists of a protocol, a domain name, a port, and a path. two URLs are considered to be same-origin if they have the same protocol, domain name, and port. If two URLs have the same protocol, domain name and port, they are considered to be cross-domain.
Limitations of homology policy
- Cookie, LoalStorage can’t be read
- DOM can not be obtained
- Ajax request cannot be sent
How can these limitations be broken?
- document.domain: if two web pages have the same first-level domain name and different second-level domain names, you can set the same document.domain shared cookie.
- window.name: by writing the information into window.name in the child window (iframe window, window.open window), jump back to the parent window, the parent window reads window.name, then you can get the DOM of the other side.
- window.postMessage: HTML5 cross-document messaging API (Cross-document messaging), allowing cross-window communication, including reading and writing localDtorage.
The above does not go into detail, the following details ajax cross-domain methods:
Ajax cross-domain common methods
JSONP
JSON with padding (padded JSON/parameterized JSON), i.e. JSON that is included in a function call.JSONP consists of a callback function and data. The basic idea is that since <img>, <script> can load resources from other domains without restriction, a web page requests JSON data from the server by adding a <script> element, which is not subject to the same-origin policy. The server receives the request and passes the data back in a callback function with a specified name. The JS code is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
function addScriptTag(src) {
var script = document.createElement("script");
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
function foo(data) {
console.log('success:' + data.msg);
}
window.onload = function() {
addScriptTag("https://119.29.142.213/static/201609/demo.php?callback=foo");
}
It can also be implemented using jQuery:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$.ajax({
type: "GET",
//jsonp方式只支持GET请求
url: "https://119.29.142.213/static/201609/demo.php",
dataType: "jsonp",
jsonp: "callback",
success: function(data){
if(data.success){
console.log(data.msg);
} else {
console.log("出现错误:" + data.msg);
}
},
error: function(jqXHR){
alert("发生错误:" + jqXHR.status)
}
})
The php code is as follows:
1
2
3
4
5
<?php
$jsonp = $_GET["callback"];
$result = $jsonp . '({"success":true,"msg":"msg from server"})';
echo $result;
?>
CORS (Cross Origin Resource Share)
CORS requires both browser and server support. Currently, all browsers support this feature , IE browser can not be lower than IE10. the entire CORS communication process , are automatically completed by the browser , do not need the user to participate . Only the server needs to implement the CORS interface. I tried to implement the CORS interface in php by adding the following code:
1
2
3
$origin=isset($_SERVER['HTTP_ORIGIN'])?$_SERVER['HTTP_ORIGIN']:'';
/************** 获取客户端的Origin域名 **************/
header('Access-Control-Allow-Origin:'.$origin);
The process is like this: a page on urlA fetches resources on urlB, the browser checks the HTTP header of server B (HEAD request), and if there is urlA in the Access-Control-Allow-Origin, or the wildcard *, the browser will allow the cross-domain. The request header for a successful cross-domain request is shown below. The browser finds that this cross-origin AJAX request is a simple request, it automatically in the header information, add an Origin field. Because it was sent from my local file, so here is file://.
1
2
3
4
5
6
7
8
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:119.29.142.213
Origin:file://
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
The response header is as follows, and the value of Access-Control-Allow-Origin is either the value of the Origin field at the time of the request, or a *, indicating that requests from arbitrary domains are accepted.
1
2
3
4
5
6
7
8
Access-Control-Allow-Origin:file://
Connection:keep-alive
Content-Length:12
Content-Type:text/html
Date:Wed, 21 Sep 2016 13:53:41 GMT
Server:nginx/1.0.15
Vary:Accept-Encoding
X-Powered-By:PHP/5.2.17p1
Non-simple requests (Non-simple requests are the kind of requests that have special requirements for the server, such as the request method is PUT or DELETE, or the type of the Content-Type field is application/json.) I won’t go into details here, Ruan Yifeng’s Cross-Domain Resource-Sharing CORS Explained has a more detailed explanation.
WebSocket
WebSocket uses ws:// (non-encrypted) and wss:// (encrypted) as protocol prefixes. The protocol does not have a same-origin policy, and cross-origin communication is possible through it as long as the server supports it. This protocol is specifically designed for fast transfer of small data and is suitable for use on mobile. JS Code
1
2
3
4
5
6
7
8
9
10
11
var socket = new WebSocket("ws://127.0.0.1:8888/");
var message = {
time: new Date(),
text: "Hello from my file"
}
socket.onopen = function(e) {
socket.send(JSON.stringify(message));
}
socket.onmessage = function(event) {
console.log(event.data);
}
Building a local server with NodeJS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var http = require('http');
var ws = require('ws');
var app = http
.createServer(function(req,res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello WebSocket from server');
res.end();
})
.listen(8888);
var WebSocketServer = require('ws').Server,
wss = new WebSocketServer( { server : app } );
console.log('Server running at https://127.0.0.1:8888');
The request header is as follows
1
2
3
4
5
6
7
8
9
GET ws://127.0.0.1:8888/ HTTP/1.1
Host: 127.0.0.1:8888
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: file://
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
The response header is as follows
1
2
3
4
5
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: wUpcqQA/Kzv80w5vM90HFf3WN10=
Sec-WebSocket-Extensions: permessage-deflate
The difference
- JSONP only supports GET requests, but has the advantage of supporting older browsers and the ability to request data from sites that do not support CORS.
- CORS supports all types of HTTP requests.
- WebSocket is special because it is a two-way communication.
XSS and CRSF Attacks
XSS and CSRF attacks are mentioned here in passing
XSS
XSS (Cross-site scripting), is a type of injection attack. That is, the attacker’s input enters the database without strict control, and is eventually displayed to the visiting user, resulting in the possibility of executing this code in the visiting user’s browser. For example, posting a comment and submitting content text containing JavaScript. At this point, if the server side doesn’t filter or escape this script, and it’s posted as content on the page, other users visiting this page will run this script. It could be a boring and malicious <script>alert(hahaha you can't shut me down~)</script>, or it could be a malicious modification of the site’s original data, or even loading a malicious site directly through a cross-domain request to steal cookies and login information, etc. For example, creating a malicious site that collects information, and then writing code in the comments that acquires cookies, makes a request to the malicious site, and thus contains the malicious site. code in the comments to get cookies, initiate requests to the malicious site, and thus send information containing the user’s account and other private information to the collection server. Some defenses:
- Processing, filtering, converting
<to<, etc., of inputs
CSRF (Cross-site request forgery).
- Set the HttpOnly attribute to prevent cookie hijacking, js can only read cookies with HttpOnly attribute
CSRF
XSS is one of the many ways to implement CSRF. CRSF (Cross-site request forgery), is the forgery of a request to impersonate a user’s normal actions within a site. This means that a user logs into a trusted site A and generates a cookie locally, and then visits a dangerous site B without logging out of A. The user then logs into a trusted site A and generates a cookie locally. For example, banking site A, which accomplishes bank transfers with a GET request, e.g., https://www.mybank.com/Transfer.php?toBankId=11&money=1000. Dangerous site B utilizes <img> to be able to load resources from other domains without restriction, writing the code <img src=https://www.mybank.com/Transfer.php?toBankId=11&money=1000>. In this way, your browser sends a Get request with a cookie from your bank’s website A. As a result, the bank’s web server receives the request and considers it as an update resource operation (a transfer operation), so it immediately performs the transfer operation. If the site uses POST requests, you can also use XSS to inject JS code to send POST requests and so on. Some defenses:
- Determination of referer: In the HTTP header there is a field called Referer, which records the source address of the HTTP request. The website can verify the referer value for each request and reject the request if the referer is another website. However, it is also possible that an intruder has manually changed the referer value.
- Add a token to the request address and verify: system developers can add a randomly generated token in the form of a parameter in the HTTP request and build an interceptor on the server side to verify the token, if there is no token in the request or the content of the token is incorrect, it is considered that it may be a CSRF attack and the request is rejected. If it is not safe enough to put into the address, you can also put the token into a customized attribute in the HTTP header and verify it.
For a detailed explanation, please see the reference article XSS and CSRF Attacks.