Trả lời nhanh: XSS (Cross-Site Scripting) là lỗ hổng ứng dụng web khiến trình duyệt của người dùng chạy đoạn mã do kẻ tấn công chèn vào, trong khi người dùng tin rằng đang xem trang hợp lệ. Hậu quả gồm chiếm phiên đăng nhập, thao tác thay người dùng và hiển thị biểu mẫu giả. Cách chặn chính là mã hoá đầu ra theo ngữ cảnh.
Điểm chính
- XSS xảy ra khi dữ liệu người dùng nhập được đưa ra trang web mà không mã hoá đúng ngữ cảnh, nên trình duyệt coi nó là mã.
- Có 3 loại: Stored (lưu trên máy chủ), Reflected (phản chiếu từ URL) và DOM-based (lỗi ở JavaScript phía trình duyệt).
- Rủi ro lớn nhất với doanh nghiệp là Stored XSS xuất hiện ở trang nhân viên hoặc quản trị xem.
- Phòng chống theo nhiều lớp: mã hoá đầu ra, CSP, cookie HttpOnly và SameSite, kiểm thử. WAF chỉ là lớp bổ trợ.
Mục lục
- XSS là gì?
- XSS hoạt động thế nào?
- Có mấy loại XSS và khác nhau ra sao?
- Kẻ tấn công làm được gì với XSS?
- Ví dụ minh hoạ: ô ghi chú đơn hàng và trang quản trị
- Phòng chống XSS bằng cách nào?
- Làm sao kiểm tra website có lỗi XSS?
- Dấu hiệu bị khai thác và cách xử lý sự cố
- XSS khác SQL injection, CSRF và phishing thế nào?
- Khi nào cần ưu tiên xử lý XSS?
- Câu hỏi thường gặp
XSS là gì?
XSS là viết tắt của Cross-Site Scripting, tạm dịch là “chèn mã kịch bản chéo trang”. Tên viết tắt là XSS chứ không phải CSS để tránh nhầm với Cascading Style Sheets. Đây là lỗ hổng trong ứng dụng web: ứng dụng nhận dữ liệu từ người dùng rồi đưa lại vào trang HTML mà không xử lý đúng. Trình duyệt không phân biệt được đâu là nội dung và đâu là mã, nên chạy luôn đoạn mã do kẻ tấn công gài vào.
Điểm dễ hiểu sai là nạn nhân của XSS thường không phải máy chủ mà là người dùng đang mở trang. Kẻ tấn công không cần vào hệ thống của bạn. Chúng chỉ cần một ô nhập liệu hoặc một tham số URL mà ứng dụng tin tưởng quá mức. Mã chạy trong ngữ cảnh của tên miền của bạn, nên trình duyệt cho nó quyền như chính trang của bạn: đọc nội dung trang, gửi yêu cầu kèm phiên đăng nhập, sửa giao diện.
Về phân loại, XSS từng có mục riêng trong OWASP Top 10 bản 2017 (A07:2017). Từ bản 2021 nó được gộp vào nhóm Injection (CWE-79). Theo OWASP Top 10:2025, Injection đứng hạng 5 (trước đó là hạng 3) và vẫn bao gồm XSS cùng SQL injection và command injection, theo tổng hợp của Reflectiz: Injection tụt từ hạng 3 xuống 5 nhưng vẫn nằm trong số các điểm yếu bị khai thác nhiều, và XSS được nhiều tài liệu OWASP coi là một nhánh của injection. Lý do gộp là cơ chế giống nhau: dữ liệu không tin cậy đi vào nơi diễn giải nó thành mã, chỉ khác là bộ diễn giải ở đây là trình duyệt thay vì cơ sở dữ liệu.
XSS hoạt động thế nào?
Có ba thành phần luôn xuất hiện trong mọi vụ XSS:
- Nguồn (source): nơi dữ liệu không tin cậy đi vào, như ô bình luận, tên hồ sơ, tham số tìm kiếm trên URL, phần sau dấu # của địa chỉ, tên file tải lên.
- Điểm đổ (sink): nơi dữ liệu được ghép vào trang theo cách trình duyệt có thể diễn giải thành mã, ví dụ ghép thẳng vào HTML, vào thuộc tính sự kiện hoặc vào hàm của JavaScript.
- Thiếu mã hoá: giữa nguồn và điểm đổ không có bước chuyển ký tự đặc biệt thành dạng hiển thị an toàn.
Hình dưới mô tả đường đi của loại nguy hiểm nhất, Stored XSS.
Bài này không đưa chuỗi mã khai thác. Điều bạn cần nắm là bước 3: chỉ cần ứng dụng ghép dữ liệu vào trang mà không mã hoá thì bước 4 sẽ xảy ra với bất kỳ ai mở trang đó.
Có mấy loại XSS và khác nhau ra sao?
| Tiêu chí | Stored | Reflected | DOM-based |
|---|---|---|---|
| Mã độc nằm ở đâu | Cơ sở dữ liệu hoặc file nội dung của máy chủ | Trong URL hoặc yêu cầu, máy chủ trả lại ngay | Trong URL hoặc nguồn phía client, máy chủ có thể không thấy |
| Nạn nhân phải làm gì | Chỉ cần mở trang có nội dung bị nhiễm | Phải bấm vào liên kết được chế tạo sẵn | Thường cũng phải mở một liên kết hoặc trang cụ thể |
| Phạm vi ảnh hưởng | Mọi người xem trang, có thể lan rộng | Từng người bị dẫn dụ | Từng người bị dẫn dụ |
| Vị trí sửa lỗi | Mã phía máy chủ khi xuất nội dung | Mã phía máy chủ khi trả lại tham số | Mã JavaScript phía trình duyệt |
| Khó phát hiện ở đâu | Nội dung bẩn nằm sẵn trong dữ liệu cũ | Không để lại dấu trong dữ liệu, chỉ thấy trong log yêu cầu | Có thể không xuất hiện trong log máy chủ |
Hai điểm hay bị bỏ qua. Thứ nhất, DOM-based XSS có thể không để lại dấu vết trong log máy chủ vì phần xử lý diễn ra hoàn toàn trên trình duyệt. Rà log truy cập sẽ không đủ, phải kiểm tra mã JavaScript. Thứ hai, ba loại này không loại trừ nhau: một ứng dụng có thể vừa lưu dữ liệu bẩn, vừa dùng JavaScript phía client để vẽ lại chúng không an toàn.
Kẻ tấn công làm được gì với XSS?
Nhiều người nghĩ XSS chỉ là làm hiện một hộp thoại cho vui. Thực tế, vì mã chạy với quyền của trang, nó có thể:
- Chiếm phiên đăng nhập: đọc cookie hoặc token nếu chúng không được đánh dấu HttpOnly, hoặc đọc token lưu trong bộ nhớ trình duyệt của trang.
- Hành động thay người dùng: gửi yêu cầu đổi email, đổi mật khẩu, tạo lệnh chuyển tiền hay duyệt đơn, vì yêu cầu đến từ chính trình duyệt đã đăng nhập. Cách này vẫn hiệu quả ngay cả khi cookie được bảo vệ.
- Dựng giao diện giả: chèn biểu mẫu đăng nhập hoặc yêu cầu nhập mã xác thực ngay trên tên miền thật, rất khó phân biệt với lừa đảo phishing thông thường vì thanh địa chỉ vẫn đúng.
- Ghi lại thao tác bàn phím trên trang, hoặc đổi hướng người dùng sang trang khác.
- Phát tán tiếp: sâu XSS tự lan bằng cách tự đăng lại nội dung độc trong hồ sơ người dùng. Vụ sâu Samy trên mạng xã hội MySpace năm 2005 là ví dụ kinh điển về loại này.
Ví dụ minh hoạ: ô ghi chú đơn hàng và trang quản trị
Ví dụ minh hoạ (giả định): một cửa hàng trực tuyến cho khách nhập “ghi chú giao hàng”. Trang thanh toán của khách hiển thị ghi chú đã được xử lý đúng, nhưng trang quản lý đơn hàng nội bộ lại in nguyên ghi chú vào HTML. Kẻ tấn công đặt một đơn với ghi chú chứa mã. Không ai trong số khách bị ảnh hưởng, nhưng khi nhân viên kho hoặc quản trị viên mở danh sách đơn, mã chạy bên trong phiên đăng nhập có quyền cao của họ.
Đây là mẫu rủi ro cần ưu tiên: dữ liệu do bên ngoài nhập (khách hàng, ứng viên, người gửi form liên hệ, ticket hỗ trợ, email được hiển thị trong hệ thống) được hiển thị ở giao diện nội bộ có quyền lớn. Kiểm thử thường chỉ tập trung vào trang công khai nên lỗi ở các màn hình nội bộ hay bị sót. Những màn hình hay gặp: CRM, helpdesk, hệ thống tuyển dụng, trang quản trị CMS, plugin của bên thứ ba.
Nếu XSS dẫn đến lộ họ tên, số điện thoại, địa chỉ của khách hàng, đó là sự cố dữ liệu cá nhân chứ không chỉ là lỗi giao diện. Khi đánh giá thiệt hại, hãy liệt kê chính xác trường dữ liệu nào hiển thị trên trang bị lỗi, và tham khảo nghĩa vụ chung tại bài bảo vệ dữ liệu cá nhân.
Phòng chống XSS bằng cách nào?
Nguyên tắc cốt lõi: coi mọi dữ liệu từ bên ngoài là không tin cậy và chuyển nó thành dạng an toàn tại thời điểm xuất ra trang. Theo tổng hợp về nhóm Injection trong OWASP Top 10:2025, các biện pháp chính gồm kiểm tra mọi đầu vào và mã hoá đầu ra theo ngữ cảnh (HTML, JavaScript, URL, SQL). Các lớp phòng thủ nên dùng cùng nhau:
Lớp 1: mã hoá đầu ra đúng ngữ cảnh
Cùng một chuỗi ký tự cần được mã hoá khác nhau tuỳ nó nằm ở đâu: nội dung HTML, giá trị thuộc tính, bên trong khối JavaScript, hay trong URL. Dùng sai ngữ cảnh là nguyên nhân hay gặp khiến lỗi vẫn còn dù đã “có lọc”. Cách làm thực tế là dùng cơ chế tự mã hoá của framework (mẫu giao diện của các framework web hiện đại thường mã hoá mặc định) và tránh các đường vòng như chèn HTML thô. Trong React, ví dụ, thuộc tính dangerouslySetInnerHTML là chỗ cần rà soát đầu tiên. Ở JavaScript thuần, ưu tiên gán vào textContent thay vì innerHTML.
Khi cần cho người dùng nhập HTML
Trình soạn thảo văn bản phong phú, bình luận có định dạng hay nội dung email hiển thị trong ứng dụng đều buộc phải cho phép một phần HTML. Lúc này mã hoá toàn bộ là không đủ. Hãy làm sạch (sanitize) bằng thư viện chuyên dụng theo danh sách cho phép: chỉ giữ các thẻ và thuộc tính đã khai báo. Đừng tự viết bộ lọc bằng biểu thức chính quy cho việc này.
Lớp 2: Content Security Policy (CSP)
CSP là tiêu đề HTTP cho trình duyệt biết nguồn script nào được phép chạy. Chính sách chặt, không cho script nhúng trực tiếp trên trang và chỉ cho script có nonce hoặc hash, giúp một lỗi mã hoá sót không dẫn ngay đến việc chạy mã. Nên triển khai ở chế độ báo cáo trước để xem chính sách có làm hỏng tính năng hợp lệ nào không, rồi mới chuyển sang chặn. Với mã JavaScript phía client có nhiều điểm đổ nguy hiểm, trình duyệt hiện đại còn hỗ trợ Trusted Types để buộc dữ liệu đi qua hàm làm sạch trước khi vào các điểm đổ đó.
Lớp 3: giảm thiệt hại khi lỗi xảy ra
Đặt cờ HttpOnly cho cookie phiên để mã chạy trên trang không đọc được cookie. Đặt SameSite để hạn chế việc cookie bị gửi kèm trong yêu cầu từ trang khác. Hạn chế này không ngăn mã trong trang gửi yêu cầu thay người dùng, nên với thao tác nhạy cảm (đổi mật khẩu, chuyển tiền, đổi email) hãy yêu cầu xác thực lại hoặc xác thực đa yếu tố ở thời điểm thực hiện, để một phiên bị chiếm không đủ để làm tổn hại tài khoản.
Lớp 4: WAF và giám sát
Tường lửa ứng dụng web có thể chặn nhiều mẫu yêu cầu đáng ngờ và là biện pháp tạm khi chưa kịp vá. Nó dựa trên nhận dạng mẫu nên có thể bị né bằng cách biến đổi dữ liệu, và không thấy được các lỗi DOM-based xảy ra hoàn toàn trên trình duyệt. Vì vậy hãy xem WAF là lớp bổ trợ, không thay cho việc sửa mã. Phần khác biệt với tường lửa mạng thông thường nằm ở chỗ WAF đọc được nội dung yêu cầu HTTP ở tầng ứng dụng.
Làm sao kiểm tra website có lỗi XSS?
Chỉ kiểm tra hệ thống do bạn sở hữu hoặc có văn bản uỷ quyền rõ ràng. Một quy trình hợp lý cho doanh nghiệp:
- Lập danh sách điểm nhập và điểm hiển thị: mọi form, tham số URL, API nhận chuỗi, file tải lên, và mọi màn hình hiển thị lại các dữ liệu đó, đặc biệt màn hình nội bộ.
- Rà mã nguồn: tìm các chỗ chèn HTML thô, các hàm đánh giá chuỗi thành mã, và các điểm đổ trong JavaScript phía client.
- Quét tự động: công cụ quét ứng dụng web động (DAST) và phân tích mã tĩnh (SAST) bắt được nhiều lỗi đơn giản. Kết quả quét thường có cả báo động giả lẫn bỏ sót, nên cần người xác nhận.
- Kiểm thử thâm nhập có phạm vi: yêu cầu đơn vị kiểm thử kiểm tra cả luồng có đăng nhập và các màn hình quản trị, không chỉ trang công khai.
- Kiểm tra tiêu đề bảo mật: xem CSP và cờ cookie có thực sự được máy chủ gửi ra hay chưa, kể cả sau lớp CDN hay proxy.
Dấu hiệu bị khai thác và cách xử lý sự cố
- Dấu hiệu: người dùng báo bị đăng xuất lạ hoặc thấy cửa sổ đăng nhập xuất hiện bất thường; tài khoản có thao tác họ không làm; trường nội dung trong CSDL chứa thẻ HTML hoặc đoạn script; log có tham số URL dài với nhiều ký tự mã hoá phần trăm; báo cáo vi phạm CSP tăng đột biến.
- Xử lý: sửa điểm đổ và mã hoá đúng ngữ cảnh; làm sạch dữ liệu bẩn đã lưu; thu hồi và đổi phiên đăng nhập, token, khoá API có thể đã lộ; yêu cầu đổi mật khẩu cho các tài khoản đã mở trang nhiễm, ưu tiên tài khoản quản trị; rà lại log để xác định khoảng thời gian và dữ liệu bị ảnh hưởng.
- Sau sự cố: thêm kiểm thử hồi quy cho đúng điểm đổ đó và bật CSP ở chế độ chặn.
Việc phân loại, ghi nhận và xử lý lỗ hổng thuộc quy trình chung của an toàn thông tin. XSS chỉ là một lỗi cụ thể trong đó.
XSS khác SQL injection, CSRF và phishing thế nào?
| Tiêu chí | XSS | SQL injection | CSRF | Phishing |
|---|---|---|---|---|
| Bản chất | Mã chạy trong trình duyệt trên trang tin cậy | Câu lệnh truy vấn bị thay đổi ở máy chủ | Lợi dụng cookie tự gửi kèm để giả yêu cầu | Lừa người dùng vào trang hoặc tệp giả |
| Bộ diễn giải bị lợi dụng | Trình duyệt | Cơ sở dữ liệu | Máy chủ tin yêu cầu hợp lệ về hình thức | Con người |
| Mục tiêu trực tiếp | Người dùng của ứng dụng | Dữ liệu trên máy chủ | Thao tác của người dùng đã đăng nhập | Thông tin đăng nhập, tiền |
| Chống chủ yếu bằng | Mã hoá đầu ra, CSP | Truy vấn tham số hoá | Token CSRF, SameSite | Đào tạo, MFA, lọc email |
Về nguyên lý, SQL injection cùng họ với XSS: dữ liệu bị diễn giải thành lệnh. Khác biệt là nơi chịu tác động. SQL injection nhắm vào cơ sở dữ liệu của bạn, còn XSS nhắm vào trình duyệt của người dùng. Hai lỗi có thể xuất hiện trên cùng một ô nhập liệu, nên sửa cả hai khi rà soát một điểm nhập.
Khi nào cần ưu tiên xử lý XSS?
- Ưu tiên cao: ứng dụng có đăng nhập, có nội dung do người dùng tạo, có trang quản trị xem dữ liệu bên ngoài, xử lý thanh toán hoặc dữ liệu cá nhân, hoặc dùng nhiều plugin và giao diện của bên thứ ba.
- Mức thấp hơn: trang giới thiệu tĩnh không có ô nhập, không có đăng nhập và không có tham số phản chiếu. Rủi ro vẫn còn nếu trang nhúng script bên thứ ba, vì khi script đó bị chèn mã thì hậu quả tương tự.
- Không nên tin: chỉ dựa vào bộ lọc từ khoá, hoặc nghĩ rằng “đã dùng framework nên an toàn”. Framework mã hoá mặc định nhưng không bảo vệ được khi nhà phát triển cố ý tắt cơ chế đó.
Câu hỏi thường gặp
XSS có phải là hack máy chủ không?
Không hẳn. Lỗ hổng nằm ở ứng dụng web của bạn, nhưng mã độc chạy trong trình duyệt của người dùng chứ không chạy trên máy chủ. Tuy nhiên nếu nạn nhân là quản trị viên, kẻ tấn công có thể mượn quyền của họ để tác động đến hệ thống.
HTTPS có ngăn được XSS không?
Không. HTTPS mã hoá đường truyền giữa trình duyệt và máy chủ, nhưng không kiểm soát nội dung trang. Một trang HTTPS vẫn có thể chứa lỗi XSS nếu ứng dụng đưa dữ liệu chưa mã hoá ra HTML.
XSS có còn nằm trong OWASP Top 10 không?
Có, nhưng không còn là mục riêng. Từ bản 2021 XSS thuộc nhóm Injection. Theo bản OWASP Top 10:2025, nhóm này đứng hạng 5 trong danh sách và vẫn bao gồm XSS cùng SQL injection.
Bật WAF là đủ để chống XSS?
Chưa đủ. WAF giúp chặn các mẫu tấn công phổ biến và có ích khi cần che tạm một lỗi đang chờ vá. Nó không thay thế việc mã hoá đầu ra trong mã nguồn và khó thấy được XSS loại DOM-based.
Cookie HttpOnly có giúp gì?
Có, nó ngăn mã chạy trên trang đọc trực tiếp cookie phiên. Nhưng mã đó vẫn có thể gửi yêu cầu thay người dùng trong phiên đang mở, nên cần kết hợp mã hoá đầu ra, CSP và xác thực lại cho thao tác nhạy cảm.
Người dùng cuối có thể tự bảo vệ trước XSS không?
Phần lớn trách nhiệm thuộc về đơn vị vận hành website. Người dùng có thể giảm rủi ro bằng cách không bấm liên kết lạ, giữ trình duyệt cập nhật, đăng xuất khi không dùng và bật xác thực đa yếu tố cho các tài khoản quan trọng.
Đọc thêm tin tức, phân tích về AI, blockchain và chuyển đổi số trên blog công nghệ VBPO, hoặc các bài khác trong chuyên mục An toàn thông tin.