首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP intval() 安全陷阱深度解析與防禦指南

     編輯:PHP 相關知識

intval() 核心行為

<?php
// 從字符串開頭提取數字,直到遇到非數字字符
var_dump(intval("123abc"));    // 123
var_dump(intval("abc123"));    // 0
var_dump(intval("-456"));      // -456
var_dump(intval("  789 "));    // 789 (忽略前導空格)
var_dump(intval("0xFF"));      // 0 (不識別十六進制,除非 base=16)
var_dump(intval("0xFF", 16));  // 255
var_dump(intval("077", 8));    // 63 (八進制)
var_dump(intval(3.14));        // 3 (截斷小數)
var_dump(intval(true));        // 1
var_dump(intval(false));       // 0

經典安全漏洞:SQL 注入繞過

<?php
// 危險代碼
$id = $_GET['id'];
if (intval($id)) { // 意圖:確保是數字
    $sql = "SELECT * FROM users WHERE id = $id"; // 直接拼接!
    // 攻擊輸入: id=1 UNION SELECT password FROM admin--
    // intval("1 UNION...") => 1 (true)
    // SQL 變為: SELECT * FROM users WHERE id = 1 UNION SELECT password FROM admin--
}

根本原因分析

intval() 基於 C 標準庫 strtol(),其語義是**「解析前導數字」**,而非**「驗證整個字符串是純整數」**。

  • intval("1 evil") === 1 → 邏輯判斷通過,但原始字符串含惡意內容。
  • intval("") === 0、intval("abc") === 0 → 非數字開頭返回 0,可能被誤判為「合法的 0」。

正確的整數驗證與轉換姿勢

方案一:ctype_digit(僅正整數字符串)

<?php
function isPositiveIntString(string $val): bool {
    return ctype_digit($val) && $val !== '' && $val[0] !== '0'; // 可選:禁止前導零
}
if (isPositiveIntString($_GET['id'])) {
    $id = (int)$_GET['id']; // 安全轉換
}

方案二:filter_var(推薦)

<?php
$id = filter_var($_GET['id'], FILTER_VALIDATE_INT, [
    'options' => ['min_range' => 1, 'max_range' => PHP_INT_MAX]
]);
if ($id !== false) {
    // $id 已是 int 類型,安全
}

方案三:正則嚴格匹配

<?php
if (preg_match('/^[1-9]\d*$/', $_GET['id'])) {
    $id = (int)$_GET['id'];
}

方案四:PHP 8.1+ 僅讀屬性 + 建構函數驗證

<?php
class UserId {
    public function __construct(public readonly int $value) {
        if ($value < 1) throw new InvalidArgumentException('ID 必須為正整數');
    }
}
try {
    $id = new UserId((int)$_GET['id']); // 先轉換再驗證
} catch (Throwable $e) { /* 400 Bad Request */ }

intval() 合法使用場景

  • 已知字符串**純數字**或**以數字開頭需提取前綴**(如解析 "123px" → 123)。
  • 浮點數截斷取整(明確業務需求)。
  • 布爾/資源轉整數。
  • 指定進制轉換:intval('FF', 16)。

WordPress 歷史漏洞案例回顧

WordPress ≤ 2.0.6 wp-trackback.php 使用 intval($charset) 驗證字符集參數,攻擊者傳入 1 UNION SELECT... 繞過檢查導致 SQL 注入。修復改用 ctype_digit + 預處理語句。

項目級防禦清單

  1. 禁用 intval($_GET[x]) 作為安全檢查,代碼審查工具標記為高危模式。
  2. 所有入口參數驗證統一使用 filter_var 或專門驗證類。
  3. 數據庫操作**強制使用預處理語句**,絕不拼接經 intval 處理的變量。
  4. 單元測試覆蓋邊界:"1 OR 1=1", "0; DROP TABLE", " 123 ", "0xFF", ""。
  5. 靜態分析規則:Psalm/PHPStan 檢測 intval($_GET|_POST|_REQUEST) 模式。

總結

intval() 是「解析器」,不是「驗證器」。**永遠不要用 intval() 返回值的真假作為安全判斷依據**。轉型用 (int) 或 intval(),驗證用 filter_var/ctype_digit/正則/值對象,查詢用預處理。三層防線,方能破解「數字開頭」的萬惡之源。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved