Cross-Site Request Forgery (CSRF) sắp hết thời?!!
Bài đăng này đã không được cập nhật trong 7 năm
Sau khi làm việc với Cross-Site Request Forgery trên web, chúng ta đã có một giải pháp tốt hơn. Không yêu cầu kỹ thuật cao, cũng không thực hiện khó khăn, nó đơn giản chỉ là triển khai, đó là Same-Site Cookies.
Các giải pháp hiện tại
Cross-Site Request Forgery, còn được gọi là CSRF hoặc XSRF, nó bắt nguồn từ khả năng đơn giản là một trang web gửi request tới một trang khác. Ví dụ rằng tôi nhúng form dưới đây vào một website nào đó của tôi:
<form action="https://your-bank.com/transfer" method="POST" id="stealMoney">
<input type="hidden" name="to" value="Tuan Ho">
<input type="hidden" name="account" value="101101010101" data-msg="TK VCB của mình đó ^^">
<input type="hidden" name="amount" value="1000000000">
<input type="hidden" name="currency" value="VND">
Trình duyệt của bạn sẽ load nội dung trên, tiếp đó tôi dùng Javascript để chạy lệnh dưới đây:
document.getElementById("stealMoney").submit();
Đây chính là CSRF. Tôi đang giả mạo một yêu cầu đang được gửi Cross-Site đến ngân hàng của bạn. Vấn đề thực sự ở đây không phải là tôi đã gửi request nhưng trình duyệt của bạn sẽ gửi cookie của bạn với nó. Request sẽ được gửi đi cùng với toàn bộ thông tin xác thực bạn đang nắm giữ tại thời điểm này, có nghĩa là nếu bạn đăng nhập vào ngân hàng của mình, bạn sẽ dâng hiến 1000000000 VNĐ cho tôi. Cảm ơn bạn rất nhiều! Nhưng nếu bạn chưa đăng nhập thì request sẽ không có hại vì bạn không thể chuyển tiền mà chưa đăng nhập. Hiện tại, có một vài cách mà ngân hàng của bạn có thể giảm thiểu các cuộc tấn công CSRF này.
CSRF mitigations
Tôi sẽ không trình bày chi tiết quá nhiều vì có rất nhiều thông tin có sẵn về chủ đề này trên Google nhưng tôi muốn nhanh chóng trình bày các yêu cầu kỹ thuật để thực hiện chúng.
Kiểm tra Origin header
Khi nhận được yêu cầu, chúng ta có thể có hai thông tin có sẵn cho chúng tôi để chỉ ra yêu cầu đến từ đâu. Đây là Origin header và Referer header. Bạn có thể kiểm tra một hoặc cả hai giá trị này để xem yêu cầu có xuất xứ từ nguồn gốc khác với chính bạn hay không. Nếu yêu cầu là cross-origin (tức request từ website khác) thì bạn chỉ cần vứt nó đi. Origin header và Referer header được gửi bởi trình duyệt để tránh giả mạo nhưng không phải lúc nào cũng có.
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
accept-encoding: gzip, deflate, br
cache-control: max-age=0
content-length: 166
content-type: application/x-www-form-urlencoded
dnt: 1
origin: https://viblo.asia
referer: https://viblo.asia/login
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Anti-CSRF tokens
Có hai cách khác nhau bạn có thể sử dụng các input Anti-CSRF nhưng nguyên tắc vẫn giữ nguyên. Khi khách truy cập yêu cầu một trang, như trang chuyển tiền trong ví dụ trên, bạn nhúng một mã token ngẫu nhiên vào form. Khi người dùng chính thức gửi form này, mã token ngẫu nhiên sẽ được trả lại và bạn có thể kiểm tra nó phù hợp với mã bạn đã phát hành trong form. Trong trường hợp tấn công CSRF, kẻ tấn công không bao giờ có thể nhận được giá trị này và không thể nhận được ngay cả khi họ yêu cầu trang vì Chính sách gốc giống nhau (SOP) sẽ ngăn không cho kẻ tấn công đọc phản hồi có chứa mã token. Phương pháp này hoạt động tốt nhưng yêu cầu trang web phải theo dõi việc phát hành và trả lại các mã token Anti-CSRF. Một phương pháp tương tự là nhúng mã token vào form và phát hành trình duyệt một cookie chứa cùng một giá trị. Khi người dùng chính thức gửi form của họ, giá trị trong cookie và form sẽ khớp khi trang web nhận được. Khi kẻ tấn công gửi yêu cầu giả mạo trình duyệt sẽ không có tập hợp cookie CSRF và thử nghiệm sẽ không thành công.
<form action="https://viblo.asia/login" method="POST">
<input type="hidden" name="csrf_token" value="d82c90fc4a14b01224gde6ddebc23bf0">
<input type="email" id="email" name="email">
<input type="password" id="password" name="password">
<button type="submit" class="btn btn-primary">Login</button>
</form>
Vấn đề
Các phương pháp trên đã cho chúng ta sự bảo vệ khá mạnh mẽ chống lại CSRF trong một thời gian dài. Kiểm tra Origin và Referer không phải là 100% đáng tin cậy và hầu hết các trang web sử dụng một số biến thể của cách tiếp cận mã token Anti-CSRF. Vấn đề là mặc dù rằng cả hai đặt một số loại yêu cầu trên trang web để thực hiện và duy trì các giải pháp. Họ có thể không phải là những điều phức tạp nhất về mặt kỹ thuật trên thế giới nhưng chúng tôi vẫn đang xây dựng một giải pháp để làm việc xung quanh trình duyệt đang làm một điều mà chúng tôi không muốn nó làm. Thay vào đó, tại sao chúng ta không nói với trình duyệt để ngừng làm những điều mà chúng ta không muốn nó làm? ... Bây giờ chúng ta sẽ làm điều đó!
Same-Site Cookies
Bạn có thể đã thấy các Same-Site Cookies được đề cập trong bài viết gần đây của tôi được gọi là Tough Cookies nhưng tôi sẽ đi sâu hơn một chút vào nó ở đây với một số ví dụ quá. Về cơ bản, Same-Site Cookies hoàn toàn và có hiệu quả trong các cuộc tấn công của CSRF. Nắm bắt được bản chất của những gì chúng tôi thực sự cần trên web để giành chiến thắng trong cuộc chiến bảo mật, Same-Site Cookies đang đơn giản triển khai, thực sự đơn giản. Mang cookie hiện có của bạn:
Set-Cookie: user_id=1234; path=/
Đơn giản là chỉ cần thêm thuộc tính SameSite.
Set-Cookie: user_id=1234; path=/; SameSite
Vậy là xong! Nó cho phép thuộc tính này trên cookie sẽ hướng dẫn trình duyệt để cung cấp khả năng bảo vệ này cho cookie này. Có hai chế độ mà bạn có thể kích hoạt bảo vệ này trong, Strict hoặc Lax, tùy thuộc vào mức độ nghiêm trọng bạn muốn nhận được. Chỉ định thuộc tính SameSite trong cookie của bạn mà không có thiết lập sẽ mặc định ở chế độ Strict nhưng bạn cũng có thể thiết lập Strict hoặc Lax nếu bạn muốn.
SameSite=Strict
SameSite=Lax
Strict
Thiết lập bảo vệ SameSite của bạn cho chế độ Strict rõ ràng là sự lựa chọn ưa thích nhưng lý do chúng tôi có hai lựa chọn là không phải tất cả các trang web đều giống nhau và không có cùng yêu cầu. Khi hoạt động ở chế độ Strict, trình duyệt sẽ không gửi cookie trên bất kỳ cross-origin request nào. Vấn đề duy nhất bạn có thể gặp phải là nó cũng sẽ không gửi cookie trên các điều hướng cấp cao nhất (thay đổi URL trong thanh địa chỉ). Nếu tôi trình bày liên kết tới https://facebook.com và Facebook đã đặt cookie SameSite vào chế độ Strict, khi bạn nhấp vào liên kết để mở Facebook, bạn sẽ không đăng nhập. Cho dù bạn đã đăng nhập hay chưa, hãy mở nó Trong một tab mới, bất kể bạn đã làm gì, bạn sẽ không đăng nhập vào Facebook khi truy cập từ liên kết đó. Điều này có thể là một chút gây phiền nhiễu hoặc bất ngờ cho người dùng nhưng cung cấp bảo vệ cực kỳ mạnh mẽ. Điều Facebook cần làm ở đây tương tự như những gì Amazon làm, họ có 2 cookie. Một là loại cookie cơ bản xác định bạn là người dùng và cho phép bạn có trải nghiệm đã đăng nhập nhưng nếu bạn muốn làm điều gì đó nhạy cảm như mua hàng hoặc thay đổi một cái gì đó trong tài khoản của bạn, bạn cần cookie thứ hai, Cookie thực cho phép bạn làm những việc quan trọng. Cookie đầu tiên trong trường hợp này sẽ không có thuộc tính SameSite, nó không thực sự cho phép bạn làm bất cứ điều gì nhạy cảm và nếu kẻ tấn công có thể gửi origin-cross request, không có gì xảy ra. Cookie thứ hai sẽ có thuộc tính SameSite và kẻ tấn công không thể lạm dụng quyền hạn của nó trong các request origin-cross. Đây là giải pháp lý tưởng cho cả người sử dụng và cho bảo mật. Điều này không phải lúc nào cũng có thể và bởi vì chúng tôi muốn các cookie SameSite được dễ triển khai, có một lựa chọn thứ hai.
Lax
Thiết lập bảo vệ SameSite cho chế độ lỏng lẻo khắc phục sự cố được đề cập ở trên trong chế độ Strict của một người dùng nhấp vào một liên kết và không được đăng nhập vào trang web mục tiêu nếu họ đã đăng nhập. Ở chế độ Lax có một ngoại lệ duy nhất để cho phép các tập tin cookie được gắn vào các điều hướng cấp cao sử dụng phương pháp HTTP an toàn. Phương pháp HTTP "an toàn" được định nghĩa trong Phần 4.2.1 của RFC 7321 dưới dạng GET, HEAD, OPTIONS và TRACE, với chúng tôi đang quan tâm đến phương pháp GET ở đây. Điều này có nghĩa là điều hướng trên cùng của chúng tôi đến https://facebook.com khi người dùng nhấp vào liên kết đã đặt các cookie gắn liền với SameSite khi trình duyệt thực hiện request sẽ duy trì trải nghiệm người dùng mong đợi. Chúng tôi vẫn còn được bảo vệ hoàn toàn trước các cuộc tấn công CSRF dựa vào POST. Trở lại ví dụ ngay ở đầu, cuộc tấn công này vẫn không hoạt động ở chế độ Lax.
<form action="https://your-bank.com/transfer" method="POST" id="stealMoney">
<input type="hidden" name="to" value="Tuan Ho">
<input type="hidden" name="account" value="101101010101" data-msg="TK VCB của mình đó ^^">
<input type="hidden" name="amount" value="1000000000">
<input type="hidden" name="currency" value="VND">
Bởi vì phương pháp POST không được coi là an toàn, trình duyệt sẽ không đính kèm các cookie trong yêu cầu. Kẻ tấn công tất nhiên sẽ thay đổi phương pháp để có một phương pháp 'an toàn' mặc dù và yêu cầu cùng một vấn đề.
<form action="https://your-bank.com/transfer" method="GET" id="stealMoney">
<input type="hidden" name="to" value="Tuan Ho">
<input type="hidden" name="account" value="101101010101" data-msg="TK VCB của mình đó ^^">
<input type="hidden" name="amount" value="1000000000">
<input type="hidden" name="currency" value="VND">
Nếu chúng ta không chấp nhận các yêu cầu GET thay cho các yêu cầu POST thì cuộc tấn công này là không thể, nhưng nó là điều cần lưu ý khi hoạt động ở chế độ Lax. Ngoài ra, nếu một kẻ tấn công có thể kích hoạt trình điều khiển cấp cao nhất hoặc bật một cửa sổ mới, họ cũng có thể làm cho trình duyệt gửi yêu cầu GET cùng với các cookie được đính kèm. Đây là trade-off hoạt động ở chế độ lỏng lẻo, chúng tôi giữ kinh nghiệm người dùng còn nguyên vẹn nhưng có một lượng nhỏ rủi ro để chấp nhận thanh toán.
Tác dụng khác
Bài viết này nhằm mục đích giảm bớt CSRF với Cookies SameSite nếu có thể. Đầu tiên trong số những người được liệt kê trong spec là Cross-Site Script Inclusion (XSSI), là nơi trình duyệt đưa ra yêu cầu về một tài sản như một kịch bản thay đổi tùy thuộc vào việc người dùng có được thẩm định hay không. Trong kịch bản request Cross-Site kẻ tấn công không thể lạm dụng quyền hạn xung quanh của Cookie SameSite để tạo ra một response khác. Ngoài ra còn có một số cuộc tấn công thời gian thú vị chi tiết ở đây cũng có thể được giảm nhẹ.
Một cách sử dụng thú vị khác không phải là chi tiết là sự bảo vệ chống lại việc rò rỉ giá trị của session cookie trong các cuộc tấn công kiểu BEAST nhằm chống lại sự nén (CRIME, BREACH, HEIST, TIME). Điều này thực sự cao nhưng kịch bản cơ bản là một MiTM có thể buộc trình duyệt phát hành request origin-cross thông qua bất kỳ cơ chế nào họ muốn và giám sát chúng. Bằng cách lợi dụng sự thay đổi kích thước yêu cầu trọng tải, kẻ tấn công có thể đoán giá trị ID phiên làm việc một byte mỗi lần bằng cách thay đổi yêu cầu mà trình duyệt thực hiện và quan sát kích thước của chúng trên dây. Sử dụng Cookie SameSite trình duyệt sẽ không bao gồm cookie trong các yêu cầu như vậy và kết quả là kẻ tấn công không thể đoán được giá trị của chúng.
Trình duyệt hỗ trợ
Với hầu hết các tính năng bảo mật mới trong các trình duyệt, bạn có thể mong đợi Firefox hoặc Chrome sẽ dẫn đầu và mọi thứ cũng không khác nhau ở đây. Chrome đã hỗ trợ Same-Site Cookies từ v51, điều này có nghĩa là Opera, Android Browser và Chrome trên Android cũng có hỗ trợ. Bạn có thể xem chi tiết trên caniuse.com liệt kê danh sách hỗ trợ hiện tại. Mặc dù sự hỗ trợ chưa phổ biến nhưng chúng tôi vẫn nên thêm thuộc tính SameSite vào cookie của chúng tôi. Các trình duyệt hiểu nó sẽ tôn trọng cài đặt và cung cấp cookie bảo vệ thêm trong khi những trình duyệt không đơn giản là bỏ qua nó và tiếp tục thực hiện. Không có gì để mất ở đây và nó tạo thành một cách tiếp cận rất phòng thủ tốt đẹp. Sẽ mất một thời gian dài cho đến khi chúng ta có thể xem xét loại bỏ các cơ chế chống CSRF truyền thống nhưng việc thêm SameSite lên trên đó mang lại cho chúng ta khả năng phòng thủ cực kỳ mạnh mẽ.
Nguồn
All rights reserved