一个有效防范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攻击

针对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攻击

针对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"
}
⚠️ **GitHub.com Fallback** ⚠️