我最近發現,發送包含「意外」陣列(而不是字串)的變數可能會導致致命錯誤或其他不良行為。範例:
我們有以下陣列:
$list = array( "a" => "first", "b" => "second" );
使用者傳送 $_REQUEST["key"]
,它將用於尋找該清單中的某個元素:
echo ($list[$_REQUEST["key"]] ?? null);
如果$_REQUEST["key"]
的型別為string
、int
、float
、bool
或null
,則腳本將顯示找到的條目或不顯示任何內容(= 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粉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; }
您可以建立驗證框架或使用第三方框架。
在弄亂所有輸入之前,我會做很多事情,只是為了防止特定的極端情況。