Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Nhiều lập trình viên frontend nghĩ bảo mật là việc của backend. Thực tế, một số lỗ hổng phổ biến nhất lại nằm ngay trong mã giao diện, và hậu quả có thể là kẻ xấu đánh cắp phiên đăng nhập hoặc thao tác thay người dùng. Bài này giới thiệu XSS và những thói quen phòng tránh thiết thực.
XSS (Cross-Site Scripting) xảy ra khi kẻ tấn công khiến trang web của bạn chạy mã JavaScript của họ trong trình duyệt của người dùng khác. Mã đó chạy với quyền của trang bạn: đọc được dữ liệu trên trang, gọi API bằng phiên đăng nhập của nạn nhân, thay đổi giao diện để lừa nhập mật khẩu.
Ví dụ kinh điển: một ứng dụng bình luận chèn nội dung người dùng gửi thẳng vào trang:
// NGUY HIỂM
document.querySelector('#binh-luan').innerHTML = noiDungNguoiDung;Nếu noiDungNguoiDung chứa một thẻ có thuộc tính sự kiện chạy mã, mã đó sẽ thực thi khi người khác xem bình luận.
location.hash) rồi ghi vào DOM một cách nguy hiểm.Dữ liệu từ người dùng, URL, API của bên thứ ba, thậm chí cơ sở dữ liệu của chính bạn (vì nó có thể chứa dữ liệu người dùng) đều phải được xử lý trước khi chèn vào trang.
// An toàn: chỉ là chữ, không phải HTML
el.textContent = noiDungNguoiDung;
// An toàn: tạo phần tử rồi gán thuộc tính
const a = document.createElement('a');
a.textContent = ten;
a.href = url; // vẫn cần kiểm tra url, xem bên dướiHãy tránh innerHTML, outerHTML, insertAdjacentHTML, document.write và eval với dữ liệu không đáng tin.
React, Vue, Angular mặc định thoát ký tự khi bạn chèn biến vào template, nên {noiDung} trong React an toàn. Rủi ro quay lại khi bạn dùng các "lối thoát" như dangerouslySetInnerHTML trong React hay v-html trong Vue. Chỉ dùng chúng khi thật cần, và với HTML đã được làm sạch.
Nếu cần hiển thị nội dung giàu định dạng từ người dùng (bài viết, bình luận), hãy làm sạch bằng thư viện uy tín như DOMPurify, thay vì tự viết biểu thức chính quy. Tốt nhất là làm sạch cả ở máy chủ khi lưu và ở nơi hiển thị.
import DOMPurify from 'dompurify';
el.innerHTML = DOMPurify.sanitize(htmlTuNguoiDung);Một URL dạng javascript:... đặt trong href có thể chạy mã khi bấm. Khi nhận liên kết từ người dùng, chỉ chấp nhận giao thức an toàn:
function laUrlAnToan(url) {
try {
const u = new URL(url, window.location.origin);
return ['http:', 'https:', 'mailto:'].includes(u.protocol);
} catch {
return false;
}
}CSP là header HTTP cho trình duyệt biết nguồn nào được phép tải script, ảnh, kiểu dáng. Nó là lớp phòng thủ thứ hai: ngay cả khi có lỗi XSS, trình duyệt có thể từ chối chạy script không nằm trong danh sách cho phép.
Content-Security-Policy: default-src 'self'; script-src 'self'; img-src 'self' https:; object-src 'none'Ví dụ trên chỉ cho phép script cùng nguồn gốc, từ chối script nhúng trực tiếp trong HTML (inline) nếu không có cơ chế nonce hoặc hash. Triển khai CSP cần thử nghiệm kỹ, bạn có thể bắt đầu bằng chế độ chỉ báo cáo (Content-Security-Policy-Report-Only) để xem cái gì sẽ bị chặn trước khi áp dụng thật.
Mã thông báo (token) lưu trong localStorage hay sessionStorage mà mã JavaScript đọc được thì sẽ bị lấy nếu có XSS. Nhiều đội ưu tiên cookie với các thuộc tính HttpOnly (JavaScript không đọc được), Secure (chỉ gửi qua HTTPS) và SameSite (giảm nguy cơ CSRF). Mỗi cách đều có đánh đổi, hãy chọn dựa trên kiến trúc của bạn và hỏi đội backend.
npm audit để phát hiện lỗ hổng đã biết.integrity) khi nạp từ CDN.rel='noopener noreferrer' cùng target='_blank'.Hãy ghi nhớ: không tin dữ liệu bên ngoài, ưu tiên textContent và cơ chế thoát ký tự của framework, làm sạch HTML bằng thư viện uy tín, kiểm tra URL, dùng CSP như lớp bảo vệ bổ sung và giữ bí mật ở máy chủ. Bảo mật là thói quen hằng ngày, không phải tính năng thêm vào cuối.
Để xây dựng ứng dụng web an toàn từ cả hai phía frontend lẫn backend, bạn có thể tham khảo các khóa học tại codebem.com.
Nguyễn Đình Cường
0 comment