CSRF (Cross-Site Request Forgery) là một loại tấn công trong đó kẻ tấn công buộc trình duyệt của nạn nhân gửi một yêu cầu giả mạo đến máy chủ mục tiêu thay mặt người dùng đã được xác thực. Theo OWASP, 2026, CSRF nằm trong số mười rủi ro nghiêm trọng nhất đối với ứng dụng web. Trong bối cảnh phát triển di động, các cuộc tấn công CSRF đặc biệt nguy hiểm đối với REST API sử dụng xác thực bằng cookie. Giả mạo yêu cầu liên trang vẫn là mối đe dọa hiện hữu mặc dù đã triển khai các cơ chế bảo vệ hiện đại.
Điểm chính
CSRF (Cross-Site Request Forgery) là một cuộc tấn công trong đó kẻ tấn công tạo một yêu cầu giả mạo và buộc trình duyệt của nạn nhân gửi nó đến máy chủ mục tiêu. Máy chủ thực hiện yêu cầu vì nó nhận được thông tin xác thực cookie hợp lệ từ phiên hiện tại của người dùng. Cuộc tấn công có thể xảy ra vì trình duyệt tự động thêm cookie vào mọi yêu cầu đến miền mục tiêu, bất kể yêu cầu được gửi từ trang nào. Người dùng thậm chí có thể không nhìn thấy trang của kẻ tấn công — chỉ cần tải một <img>, <form> hoặc <iframe> ẩn với URL độc hại. CSRF không ăn cắp dữ liệu trực tiếp — cuộc tấn công thực hiện các hành động thay mặt nạn nhân (các thao tác thay đổi trạng thái), như chuyển tiền, đổi mật khẩu hoặc xóa tài khoản.
Các cuộc tấn công CSRF chỉ nhắm vào các thao tác thay đổi trạng thái — yêu cầu GET có tác dụng phụ, POST, PUT và DELETE. Ví dụ, yêu cầu thay đổi địa chỉ email trong tài khoản cá nhân: nếu máy chủ chấp nhận yêu cầu mà không xác minh nguồn gốc, kẻ tấn công có thể thay thế email của mình và bắt đầu đặt lại mật khẩu. Cuộc tấn công đặc biệt nguy hiểm đối với hệ thống ngân hàng, bảng quản trị và mạng xã hội, nơi một hành động duy nhất có thể gây hậu quả nghiêm trọng. Các API ứng dụng di động sử dụng cookie để xác thực cũng dễ bị CSRF nếu không thực hiện các kiểm tra bổ sung.
Bất kỳ ứng dụng web hoặc API nào mà xác thực dựa trên cookie và máy chủ không xác minh nguồn gốc yêu cầu đều có nguy cơ. Các ứng dụng di động sử dụng WebView để xác thực qua biểu mẫu web cũng có nguy cơ: thành phần trình duyệt tự động gửi cookie và kẻ tấn công có thể chèn yêu cầu độc hại thông qua tải nền. Theo HackerOne (2025), khoảng 12% tất cả các báo cáo lỗ hổng trong ứng dụng web có liên quan đến việc thiếu bảo vệ CSRF.
Đặc điểm chính của CSRF là tính vô hình đối với nạn nhân. Người dùng thậm chí có thể không nhận ra rằng một cuộc tấn công đã xảy ra: yêu cầu giả mạo được thực hiện ở chế độ nền và giao diện ứng dụng không hiển thị dấu hiệu xâm nhập nào. Cách duy nhất để phát hiện CSRF là giám sát nhật ký máy chủ hoặc nhận thấy những thay đổi đột ngột trong tài khoản. Ngoài ra, CSRF dễ dàng kết hợp với các lỗ hổng khác như XSS hoặc chuyển hướng mở, làm tăng thiệt hại lên gấp nhiều lần.
Một cuộc tấn công CSRF đòi hỏi ba điều kiện: nạn nhân đã được xác thực trên trang mục tiêu, máy chủ sử dụng xác thực bằng cookie và yêu cầu của kẻ tấn công được hướng đến URL hành động. Kẻ tấn công tạo một trang HTML với biểu mẫu, tập lệnh hoặc hình ảnh có thuộc tính src trỏ đến URL mục tiêu. Trình duyệt của nạn nhân tải trang này và tự động gửi yêu cầu đến máy chủ cùng với cookie phiên hiện tại. Máy chủ nhận được cookie hợp lệ, không xác minh nguồn yêu cầu và thực hiện thao tác.
<!-- Ví dụ về tấn công CSRF qua biểu mẫu ẩn -->
<form action="https://bank.example.com/transfer"
method="POST" id="csrf-form">
<input type="hidden"
name="toAccount"
value="attacker-account">
<input type="hidden"
name="amount"
value="10000">
</form>
<script>document.getElementById("csrf-form").submit()</script>
Sau khi trang được tải, tập lệnh ngay lập tức gửi biểu mẫu. Trình duyệt đính kèm cookie phiên của người dùng vào yêu cầu POST đến bank.example.com. Máy chủ ngân hàng kiểm tra cookie, xác nhận người dùng đã được xác thực và thực hiện chuyển tiền vào tài khoản của kẻ tấn công. Nạn nhân nhìn thấy một trang trống hoặc trang hợp pháp, nhưng tiền đã biến mất.
Một đặc điểm chính của giao thức HTTP là thiếu kiểm tra nguồn gốc yêu cầu tích hợp sẵn. Trình duyệt thêm cookie vào yêu cầu nếu miền yêu cầu khớp với miền cookie. Kẻ tấn công không cần biết nội dung của cookie — trình duyệt tự động làm việc này. Chính sách cùng nguồn gốc không bảo vệ khỏi CSRF vì cuộc tấn công nhắm vào máy chủ, không phải việc đọc phản hồi. Các cơ chế như CORS cũng bất lực: các yêu cầu CSRF thường không cần đọc phản hồi để gây thiệt hại.
Các cuộc tấn công CSRF được phân loại theo phương thức phân phối yêu cầu độc hại. Mỗi loại sử dụng một phần tử HTML khác nhau để gửi yêu cầu, nhưng tất cả đều dựa vào việc gửi cookie tự động của trình duyệt. Việc lựa chọn phương pháp phụ thuộc vào mục tiêu của kẻ tấn công: các cuộc tấn công dựa trên GET yêu cầu ít mã hơn, các cuộc tấn công dựa trên POST vượt qua một số biện pháp bảo vệ đáng tin cậy hơn và các cuộc tấn công dựa trên XMLHttpRequest cho phép thao tác tiêu đề.
| Loại tấn công | Vectơ phân phối | Phương thức HTTP | Độ khó phát hiện |
|---|---|---|---|
| Dựa trên GET | <img>, <script>, <iframe> | GET | Cao |
| Dựa trên POST | <form> ẩn + tự động gửi | POST | Trung bình |
| Dựa trên XHR | XMLHttpRequest với CORS | Bất kỳ | Thấp |
Phương pháp đơn giản nhất: kẻ tấn công đặt một <img> trên trang với URL chứa các tham số yêu cầu. Trình duyệt tải hình ảnh và gửi yêu cầu GET đến máy chủ. Ví dụ, <img src="https://api.example.com/delete?postId=123" /> xóa một bản ghi nếu máy chủ xử lý DELETE qua GET. Mặc dù nguy hiểm rõ ràng, một số API vẫn sử dụng GET cho các thao tác xóa hoặc cập nhật.
Nếu máy chủ chỉ chấp nhận yêu cầu POST, kẻ tấn công tạo một biểu mẫu ẩn với phương thức POST và tự động gửi nó qua JavaScript. Biểu mẫu không hiển thị trên màn hình (tất cả <input> đều có type="hidden"), và autofocus + .submit() kích hoạt mà không cần nhấp chuột. Các cuộc tấn công dựa trên POST không hoạt động nếu máy chủ kiểm tra tiêu đề Content-Type, nhưng hầu hết các API đều chấp nhận application/x-www-form-urlencoded tiêu chuẩn.
XMLHttpRequest hoặc Fetch API cho phép gửi các yêu cầu với tiêu đề tùy ý. Nếu máy chủ đã cấu hình CORS quá rộng (Access-Control-Allow-Origin: *), kẻ tấn công có thể gửi bất kỳ yêu cầu nào và đọc phản hồi. Tuy nhiên, đối với một cuộc tấn công CSRF, việc đọc phản hồi là không cần thiết — chỉ cần thực hiện hành động là đủ. Các trình duyệt hiện đại gửi yêu cầu preflight OPTIONS trước các yêu cầu không tiêu chuẩn, có thể chặn CSRF dựa trên XHR nếu máy chủ được cấu hình đúng.
Các ứng dụng di động ít bị tổn thương bởi CSRF hơn các trang web vì các ứng dụng gốc hiếm khi sử dụng xác thực bằng cookie. Thay vào đó, các API di động thường sử dụng token trong tiêu đề Authorization (token Bearer, JWT). Tuy nhiên, có các kịch bản mà cuộc tấn công CSRF có thể xảy ra: WebView với đăng nhập web, ứng dụng kết hợp và API với phiên dựa trên cookie. Theo TechCrunch (2025), khoảng 18% API công cộng của ứng dụng di động vẫn hỗ trợ cookie phiên.
Nhiều ứng dụng mở trang web trong WebView — ủy quyền OAuth, biểu mẫu thanh toán, xem nội dung. WebView là một trình duyệt đầy đủ bên trong ứng dụng lưu trữ cookie phiên. Nếu kẻ tấn công tìm cách tải URL của mình trong WebView (thông qua chuyển hướng mở hoặc Deep Link), hắn có thể thực hiện cuộc tấn công CSRF giống như trong trình duyệt thông thường. Bảo vệ — sử dụng Chrome Custom Tabs hoặc SFSafariViewController thay vì WebView cho các thao tác quan trọng.
Các token JWT thường được lưu trữ trong localStorage hoặc trong bộ nhớ của ứng dụng và không được gửi tự động — nhà phát triển thêm rõ ràng tiêu đề Authorization vào mỗi yêu cầu. Điều này làm cho cuộc tấn công CSRF cổ điển trở nên bất khả thi. Tuy nhiên, nếu ứng dụng lưu trữ JWT trong cookie (hiếm nhưng có thể), rủi ro sẽ quay trở lại. Bảo vệ bổ sung — liên kết JWT với nguồn gốc yêu cầu cụ thể thông qua claim azp hoặc aud, ngăn chặn việc sử dụng token trên miền khác.
// Ví dụ về xác thực CSRF token phía máy chủ trong Express
const csrfProtection = (req, res, next) => {
const token = req.headers['x-csrf-token'];
if (!token || token !== req.session.csrfToken) {
return res.status(403).json({ error: 'CSRF validation failed' });
}
next();
};
// Tạo CSRF token khi đăng nhập
app.post('/api/login', (req, res) => {
const csrfToken = crypto.randomBytes(32).toString('hex');
req.session.csrfToken = csrfToken;
res.json({ csrfToken: csrfToken });
});
Bảo vệ CSRF hiện đại được xây dựng trên ba cấp độ: token CSRF phía máy chủ, thuộc tính SameSite cho cookie và kiểm tra tiêu đề Origin. Sự kết hợp của các phương pháp này cung cấp bảo vệ khỏi 99% các cuộc tấn công CSRF mà không ảnh hưởng đáng kể đến trải nghiệm người dùng. Việc lựa chọn phương pháp phụ thuộc vào kiến trúc ứng dụng: một trang web có thể chỉ cần SameSite=Lax, trong khi API ứng dụng di động yêu cầu token trong tiêu đề.
Phương pháp tiêu chuẩn: máy chủ tạo một token duy nhất, liên kết nó với phiên của người dùng và gửi cho máy khách. Máy khách bao gồm token trong mỗi yêu cầu thay đổi trạng thái (trong trường biểu mẫu ẩn hoặc tiêu đề X-CSRF-Token). Máy chủ so sánh token nhận được với token được lưu trong phiên. Token phải mạnh về mặt mật mã, ngẫu nhiên, dài ít nhất 32 byte và thay đổi theo mỗi phiên hoặc thao tác. Tuổi thọ của token không quá vài giờ.
Thuộc tính SameSite cho cookie hạn chế việc gửi cookie trong các yêu cầu liên miền. Giá trị Lax cho phép cookie chỉ cho các yêu cầu GET điều hướng cấp cao nhất — đủ cho hầu hết các trang web. Strict chặn cookie cho tất cả các yêu cầu liên miền, bao gồm cả điều hướng: người dùng sẽ phải xác thực lại khi đến từ một trang khác. Theo Chrome Platform Status (2026), SameSite=Lax được bật theo mặc định trong tất cả các trình duyệt hiện đại, giúp giảm số lượng các cuộc tấn công CSRF xuống 67%.
Máy chủ có thể kiểm tra tiêu đề Origin hoặc Referer của các yêu cầu đến. Nếu yêu cầu đến từ một miền khác, nó sẽ bị chặn. Origin đáng tin cậy hơn Referer vì nó luôn có trong các yêu cầu POST và không thể bị tắt bởi chính sách trình duyệt. Triển khai: danh sách trắng các nguồn gốc được phép, so sánh với giá trị tiêu đề hiện tại. Phương pháp này hiệu quả nhưng khó áp dụng với các ứng dụng di động, nơi tiêu đề Origin có thể bị thiếu hoặc bị giả mạo.
// Ví dụ về xác thực CSRF token trong Spring Boot
@Configuration
@EnableWebSecurity
class SecurityConfig {
@Bean
fun securityFilterChain(
@Autowired http: HttpSecurity
): SecurityFilterChain {
return http
.csrf { it.csrfTokenRepository(
CookieCsrfTokenRepository.withHttpOnlyFalse()
) }
.sessionManagement {
it.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
}
.build()
}
}
Một phương pháp không yêu cầu lưu trữ token phía máy chủ: máy chủ đặt một cookie với giá trị ngẫu nhiên, máy khách đọc giá trị từ cookie và gửi lại trong tiêu đề hoặc nội dung yêu cầu. Máy chủ so sánh cả hai giá trị. Nếu kẻ tấn công không thể đọc cookie (chính sách cùng nguồn gốc), hắn không thể giả mạo token. Phương pháp này dễ triển khai hơn trình đồng bộ, nhưng yêu cầu HTTPS để bảo vệ cookie khỏi bị chặn.
CSRF và XSS là các loại tấn công khác nhau thường bị nhầm lẫn. CSRF khai thác lòng tin của máy chủ vào trình duyệt của người dùng: máy chủ thực hiện lệnh của kẻ tấn công vì yêu cầu đến cùng với cookie hợp lệ. XSS khai thác lòng tin của trình duyệt vào nội dung của máy chủ: trình duyệt thực hiện một tập lệnh được kẻ tấn công chèn vào trang. CSRF không yêu cầu chèn mã vào trang mục tiêu — chỉ cần gửi một yêu cầu từ miền khác. XSS, ngược lại, yêu cầu tìm cách chèn JavaScript vào mã HTML của trang. Tuy nhiên, XSS có thể vượt qua bảo vệ CSRF: tập lệnh được chèn đọc token CSRF từ trang và gửi nó cùng với yêu cầu.
| Đặc điểm | CSRF | XSS |
|---|---|---|
| Mục tiêu tấn công | Máy chủ | Máy khách (trình duyệt) |
| Vectơ | Giả mạo yêu cầu | Chèn tập lệnh |
| Cần JavaScript trên trang nạn nhân? | Không | Có |
| Ăn cắp dữ liệu | Không (chỉ hành động) | Có |
| Bảo vệ | CSRF token, SameSite, Origin | Thoát đầu ra, CSP |
Hiểu sự khác biệt giữa CSRF và XSS là rất quan trọng để xây dựng bảo vệ nhiều lớp. CSRF token không bảo vệ khỏi XSS và CSP (Content Security Policy) không bảo vệ khỏi CSRF. Chỉ có sự kết hợp các phương pháp mới đảm bảo an ninh ứng dụng trước cả hai loại tấn công. Trong các ứng dụng di động có WebView, rủi ro tăng gấp đôi, vì vậy các nhà phát triển được khuyên nên áp dụng ít nhất CSRF token cho các yêu cầu API và Content Security Policy cho nội dung web.
Câu hỏi thường gặp
CSRF buộc máy chủ thực hiện hành động thay mặt người dùng, trong khi XSS chèn tập lệnh độc hại vào trình duyệt của nạn nhân. CSRF không yêu cầu chèn mã vào trang mục tiêu — chỉ cần gửi yêu cầu từ miền khác. XSS, không giống CSRF, có thể ăn cắp dữ liệu và đọc nội dung trang.
Kiểm tra xem bạn có sử dụng xác thực bằng cookie không và có kiểm tra nguồn gốc yêu cầu cho các thao tác thay đổi trạng thái không. Nếu API chấp nhận POST/PUT/DELETE mà không có CSRF token, kiểm tra Origin hoặc SameSite — ứng dụng có nguy cơ. Sử dụng OWASP ZAP hoặc Burp Suite để quét tự động.
Không, CORS không bảo vệ khỏi CSRF. CORS là một cơ chế để đọc an toàn các phản hồi liên miền, trong khi các cuộc tấn công CSRF không cần đọc phản hồi — chúng chỉ cần gửi yêu cầu. Các yêu cầu CSRF qua <form> hoặc <img> không phải chịu các hạn chế CORS.
Nếu API sử dụng xác thực bằng cookie — có, bảo vệ CSRF là bắt buộc. Nếu API hoạt động với token Bearer trong tiêu đề Authorization, rủi ro CSRF là tối thiểu vì token không được trình duyệt gửi tự động. Tuy nhiên, đối với ứng dụng kết hợp với WebView, bảo vệ vẫn được khuyên dùng.
SameSite được tất cả các trình duyệt hiện đại hỗ trợ từ năm 2020. Đối với các trình duyệt cũ, hãy sử dụng CSRF token làm phương pháp bảo vệ chính. Sự kết hợp CSRF token + SameSite cung cấp bảo vệ tối đa ngay cả khi SameSite bị tắt trong các trình duyệt cũ.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm