一个有效防范xss与csrf攻击的api设计 - littleboy12580/learning_python GitHub Wiki
关于XSS攻击与CSRF攻击的概念可以看我的这篇wiki:https://github.com/littleboy12580/learning_python/wiki/%E5%85%B3%E4%BA%8Exss%E4%B8%8Ecsrf
针对XSS攻击可以使用Session Cookie Storage,将cookie设为HttpOnly属性,这种情况下cookie都是直接由浏览器来自动发送的,客户端无法获取到cookie;对于客户端的请求,服务器端的响应应该加上Set-Cookie头部与Access-Control-Allow-Credentials头部且被设为true;相应的客户端发请求时也应该加上withCredentials = true这一条;具体实例如下:
客户端request:
function getAccounts() {
return new Promise(function(fulfill, reject) {
var req = new XMLHttpRequest();
req.open('GET', 'https://api.bobank.com/accounts', true); // force XMLHttpRequest2
req.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
req.setRequestHeader('Accept', 'application/json');
req.withCredentials = true; // pass along cookies
req.onload = function() {
// store token and redirect
let json;
try {
json = JSON.parse(req.responseText);
} catch (error) {
return reject(error);
}
resolve(json);
};
req.onerror = reject;
});
}
服务器端response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type,Authorization
Access-Control-Allow-Methods: GET,POST,PUT
Access-Control-Allow-Origin: https://www.bobank.com
Set-Cookie: session=15d38683-a98f-402d-a373-4f81a5549536; path=/; expires=Fri, 06 Nov 2015 09:30:15 GMT; httponly
[
{ id: 456346436, ... }
]
针对CSRF攻击可以使用token,通过将token存在Session Storage里,通过token验证用户请求;在请求中加上Authorization头部,与此同时响应的Access-Control-Allow-Headers里也应该加上Authorization;具体实例如下:
客户端request:
/**
* @return {Promise}
*/
function getAccounts() {
return fetch('https://api.bobank.com/accounts', {
headers: {
'Authorization': 'Token ' + window.sessionStorage.getItem('token'),
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
}
}).then(function(response) {
return response.json();
})
}
服务器端response:
HTTP/1.1 200 OK
Content-Type:application/json; charset=utf-8
Access-Control-Allow-Headers: Content-Type,Authorization
Access-Control-Allow-Methods: GET,POST,PUT
Access-Control-Allow-Origin: https://www.bobank.com
[
{ id: 456346436, ... }
]
对以上两种方法的比对如下表:
Approach | Vulnerable to | Immune to |
---|---|---|
Token, Web Storage and Authorization Header | XSS | CSRF |
Session cookie | CSRF | XSS |
每个方法单独用都会无法防范另一种攻击,因此最好的办法是将二者结合;即请求又得包含Session Cookie,又得有token;即既得加上Authorization头,又得加上withCredentials = true这一条;具体实例如下:
客户端request:
authenticate(login, password)
.then(function(authentication) {
window.sessionStorage.setItem('token', authentication.token); // store token
})
.then(getAccounts)
.then(function(accounts) {
// display the accounts page
// ...
})
.catch(function(error) {
// display error message in the login form
// ...
});
/**
* @return {Promise}
*/
function getAccounts() {
return fetch('https://api.bobank.com/accounts', {
headers: {
'Authorization': 'Token ' + window.sessionStorage.getItem('token'), // <= include token
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
},
credentials: 'include' // <= include session cookie
}).then(function(response) {
return response.json();
})
}
服务器端response:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type,Authorization
Access-Control-Allow-Methods: GET,POST,PUT
Access-Control-Allow-Origin: https://www.bobank.com
Set-Cookie: session=ee506a61-d51a-4145-83fd-47f63cff8b2f; path=/; expires=Fri, 06 Nov 2015 08:30:15 GMT; httponly
{
"token": "15d38683-a98f-402d-a373-4f81a5549536"
}