CSRF và CSRF Protection trong Laravel

Tổng quan về CSRF

CSRF là gì?

CSRF (Cross Site Request Forgery) là kỹ thuật tấn công bằng cách sử dụng quyền chứng thực của người dùng đối với một website. Kỹ thuật này tấn công vào người dùng, dựa vào đó hacker có thể thực thi những thao tác phải yêu cầu sự chứng thực. Hiểu một cách nôm na, đây là kỹ thuật tấn công dựa vào mượn quyền trái phép. CSRF còn được gọi là “session riding”, “XSRF”.

CSRF là một cuộc tấn công lừa các nạn nhân vào một trình yêu cầu độc hại. Hacker sử dụng phương pháp CSRF để lừa trình duyệt của người dùng gửi đi các câu lệnh HTTP đến các ứng dụng web. Trong trường hợp phiên làm việc của người dùng chưa hết hiệu lực thì các câu lệnh trên sẽ dc thực hiện trên danh nghĩa của nạn nhân. Đối với hầu hết các trang web, yêu cầu trình duyệt sẽ tự động bao gồm bất kỳ thông tin đăng nhập nào được liên kết với trang web, chẳng hạn như cookie phiên giao dịch của người dùng, địa chỉ IP, chứng chỉ tên miền Windows, v.v. Do đó, nếu người dùng hiện đang được xác thực vào trang web, trang web sẽ không có cách nào để phân biệt giữa yêu cầu giả mạo được gửi bởi nạn nhân và yêu cầu hợp pháp được gửi bởi nạn nhân. CSRF tấn công các chức năng nhằm mục tiêu tạo ra sự thay đổi trạng thái trên máy chủ, chẳng hạn như thay đổi địa chỉ email hoặc mật khẩu của nạn nhân. 

Đôi khi có thể lưu trữ các cuộc tấn công CSRF vào các trang web dễ bị tổn thương. Những lỗ hổng này được gọi là “các lỗi lưu trữ CSRF”. Gỉa sử hệ thống của bạn có url sau: youwebsite.com/post/{id}/delete. Như vậy nếu có một người nào biết được URL này thì họ có thể lợi dụng quyền của người dùng để xóa post với id tương ứng. Hacker có thể che giấu khéo léo các đoạn mã dưới dạng thẻ IMG hoặc IFRAME trong một trường chấp nhận HTML hoặc bằng một cuộc tấn công kịch bản chéo phức tạp hơn. Nếu kẻ tấn công làm được điều này, mức độ nghiêm trọng của cuộc tấn công được khuếch đại. Đặc biệt, khả năng xảy ra tấn công cao bởi nạn nhân có nhiều khả năng bị lừa xem các trang có chứa các dường dẫn độc hại hơn một số trang ngẫu nhiên trên Internet, cũng bởi vì nạn nhân chắc chắn đã được chứng thực vào trang web.

Cách phòng chống

Có nhiều lời khuyến cáo được đưa ra, tuy nhiên cho đến nay vẫn chưa có biện pháp nào có thể phòng chống triệt để CSRF. Sau đây là một vài kỹ thuật sử dụng.

  • Hạn chế thời gian tồn tại của session.
  • Sử dụng GET và POST đúng cách. Dùng GET nếu thao tác là truy vấn dữ liệu. Dùng POST nếu các thao tác tạo ra sự thay đổi hệ thống. Nếu ứng dụng của bạn theo chuẩn RESTful, bạn có thể dùng thêm các HTTP verbs, như PATCH, PUT hay DELETE.
  • Sử dụng token: Tạo ra một token tương ứng với mỗi form, token này sẽ là duy nhất đối với mỗi form và thường thì hàm tạo ra token này sẽ nhận đối số là”SESSION” hoặc được lưu thông tin trong SESSION, chèn thêm token vào đường link thực hiện thao tác. Khi nhận lệnh HTTP POST về, hệ thống sẽ thực hiên so khớp giá trị token này để quyết định có thực hiện hay không. Mục đích của token là làm cho hacker không thể xác định được chính xác đường link thực hiện thao tác.
  • Chèn bước xác nhận trung gian trước những thao tác nhạy cảm: ví dụ như sử dụng captcha, các thông báo xác nhận, yêu cầu nhập lại password hoặc sử dụng thêm OTP (One-time password) hay chứng thư số để xác nhận lại các giao dịch.
  • Sử dụng cookie riêng biệt cho trang quản trị: Một cookie không thể dùng chung cho các domain khác nhau, chính vì vậy việc sử dụng “admin.site.com” thay vì sử dụng “site.com/admin” là an toàn hơn.
  • Kiểm tra REFERRER: Kiểm tra xem các câu lệnh http gửi đến hệ thống xuất phát từ đâu. Một ứng dụng web có thể hạn chế chỉ thực hiện các lệnh http gửi đến từ các trang đã được chứng thực. Tuy nhiên cách làm này có nhiều hạn chế và không thật sự hiệu quả.
  • Kiểm tra IP: Một số hệ thống quan trọng chỉ cho truy cập từ những IP được
    thiết lập sẵn.

CSRF Protection trong Laravel

Giới thiệu

Có thể dễ dàng bảo vệ các ứng dụng của bạn từ tấn công giả mạo CSRF với Laravel ngay cả khi bạn không biết gì về CSRF. Laravel tự động tạo ra một CSRF “token” cho mỗi phiên người dùng đang hoạt động do ứng dụng quản lý. Token này dùng để xác minh rằng người dùng đã được chứng thực là người thực hiện yêu cầu cho ứng dụng.

Bất cứ khi nào tạo một HTML form trong ứng dụng, nên thêm một hidden field CSRF token vào trong form để CSRF middleware có thể xác nhận request. Với Laravel phiên bản 5.1 trở lên bạn chỉ cần sử dụng csrf_field để sinh ra field này:

<form method="POST" action="/profile">
{{ csrf_field() }}
...
</form>

Class VerifyCsrfToken middleware, bao gồm nhóm web middleware , sẽ tự động xác minh token từ request input giống với token lưu trong session.

Loại bỏ URIs khỏi CSRF Protection

Class VerifyCsrfToken đã được include trong middleware, tức là tất cả các POST request đã được bảo vệ khỏi CSRF. Nhưng chính điều đó lại trở thành vấn đề. Rõ ràng là không phải tất các POST request đều đến từ một form nào đó, có thể nó được gọi từ 1 API hoặc Ajax… VerifyCsrfToken trong $middleware array:

protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
];

Tuy nhiên bạn có thể loại bỏ nó khỏi những URL nhất định mà bạn muốn, mở app/Http/Middleware/VerifyCsrfToken.php thêm thuộc tính $except:

    <?php

    namespace App\Http\Middleware;

    use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

    class VerifyCsrfToken extends BaseVerifier
    {
        /**
         * The URIs that should be excluded from CSRF verification.
         *
         * @var array
         */
        protected $except = [
            'ajax/*',
        ];
    }

Lưu ý rằng (*) là một biểu tượng để quy định 1 rule nào đấy và rule này mô tả các URL chứ ko phải route.

X-CSRF-TOKEN

Ngoài việc kiểm tra CSRF token như 1 tham số POST, VerifyCsrfToken middleware cũng kiểm tra X-CSRF-TOKEN request header. Bạn có thể, ví dụ, lưu token trong thẻ HTML meta:

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

Sau đó, khi bạn đã tạo ra thẻ meta, bạn có thể hướng dẫn một thư viên như jQuery để tự động thêm token vào tất cả các request header. Điều này rất đơn giản, thuận tiện để bảo mật CSRF các ứng dụng AJAX của bạn:

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

X-XSRF-TOKEN

Laravel lưu CSRF token hiện tại trong XSRF-TOKEN cookie mỗi khi có response tạo ra bởi framework. Bạn có thể sử dụng cookie để đặt giá trị X-XSRF-TOKEN request header.

Cookie này chủ yếu được gửi đến một cách thuận tiện từ khi một số frameworks và thự viện của JavaScript, như Angular và Axios, nó tự động thêm giá trị vào X-XSRF-TOKEN header.

Tham khảo

Một số câu hỏi về CSRF Protection trong Laravel:

Bài viết không thể tránh khỏi những sai sót và nhầm lẫn, rất mong nhận được ý kiến đóng góp từ mọi người để có thể bổ sung kiến thức và hoàn thiện bài viết!