Nếu tôi hiểu điều này một cách chính xác, có vẻ như bạn đang đặt mã thông báo cho mỗi yêu cầu. Tôi đoán rằng trang cũ vẫn còn mã thông báo cũ. Tôi sẽ kiểm tra xem mã thông báo đã được đặt chưa trước khi tự động thổi bay nó.
if (isset($_SESSION['token'])){
//do nothing
} else{
$_SESSION['token'] = md5(rand());
}
Chỉnh sửa Để giải quyết câu hỏi của bạn.
Thay vì chỉ sử dụng một khóa "mã thông báo", hãy tạo một khóa cho mỗi phiên trình duyệt.
$_SESSION[$sessionId] = md5(rand());
Tất nhiên, mẹo sẽ là tìm ra khi nào những điều đó xảy ra bởi vì nếu bạn không thể sử dụng phiên, bạn thực sự sẽ không biết liệu yêu cầu đến từ tab mới hay tab cũ. Bạn có thể sử dụng chuỗi truy vấn để chuyển tham số này xung quanh. Về cơ bản, tất cả các yêu cầu sẽ phải có tham số này nếu không bạn không liên kết phiên với chúng.
ví dụ:
http://www.yoursite.com/somepage.php?sessionid=<some generated id>
Cuối cùng, người dùng có thể phát hiện ra điều này nhưng tôi không chắc có bất kỳ cách nào để giải quyết vấn đề đó.
Chỉnh sửa 2 Ok, đây là suy nghĩ của tôi về cách bạn nên làm điều này. Các chuyên gia bảo mật ngoài kia, cứ thoải mái cho tôi nếu tôi mắc sai lầm này, như tôi đã nói trước đây rằng tôi không phải là chuyên gia, nhưng có vẻ như tôi sẽ thoát ra khỏi vấn đề này mà không đề xuất điều gì đó; -)
Vấn đề với CSFR là một số người dùng độc hại, Bob, có thể tạo một phần tử trên một trang web khác khiến trình duyệt của Alice đưa ra yêu cầu đối với một số trang web khác và vì Alice đã đăng nhập trước đó và thông tin đó được lưu trữ dưới dạng cookie hoặc Alice được nhận dạng thông qua phiên, trang web thực hiện yêu cầu như thể Alice đã yêu cầu. Ví dụ:nếu ngân hàng của Alice là http://www.mybank.com , sau đó Bob có thể tạo một bài đăng trên diễn đàn có chứa
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />
Ngân hàng của Alice sẽ nhận ra trình duyệt của cô ấy đang đưa ra yêu cầu, vì nghĩ rằng đó là cô ấy. Có một vài điều quan trọng phải xảy ra (nếu không kết hợp được với nhau, một trong hai điều này sẽ khiến cuộc tấn công thất bại) để biến đây trở thành một cuộc tấn công khả thi (đây là những điều quan trọng để hiểu cách ngăn chặn nó):
- Alice phải đăng nhập vào trang web ngân hàng của mình để ngân hàng nhớ đến cô ấy. Điều này có thể xảy ra trong cookie ("nhớ tôi") hoặc qua phiên. Tuy nhiên, nếu cô ấy đóng trình duyệt của mình (kết thúc phiên) hoặc xóa cookie của mình, thì không có mối đe dọa nào vì trang web ngân hàng sẽ không nhận ra cô ấy và sẽ từ chối yêu cầu.
- Bob phải có khả năng cung cấp tất cả các thông số cần thiết cho yêu cầu, nếu không, trang web ngân hàng sẽ từ chối yêu cầu.
Để cung cấp một số khái niệm về "trạng thái" trên đầu một giao thức không trạng thái (HTTP), bạn thực sự không thể tránh khỏi rủi ro trong (1). Trừ khi bạn khiến mọi người luôn nhấp vào "đăng xuất" hoặc đóng cửa sổ của họ, v.v., bạn không thể làm gì xung quanh việc lưu trữ thông tin trong trình duyệt hoặc phiên. Tuy nhiên, bạn có thể ngăn (2) khỏi là một vấn đề. Giải pháp của tôi cho điều này (và tôi chắc rằng có rất nhiều giải pháp khác) là tạo một hàm băm, giống như bạn đang làm và lưu trữ nó trong phiên.
Ví dụ,
$_SESSION['token'] = md5(rand());
Sau đó, những gì bạn làm là nối mã thông báo đó vào tất cả các liên kết nội bộ của bạn.
http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd
Bạn KHÔNG BAO GIỜ lưu trữ mã thông báo đó trong bộ nhớ trình duyệt:tức là một cookie. Khi yêu cầu được thực hiện, trước khi bạn làm bất cứ điều gì, bạn kiểm tra mã thông báo
//note, you'll want to sanitize user input, I'm just being brief
if ($_GET['token'] != $_SESSION['token']){
//User either attempted to enter a link on their own or it's a CSRF attack
header('HTTP/1.1 403 Forbidden');
}else{
//do whatever needs to be done
}
Chìa khóa của điều này là tất cả các liên kết trên trang web của bạn sẽ bao gồm mã thông báo. Tuy nhiên, Bob không có cách nào để biết mã thông báo đó là gì vì nó không được lưu trữ trong cookie trên trình duyệt. Nếu anh ta cố gắng tạo liên kết đến một trong các trang của bạn, nó sẽ chứa sai khóa hoặc sẽ không chứa bất kỳ khóa nào và bạn có thể từ chối. (Công bằng mà nói, có khả năng anh ta có thể đoán chính xác mã thông báo cho một người dùng cụ thể tình cờ xem mã của anh ta, nhưng anh ta có nhiều khả năng bùng cháy hơn.)
Không cần chỉ định thời gian chờ cho mã thông báo vì mã thông báo sẽ bị xóa khi trình duyệt bị đóng và cần được tạo lại khi người dùng truy cập trang web.