PHP – CSRF 跨站請求偽造



縮寫“CSRF”代表跨站請求偽造。CSRF是一種網際網路漏洞,它涉及受信任的網站使用者發出未經授權的命令。透過採取本章中解釋的措施,可以為PHP Web應用程式提供針對此攻擊的充分保護。

預設情況下,瀏覽器使用“GET”請求方法傳送資料。這通常用作CSRF中的漏洞點。為了將命令注入特定網站,攻擊者使用諸如“IMG”之類的HTML標籤。例如,Web應用程式的URL端點,例如“/delete.php?empcode=1234”,會刪除GET請求的empcode引數傳遞的帳戶。現在,如果經過身份驗證的使用者在任何其他應用程式中遇到以下指令碼。

<img src="http://example.com/delete.php?empcode=1234" 
   width="0" height="0" border="0">

無意中導致與empcode=1234相關的資料被刪除。

解決此問題的常用方法是使用CSRF令牌。CSRF令牌是嵌入到請求中的隨機字元字串,以便Web應用程式可以信任已從預期的源(根據正常工作流程)接收請求。

實現CSRF的步驟

在PHP中實現CSRF令牌保護的步驟如下:

  • 啟動指令碼,開始一個新會話。

  • 生成一個隨機字元令牌。可以使用PHP提供的幾個內建函式中的任何一個來生成隨機字串。讓我們使用md5()函式來獲取生成唯一隨機字串的uniqueid()函式的雜湊值。

  • 在提供給使用者提交資料的HTML表單中,包含一個隱藏欄位,其值為上述步驟中生成的隨機令牌。

  • 然後,伺服器在表單提交後根據使用者會話驗證令牌,以消除惡意請求。

  • 您還可以新增另一個會話變數,其值為當前時間,併發送一個到期時間以進行驗證。

示例

這是實現CSRF令牌驗證機制的PHP程式碼。以下指令碼生成一個令牌並將其嵌入到HTML表單中。

<?php
   session_start();
   if(!isset($_SESSION["csrf_token"])) {
   
      // No token present, generate a new one
      $token = md5(uniqid(rand(), true));
      $_SESSION["csrf_token"] = $token;
	  
   } else {
   
      // Reuse the token
      $token = $_SESSION["csrf_token"];        
   }
?>
<html>
<body>
   <form method="get" action="test.php">
      <input type="text" name="empcode" placeholder="empcode" />
      <input type="hidden" name="csrf_token" value="<?php echo $token;?>" />
      <input type="submit" />
   </form>
</body>
</html>

該表單提交到下面的“test.php”指令碼:

<?php
   session_start();
   echo "hello";
   if ($_GET["csrf_token"] == $_SESSION["csrf_token"]) {

      // Reset token
      echo $_GET["csrf_token"] . "<br>";
      echo $_SESSION["csrf_token"] . "<br>";
      echo "<h3>CSRF token validation successful. Proceed to further action</h3>";
   } else {
      echo "<h3>CSRF token validation failed</h3>";
   }
?>

它將產生以下輸出

PHP Csrf

要模擬CSRF驗證失敗,請開啟瀏覽器的檢查工具,手動編輯隱藏欄位中的值,然後提交表單以檢視令牌不匹配,導致驗證失敗。

廣告