Tấn công CSRF và cách phòng chống
1 Giới thiệu về CSRF Cross-Site Request Forgery (CSRF) là một hình thức tấn công nhằm vào người dùng nhằm thực thi các hành động không mong muốn trên ứng dụng web dựa vào quyền chứng thực của người dùng. Các cuộc tấn công CSRF nhằm vào việc thực hiện các yêu cầu thay đổi trạng thái, chứ không ...
1 Giới thiệu về CSRF
Cross-Site Request Forgery (CSRF) là một hình thức tấn công nhằm vào người dùng nhằm thực thi các hành động không mong muốn trên ứng dụng web dựa vào quyền chứng thực của người dùng. Các cuộc tấn công CSRF nhằm vào việc thực hiện các yêu cầu thay đổi trạng thái, chứ không phải trộm cắp dữ liệu. Bằng việc sử dụng các kỹ thuật tấn công xã hội (như gửi link qua email hay chat), kẻ tấn công có thể lừa người dùng đang sử dụng ứng dụng web thực thi các hành động mà kẻ tấn công mong muốn. Nếu nạn nhân là người dùng bình thường, một cuộc tấn công CSRF thành công có thể buộc người dùng thực hiện các yêu cầu chuyển đổi trạng thái như chuyển tiền, thay đổi địa chỉ email của họ, vân vân. Nếu nạn nhân là người quản trị, CSRF có thể tác động đến toàn bộ ứng dụng web.
2 Kịch bản tấn công
Có rất nhiều cách để đánh lừa người dùng tải hoặc gửi thông tin tới một ứng dụng web. Để thực hiện một cuộc tấn công, trước tiên chúng ta phải hiểu làm thế nào để tạo ra một yêu cầu độc hại cho nạn nhân để thực thi. Hãy cũng xem xét ví dụ sau: Taric muốn chuyển cho Thresh 100$$thông qua trang web bank.com có chứa lỗ hổng CSRF. Lucian, kẻ tấn công, muốn lừa Taric gửi tiền cho anh ấy thay vì gửi cho Thresh. Cuộc tấn công gồm 2 bước sau:
- Tạo một URL để khai thác hoặc dùng một đoạn mã script.
- Lừa Taric thực thi bằng cách sử dụng các kỹ thuật xã hội.
2.1 Tấn công thông qua phương thức GET Nếu ứng dụng web chủ yếu sử dụng phương thức GET để chuyển các tham số và thực hiện các hành động, hoạt động chuyển tiền của Taric có thể giống như sau: Bằng việc lợi dụng lỗ hổng CSRF, Lucian có thể sử dụng Taric làm nạn nhân của mình. Đầu tiên, Lucian muốn chuyển 100.000 từ tài khoản của Taric sang tài khoản của anh ta. Lucian tạo một URL và thay thế người nhận tiền từ Thresh thành Lucian, tiếp đó tăng số tiền gửi lên 100.000: Sử dụng các kỹ thuật xã hội nhằm lừa Taric truy cập vào URL trên khi anh ấy đã đăng nhập vào trang web của bank.com. Việc này có thể thự hiện bằng một trong các kỹ thuật sau:
- Gửi một email có chứa URL tới cho Taric
- Giả mạo website bank.com nhằm đánh lừa Taric thực thi URL. Mã URL khai thách có thể được ngụy trang dưới dạng một liên kết thông thường, thu hút nạn nhân click vào nó: Hoặc một bức ảnh giả với kích thước 0x0: Nếu ảnh này được gắn trong email thì Taric sẽ không thể nhận ra được. Tuy nhiên , trình duyệt vẫn sẽ gửi yêu cấu tới bank.com mà không có bất kỳ dấu hiệu trực quan nào cho thấy việc chuyển tiền đã diễn ra.
2.2 Tấn công qua phương thức POST Giả sử bây giờ ngân hàng sử dụng phương thức POST và nội dung của yêu cầu chuyển tiền sẽ thay đổi như sau: Do sử dụng phương thức POST nên việc ngụy trang URL thông qua thẻ <a> và thẻ <img> không còn tác dụng nữa, tuy nhiên ta có thể gửi bằng cách sử dụng các thẻ định dạng của FORM: Form này sẽ yêu cầu người dùng click vào nút submit để gửi thông tin lên server, tuy nhiên điều này có thể thực hiện tự động bằng JavaScript: Thông qua cách này ta hoàn toàn có thể tọa form như ý muốn và tự động submit không cần đến sự tác động từ người dùng.
3 Cơ chế chống tấn công CSRF trong Rails 3
Rails có một cơ chế được tích hợp sẵn để ngăn chặn tấn công CSRF, đó là protect_from_forgery, khai báo trong lớp điều khiển application_controller.rb khi khởi tạo ứng dụng mới. Phương pháp protect_from_forgery này đảm bảo ứng dụng của bạn được bảo vệ khỏi tin tặc. 3.1 Phân tích hàm protect_from_forgery trong Rails Rails sinh ra một tokens ngẫu nhiên được mã hóa, token này được gán với phiên của người dùng. Bên trong mỗi form, một trường hidden có tên là authenticity_token được chèn vào. Trường này chứa token đã được sinh ra ở trên. Sau khi form được submit bằng phương thức POST, server so sánh giá trị authenticity_token gửi lên với với giá trị được sinh ra theo phiên làm việc của người dùng, nếu không khớp, điều này cho thấy yêu cầu gửi lên có thể là một yêu cầu giả mạo được gây ra bởi kẻ tấn công và sẽ bị từ chối xử lý bởi hàm protect_from_forgery.
Tuy nhiên, trong một số trường hợp, mặc dù ứng dụng web đã triển khai phương thức protect_from_forgery nhưng vẫn bị tấn công CSRF. Tại sao lại như vậy?
Để trả lời câu hỏi này, hãy tìm hiểu sâu hơn vào source của ActionController. Khi chúng ta gọi phương thức protect_from_forgery, chúng ta cũng đồng thời tạo ra before filter, cái mà sẽ gọi đến hàm verify_authenticity Khi hàm verify_authenticity_token được chạy, nó sẽ kiểm tra xem yêu cầu đã được xác minh chưa bằng cách gọi hàm verified_request?. Nếu xác minh thất bại, nó sẽ sinh ra một cảnh báo và gọi đến hàm handle_unverified_request. Hàm verified_request? sẽ so sánh authenticity_token, cái mà được chứa trong sesion[:_csrf_token], với các thuộc tính được gửi lên bằng phương thức POST và X-CSRF-Token HTTP Header. Nếu khớp với nhau thì yêu cầu xác minh là đúng. Nếu sai thì sẽ gọi đến hàm handle_unverified_request.
handle_unverified_request sẽ gọi đến ActionDispatch_reset_session để xóa các session liên quan đến yêu cầu giả mạo. Tuy nhiên, request vẫn tiếp tục để xử lý mà không có sesion. Bằng việc xóa session liên quan đến các request giả mạo, chúng ra khiến cho request vẫn được xử lý như những người dùng chưa đăng nhập.
Tóm tắt flow của phương thức protect_from_fogery trong Rails như sau: Vậy làm cách nào để khắc phục điều này?
Bằng việc ghi đè lên hàm handle_inverified_request trong application contronller, chúng ta có thể định nghĩa lại hành động sẽ xảy ra khi yêu cầu không được xác minh. Trong trường hợp này, ta sẽ thay đổi đếm đưa ra một ngoại lệ và yêu cầu ngừng thực hiện request. Xem xét ví dụ dưới đây:
4 Một số thay đổi trong Rails 4
Rất may, mọi thứ đã thay đổi đôi chút trong Rails 4. Bây giờ, phương thức protect_from_forgery sẽ dùng cookies khi loại bỏ các thông tin nhạy cảm khỏi các yêu cầu giả mạo. Flow sẽ có chút thay đổi như sau: Phương thức handle_unverified_request đã được cấu trúc lại để gọi trình xử lý của module ProtectionMethods, giúp loại bỏ session dât, thông tin flash, và các cookies liên quan đến yêu cầu không xác minh.
Tuy nhiên thì giống với Rails 3, yêu cầu vẫn được thực hiện.
Hãy cùng tìm hiểu về lỗi này. Hãy xem qua ví dụ sau: Ứng dụng gọi protect_from_forgery, nếu cần.Bởi vì hàm "transfer_funds" nhận được các đối số của người dùng chứ không phải nhận từ phiên làm việc, phương thức này được thực hiện ngay cả khi không kiểm tra verified_request?. Điều này có nghĩa là kẻ tấn công có thể tạo yêu cầu giả mạo và lừa người dùng hợp pháp thực hiện yêu cầu.
Để khắc phục việc này, chúng ta có thể thêm tham số vào phương thức protect_from_forgery
5 Tổng kết
CSRF là một lỗ hồng nghiêm trọng rất phổ biến. Trong Rails, phương thức protect_from_forgery giúp bảo vệ các ứng dụng khỏi lỗ hổng này. Tuy nhiên nó không thể bảo vệ một cách hoàn toàn. Trong một số tình huống, ứng dụng của bạn vẫn có thể bị gây hại. Bằng việc hiểu rõ cách hoạt động của phương thức bảo mật này sẽ giúp chúng ta phòng tránh cuộc tấn công ngoài ý muốn