Table of Contents
CSRF (Cross-Site Request Forgery) là gì?
CSRF (Cross-Site Request Forgery) là một lỗ hổng bảo mật web mà trong đó một kẻ tấn công lừa người dùng đã xác thực để thực hiện các hành động mà họ không hề mong muốn trên một trang web mà người dùng đã đăng nhập. CSRF có thể dẫn đến việc thay đổi thông tin, chuyển tiền, hoặc các hành động nguy hiểm khác mà người dùng không hề nhận ra.
Cách CSRF hoạt động:
- Người dùng đăng nhập: Người dùng đăng nhập vào một trang web (Website A) và duy trì phiên đăng nhập với cookie phiên.
- Truy cập trang không đáng tin cậy: Người dùng vô tình truy cập vào một trang web độc hại (Website B) hoặc nhận được một email với liên kết độc hại.
- Thực hiện yêu cầu: Website B chứa mã lệnh thực hiện một yêu cầu đến Website A bằng cách sử dụng cookie phiên của người dùng đã xác thực, mà người dùng không hề nhận ra.
- Kết quả: Yêu cầu được chấp nhận bởi Website A vì nó tin rằng yêu cầu đến từ người dùng hợp lệ.
Ví dụ về tấn công CSRF:
Giả sử chúng ta có một trang web ngân hàng trực tuyến (Website A) với một chức năng chuyển tiền. Người dùng có thể chuyển tiền bằng cách gửi một yêu cầu POST tới URL https://bank.com/transfer với các tham số như sau:
POST /transfer Host: bank.com Content-Type: application/x-www-form-urlencoded Cookie: session=abc123 amount=1000&to_account=123456789
Người dùng đăng nhập vào Website A: Người dùng Alice đăng nhập vào tài khoản ngân hàng trực tuyến của mình trên Website A và hệ thống lưu lại phiên đăng nhập của cô ấy dưới dạng cookie.
Truy cập trang web độc hại (Website B): Alice sau đó vô tình truy cập vào một trang web độc hại (Website B) được kiểm soát bởi kẻ tấn công. Website B chứa mã HTML hoặc JavaScript như sau:
<!DOCTYPE html> <html> <body> <h1>Check out this cool site!</h1> <img src="https://bank.com/transfer?amount=1000&to_account=987654321" style="display:none;" /> </body> </html>
Hoặc một form ẩn được tự động gửi:
<!DOCTYPE html> <html> <body onload="document.forms[0].submit()"> <form action="https://bank.com/transfer" method="POST"> <input type="hidden" name="amount" value="1000"> <input type="hidden" name="to_account" value="987654321"> </form> </body> </html>
Yêu cầu chuyển tiền được gửi: Khi Alice truy cập vào Website B, trình duyệt của cô ấy sẽ tự động gửi yêu cầu chuyển tiền đến Website A mà cô ấy không hề hay biết. Vì Alice đã đăng nhập vào Website A và cookie phiên của cô ấy vẫn còn hiệu lực, yêu cầu này sẽ được xử lý như một yêu cầu hợp lệ.
Tiền bị chuyển: Website A nhận được yêu cầu chuyển tiền và vì yêu cầu đó chứa cookie phiên hợp lệ của Alice, tiền sẽ được chuyển từ tài khoản của Alice sang tài khoản của kẻ tấn công.
Các phương pháp phòng chống CSRF:
CSRF Token:
Mỗi yêu cầu không phải GET nên kèm theo một token CSRF duy nhất, được sinh ra ngẫu nhiên và được gán vào form hoặc header của yêu cầu. Khi server nhận yêu cầu, nó sẽ kiểm tra token này. Nếu token hợp lệ, yêu cầu sẽ được xử lý.
Kiểm tra Referrer Header:
Kiểm tra giá trị của header Referrer để đảm bảo yêu cầu đến từ cùng một miền. Tuy nhiên, phương pháp này không hoàn toàn đáng tin cậy vì Referrer Header có thể bị thiếu hoặc bị thay đổi.
SameSite Cookie Attribute:
Thiết lập thuộc tính SameSite cho cookie để ngăn chặn việc gửi cookie trong các yêu cầu cross-site. Các giá trị SameSite có thể là Strict, Lax, hoặc None.
Sử dụng phương thức HTTP hợp lý:
Hạn chế sử dụng các phương thức GET cho các hành động có tác động thay đổi dữ liệu. Sử dụng POST, PUT, DELETE, v.v. cho các yêu cầu thay đổi dữ liệu.
Yêu cầu xác thực lại cho các hành động quan trọng:
Đối với các hành động nhạy cảm, yêu cầu người dùng nhập lại mật khẩu hoặc xác thực lại thông qua một bước bảo mật khác.
CORS (Cross-Origin Resource Sharing):
Thiết lập chính sách CORS để chỉ cho phép các miền đáng tin cậy thực hiện yêu cầu đến server của bạn.
Phòng chống CSRF trong Laravel:
Laravel sử dụng CSRF token để bảo vệ các ứng dụng web khỏi các tấn công CSRF. Mặc định, các route trong Laravel được bảo vệ bởi CSRF middleware, ngoại trừ các route sử dụng phương thức GET, HEAD, OPTIONS.
Thêm CSRF Token vào Form: Khi bạn tạo một form trong Laravel, hãy đảm bảo rằng bạn thêm CSRF token vào form. Bạn có thể làm điều này bằng cách sử dụng blade directive @csrf:
<form method="POST" action="/transfer"> @csrf <input type="text" name="amount"> <input type="text" name="to_account"> <button type="submit">Transfer</button> </form>
Blade directive @csrf sẽ tự động tạo một hidden input với token CSRF:
<input type="hidden" name="_token" value="CSRF_TOKEN_HERE">
Sử dụng trong AJAX:
Khi gửi yêu cầu AJAX, cần thêm CSRF token vào header của yêu cầu. Bạn có thể lấy token từ meta tag trong trang HTML và thêm vào tất cả các yêu cầu AJAX. Laravel mặc định tạo một meta tag chứa token CSRF:
<meta name="csrf-token" content="{{ csrf_token() }}">
Có thể sử dụng JavaScript để lấy giá trị của token này và thêm vào header của yêu cầu AJAX. Dưới đây là một ví dụ với jQuery:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });
Sau đó, bạn có thể thực hiện các yêu cầu AJAX như bình thường:
$.post('/transfer', { amount: 1000, to_account: '123456789' }, function(data) { console.log(data); });
Cấu hình CSRF Middleware:
Laravel cung cấp một middleware mặc định cho việc xử lý CSRF token. Middleware này nằm trong file VerifyCsrfToken.php:
- App\Http\Middleware\VerifyCsrfToken.php
namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { // Các route hoặc URI bạn muốn bỏ qua kiểm tra CSRF protected $except = [ // ]; }
Nếu bạn muốn bỏ qua kiểm tra CSRF cho một số route hoặc URI cụ thể, bạn có thể thêm chúng vào mảng $except.
Sử dụng thuộc tính SameSite cho Cookie:
Để tăng cường bảo mật, bạn có thể thiết lập thuộc tính SameSite cho cookie session của Laravel. Bạn có thể làm điều này trong file config/session.php:
- config/session.php
'same_site' => 'lax', // hoặc 'strict', 'none'
Bằng cách này, cookie sẽ không được gửi trong các yêu cầu cross-site trừ khi chúng đến từ một navigation từ link trên cùng hoặc submit form (với giá trị lax).
Kiểm tra và rà soát lỗi CSRF (Cross-Site Request Forgery)
Kiểm tra và rà soát lỗi CSRF (Cross-Site Request Forgery) là một bước quan trọng để đảm bảo rằng ứng dụng web của bạn được bảo vệ khỏi các tấn công CSRF. Dưới đây là các cách kiểm tra và rà soát lỗi CSRF:
Kiểm tra bằng cách sử dụng công cụ tự động:
OWASP ZAP:
OWASP ZAP (Zed Attack Proxy) là một công cụ mã nguồn mở được sử dụng rộng rãi để kiểm tra bảo mật web. Nó có thể phát hiện các lỗ hổng bảo mật, bao gồm cả CSRF.
Burp Suite:
Burp Suite là một công cụ bảo mật web phổ biến khác có thể giúp bạn kiểm tra và phát hiện các lỗ hổng CSRF.
Kiểm tra thủ công:
Kiểm tra CSRF Token:
Xác minh sự hiện diện của CSRF Token:
- Đảm bảo rằng mọi form trên trang web của bạn bao gồm một CSRF token.
- Kiểm tra rằng CSRF token được kiểm tra trên server khi xử lý các yêu cầu POST.
Kiểm tra tính ngẫu nhiên của CSRF Token:
- Đảm bảo rằng CSRF token là duy nhất cho mỗi phiên người dùng.
- Token không nên có mẫu dễ đoán hoặc có thể tái sử dụng.
Kiểm tra SameSite Cookie Attribute:
Xác minh cấu hình SameSite: Kiểm tra rằng thuộc tính SameSite cho cookie session được thiết lập hợp lý (ví dụ: 'Lax', 'Strict').
Sử dụng các bộ kiểm thử bảo mật (Security Testing Frameworks):
PHPUnit:
Viết các bài kiểm thử đơn vị (Unit Test) để kiểm tra CSRF: Sử dụng PHPUnit để viết các bài kiểm thử nhằm đảm bảo rằng mọi yêu cầu POST, PUT, DELETE đều phải có CSRF token hợp lệ.
public function testCsrfProtection() { $response = $this->post('/transfer', [ 'amount' => 1000, 'to_account' => '123456789' ]); $response->assertStatus(419); // 419 status code indicates CSRF token mismatch }
Laravel Dusk:
Viết các bài kiểm thử giao diện người dùng (UI Test) để kiểm tra CSRF: Sử dụng Laravel Dusk để tự động hóa kiểm tra giao diện người dùng và đảm bảo rằng mọi form bao gồm CSRF token và yêu cầu bị từ chối nếu không có token hợp lệ.
public function testCsrfProtection() { $this->browse(function (Browser $browser) { $browser->visit('/transfer') ->type('amount', '1000') ->type('to_account', '123456789') ->press('Transfer') ->assertSee('CSRF token mismatch'); }); }
Thực hiện kiểm tra bảo mật định kỳ:
Đánh giá bảo mật định kỳ:
- Thực hiện các kiểm tra bảo mật định kỳ (quarterly hoặc annually) để đảm bảo rằng không có lỗ hổng bảo mật mới xuất hiện.
- Cập nhật các công cụ kiểm tra bảo mật và theo dõi các cập nhật bảo mật mới nhất từ cộng đồng bảo mật.