Skip to content

CSRF Protection (Bảo vệ CSRF)

Giới thiệu (Introduction)

Cross-site request forgeries (CSRF) là loại tấn công ác ý trong đó các lệnh trái phép được thực hiện dưới danh nghĩa user đã xác thực. Laravel giúp dễ dàng bảo vệ ứng dụng khỏi tấn công cross-site request forgery.

Giải thích lỗ hổng (Explanation of the Vulnerability)

Giả sử ứng dụng có route /user/email chấp nhận POST request để thay đổi email. Không có CSRF protection, website ác ý có thể tạo HTML form trỏ đến route này và tự động submit:

html
<form action="https://your-application.com/user/email" method="POST">
    <input type="email" value="malicious@example.com">
</form>

<script>
    document.forms[0].submit();
</script>

Nếu website ác ý tự động submit form khi trang tải, kẻ tấn công chỉ cần lừa user truy cập trang đó là email sẽ bị thay đổi.

Để ngăn chặn, chúng ta cần kiểm tra mọi POST, PUT, PATCH, hoặc DELETE request với giá trị session bí mật mà ứng dụng ác ý không thể truy cập.

Ngăn chặn CSRF Requests (Preventing CSRF Requests)

Middleware Illuminate\Foundation\Http\Middleware\PreventRequestForgery — được bao gồm trong nhóm middleware web mặc định — bảo vệ ứng dụng bằng hai lớp (two-layer approach):

  1. Kiểm tra header Sec-Fetch-Site: Browsers hiện đại tự động đặt header này trên mọi request, cho biết request đến từ same-origin, same-site hay cross-site. Nếu same-origin → cho phép ngay, không cần xác minh token.

  2. Fallback CSRF token validation: Nếu kiểm tra origin không pass (browser cũ hoặc kết nối không an toàn) → middleware dùng CSRF token truyền thống.

Laravel tự động tạo CSRF "token" cho mỗi user session. Token này xác minh rằng user đã xác thực thực sự đang gửi requests.

CSRF token hiện tại có thể truy cập qua session hoặc helper csrf_token:

php
use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $token = $request->session()->token();

    $token = csrf_token();

    // ...
});

Khi định nghĩa form HTML với POST, PUT, PATCH, hoặc DELETE, bạn phải bao gồm field ẩn CSRF _token. Dùng directive @csrf của Blade:

html
<form method="POST" action="/profile">
    @csrf

    <!-- Tương đương với... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

CSRF Tokens và SPAs

Nếu xây dựng SPA sử dụng Laravel làm API backend, xem tài liệu Laravel Sanctum về xác thực API và bảo vệ CSRF.

Origin Verification (Xác minh nguồn gốc)

Middleware kiểm tra header Sec-Fetch-Site trước. Nếu muốn chỉ dùng origin verification và tắt CSRF token fallback:

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(originOnly: true);
})

Khi dùng chế độ origin-only, requests thất bại sẽ nhận response 403 thay vì 419 của CSRF token mismatch.

LƯU Ý

Header Sec-Fetch-Site chỉ được gửi qua kết nối HTTPS. Nếu ứng dụng không dùng HTTPS, origin verification không khả dụng và middleware sẽ fallback về CSRF token.

Cho phép requests từ subdomains (ví dụ dashboard.example.com chấp nhận từ example.com):

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(allowSameSite: true);
})

Loại trừ URIs khỏi CSRF Protection

Đôi khi cần loại trừ một số URIs (ví dụ webhook Stripe):

php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->preventRequestForgery(except: [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ]);
})

GỢI Ý

CSRF middleware tự động bị tắt cho tất cả routes khi chạy tests.

X-CSRF-TOKEN

Ngoài kiểm tra CSRF token như POST parameter, middleware PreventRequestForgery còn kiểm tra header X-CSRF-TOKEN. Bạn có thể lưu token trong HTML meta tag:

html
<meta name="csrf-token" content="{{ csrf_token() }}">

Sau đó cấu hình thư viện JavaScript (như jQuery) tự động gửi token:

javascript
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

X-XSRF-TOKEN

Laravel lưu CSRF token trong cookie mã hóa XSRF-TOKEN kèm theo mỗi response. Bạn có thể dùng giá trị cookie để đặt header X-XSRF-TOKEN.

Cookie này chủ yếu là tiện lợi cho developer vì một số frameworks JavaScript (Angular, Axios) tự động đặt giá trị này vào header X-XSRF-TOKEN cho same-origin requests.

GỢI Ý

Mặc định, file resources/js/bootstrap.js bao gồm thư viện Axios HTTP sẽ tự động gửi header X-XSRF-TOKEN.