搜尋

首頁  >  問答  >  主體

PHP:處理使用者輸入中的(意外)數組

我最近發現,發送包含「意外」陣列(而不是字串)的變數可能會導致致命錯誤或其他不良行為。範例:

我們有以下陣列:

$list = array(
"a" => "first",
"b" => "second"
);

使用者傳送 $_REQUEST["key"],它將用於尋找該清單中的某個元素:

echo ($list[$_REQUEST["key"]] ?? null);

如果$_REQUEST["key"] 的型別為stringintfloatboolnull,則腳本將顯示找到的條目或不顯示任何內容(= null)。這就是所需的行為。

如果 $_REQUEST["key"]array,則腳本將因致命錯誤而停止。


現在,顯而易見的解決方案是在整個程式碼中添加數千個類型檢查(is_scalar()!is_array())。但我想知道從安全角度來看,以下替代方案聽起來是否合理:

在每個請求開始時,以下腳本將執行:

$_COOKIE = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_COOKIE);
$_REQUEST = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_REQUEST);
$_POST = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_POST);
$_GET = array_map(function($e) { return (is_array($e) ? json_encode($e, JSON_INVALID_UTF8_IGNORE) : $e); }, $_GET);

這實際上禁用了將陣列傳送到伺服器的功能。如果實際需要程式碼數組中的任何位置,則將使用 json_decode() 手動解碼它們。

這是個好主意嗎?

P粉547362845P粉547362845240 天前552

全部回覆(1)我來回復

  • P粉668113768

    P粉6681137682024-04-02 14:31:09

    您手動解碼每個輸入變量,以避免手動驗證每個輸入變數。對我來說,這也是同樣的煩惱,但更令人困惑,性能較差,並且有新的錯誤(例如,如果輸入不是有效的UTF-8,json_encode() 將中斷) 。

    一般來說,明確您的應用程式輸入是有好處的。確保您使用一組處於已知狀態的已知變數確實可以節省時間和麻煩。

    $key = isset($_REQUEST['key']) && is_string($_REQUEST['key']) ? $_REQUEST['key'] : null;
    $item = $list[$key] ?? null;

    如果 \TypeError 是您唯一關心的問題,您可以將所有內容包裝在 try/catch 區塊中。

    您可以使用函數來避免程式碼重複:

    function get(string $name, ?string $default = null): ?string
    {
        if (isset($_REQUEST[$name]) && is_string($_REQUEST[$name])) {
            return $_REQUEST[$name];
        }
        return $default;
    }

    您可以建立驗證框架或使用第三方框架。

    在弄亂所有輸入之前,我會做很多事情,只是為了防止特定的極端情況。

    回覆
    0
  • 取消回覆