max_input_varsとリクエストパラメータの消失
はじめに
開発中の機能をテストしているとき、想定外の挙動となりエラーが発生しました。
原因の調査から解決するまでを書いていきます。
何が起きたか
データを一括登録するAPIで300件のデータをPOST送信したところ、リクエストパラメータが以下のようになっていました。
$arr = [
0 => [
'key1' => 1,
'key2' => 2,
'key3' => [
'key3_1' => 'hoge',
'key3_2' => 'fuga',
'key3_3' => 'hogefuga',
'key3_4' => 'fugahoge',
],
],
1 => [
'key1' => 1,
'key2' => 2,
'key3' => [
'key3_1' => 'hoge',
'key3_2' => 'fuga',
'key3_3' => 'hogehuga',
'key3_4' => 'fugahoge',
],
],
...
166 => [
'key1' => 1,
'key2' => 2,
'key3' => [
'key3_1' => 'hoge',
'key3_2' => 'fuga',
// key3_3,key3_4とkey167以降のデータが消失している
],
],
];
調査の結果 php.ini
の max_input_vars
設定値を超えていたため、リクエストパラメータが削除されていました。
設定値はデフォルトの1,000となっていました。
max_input_varsとは
入力変数を最大で何個まで受け付けるかを指定します (この制限は、スーパーグローバル
_POST そして $_COOKIE にそれぞれ個別に適用されます)。このディレクティブを使うと、ハッシュの衝突を悪用したサービス不能攻撃を受ける可能性を軽減できます。 このディレクティブで設定した数を超える入力変数があった場合は E_WARNING が発生し、それ以降の入力変数はリクエストから削除されます。 _GET、
Content-Type: multipart/form-data
のデータ数に関するパラメータになります。
入力変数の件数が設定値を超えるとログに以下の Warning
が出力されますが、プログラムの処理は実行されます。
PHP Warning: Unknown: Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini. in Unknown on line 0, referer:
解決策
-
max_input_vars
の設定値を変更する - 仕様変更を検討する
- 一度にPOSTできるデータ数に上限を設ける
- 入力されたデータを切り分けてAPIを複数回叩く
max_input_vars
は上記マニュアルの引用からセキュリティの観点で安易に変更するものではないことがわかります。
今回は 入力されたデータを切り分けてAPIを複数回叩く
を採用し解決できました。
入力変数について
リクエストパラメータには配列の入れ子となっている要素も複数存在しています。
それらも max_input_vars
の影響を受けるのか調べます。
リクエストパラメータの要素数を出力させる
上記リクエストパラメータの要素数 count($arr, COUNT_RECURSIVE)
で出力させると 1,334
となり、設定値の1,000を大幅に上回っています。
count($arr, COUNT_RECURSIVE)
は多次元配列のすべての要素をカウントするため
$arrの要素数: 167
key0-165配列の要素数: 7
key166配列の要素数: 5
167 + (166 * 7) + 5 = 1334
max_input_vars
で設定されている数値と一致しません。
数値や文字列が格納されている要素数を算出する
数値や文字列が格納されている要素数は
key0-165配列の要素数: 6
key166配列の要素数: 4
165 * 6 + 4 = 1000
max_input_vars
で設定されている数値と一致したため、配列の入れ子となっている要素は max_input_vars
に影響しないことがわかりました。
感想
php.ini
は変更しにくいためどうするのが得策か非常に悩みました。
この記事が同じ問題で躓いた方の助けになれば幸いです!!
Discussion