У меня есть контроллер, который принимает пост-параметры из формы HTML, затем отправляет их в модель, которая будет вставлять массив в базу данных Cassandra.
Это SQLInjection доказательство, потому что это NoSQL, однако я боюсь, что пользователь может просто имитировать 100 000 пост-параметров или просто добавить некоторые, которые мне не нужны, и он будет вставлен в базу данных. Как я могу убедиться, что только мои значения останутся в моем массиве.
Пример:
$post = ['parent_id', 'type', 'title', 'body', 'tags']; // Good $post = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three'] // Bad
Как я могу убедиться, что мой массив отключит все элементы, которые не в хорошем примере?
Вы ищете array_intersect
:
$good = ['parent_id', 'type', 'title', 'body', 'tags']; $post = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three']; print_r(array_intersect($good, $post));
Смотрите в действии .
Конечно, этот конкретный пример не имеет особого смысла, потому что он работает с значениями массива, но также есть array_intersect_key
который делает то же самое на основе ключей.
Посредством белого списка записей, которые вы ожидаете.
<?php $post = array( 'parent_id' => 1, 'type' => 'foo', 'title' => 'bar', 'body' => 'foo bar', 'tags' => 'foo, bar', 'one' => 'foo', 'two' => 'bar', 'three' => 'qux' ); $whitelist = array( 'parent_id', 'type', 'title', 'body', 'tags' ); $filtered = array_intersect_key( $post, array_flip( $whitelist ) ); var_dump( $filtered );
Во всяком случае, использование Cassandra в качестве хранилища данных, конечно, не является основанием для того, чтобы не выполнять валидацию данных, которые вы получаете.
Используйте пересечение массива. массив пересекается , это поможет вам.
Это будет выводиться так же, как $ post_allowed. То, что он делает, это разрешить только значения в $ post_input, которые также присутствуют в $ post_allow.
$post_allowed = ['parent_id', 'type', 'title', 'body', 'tags']; $post_input = ['parent_id', 'type', 'title', 'body', 'tags', 'one', 'two', 'three']; $post = array_intersect($post_input, $post_allowed);
Это называется белым листингом, ваш пример вводит в заблуждение, поскольку $_POST
является массивом ассоциаций.
$post = [ 'parent_id' => 'val', 'type' => 'val', 'title' => 'val', 'body' => 'val', 'tags' => 'val', 'one' => 'val', 'two' => 'val', 'three'=>'val', ]; $whitelist = ['parent_id', 'type', 'title', 'body', 'tags']; $sanitized_post = array_whitelist_assoc($post, $whitelist);
Это функция «белый список», созданная для ассоциативных массивов.
if(!function_exists('array_whitelist_assoc')){ /** * Returns an associative array containing all the entries of array1 which have keys that are present in all the arguments when using their values as keys. * * @param array $array The array with master keys to check. * @param array $array2 An array to compare keys against its values. * @return array $array2,... A variable list of arrays to compare. * */ function array_whitelist_assoc(Array $array1, Array $array2) { if(func_num_args() > 2){ $args = func_get_args(); array_shift($args); $array2 = call_user_func_array('array_merge', $args); } return array_intersect_key($array1, array_flip($array2)); } }
Если вы имеете дело с ассоциативными массивами, и по какой-либо причине вы не хотите использовать array_intersect_key()
, вы также можете сделать более простой подход для создания нового массива вручную, используя значения, которые вы хотите использовать из старого.
$post = array( 'parent_id' => 1, 'type' => "post", 'title' => "Post title", 'body' => "Post body", 'tags' => "Post tags", 'malicious' => "Robert'); DROP TABLE students;--" ); $good = array( 'parent_id' => $post['parent_id'], 'type' => $post['type'], 'title' => $post['title'], 'body' => $post['body'], 'tags' => $post['tags'] );
Что относительно многомерного массива? Я был исследован на пару часов для этого решения, нигде не нашел оптимального решения. поэтому, я написал это сам
function allow_keys($arr, $keys) { $saved = []; foreach ($keys as $key => $value) { if (is_int($key) || is_int($value)) { $keysKey = $value; } else { $keysKey = $key; } if (isset($arr[$keysKey])) { $saved[$keysKey] = $arr[$keysKey]; if (is_array($value)) { $saved[$keysKey] = allow_keys($saved[$keysKey], $keys[$keysKey]); } } } return $saved; }
использовать: пример
$array = [ 'key1' => 'kw', 'loaa'=> ['looo'], 'k' => [ 'prope' => [ 'prop' => ['proo', 'prot', 'loolooo', 'de'], 'prop2' => ['hun' => 'lu'], ], 'prop1' => [ ], ], ];
call: example
allow_keys($array, ['key1', 'k' => ['prope' => ['prop' => [0, 1], 'prop2']]])
вывод:
Array ( [key1] => kw [k] => Array ( [prope] => Array ( [prop] => Array ( [0] => proo [1] => prot ) [prop2] => Array ( [hun] => lu ) ) ) )
поэтому вы получаете только нужные ключи из многомерного массива. он не ограничивается только «многомерным», вы можете использовать его, передавая массив вроде
['key1', 'loaa']
вы получаете:
Array ( [key1] => kw [loaa] => Array ( [0] => looo ) )
ура!
Стоит вспомнить, что в то время как array_intersect
и array_intersect_key
хороши, они вполне могут быть переполнены. В моей ситуации я хотел только 1 элемент слева, поэтому самым простым вариантом было просто перестроить массив, который я хотел, на основе ключа / значений, которые мне нужны. Интересно, в какой момент массив array_intersect не стоит того, и вам просто лучше с $new = array('whatI'=>'want');
, Я верю в ОП, это того стоит, но в меньших случаях это может быть излишним.
Альтернативно, в ответ на исходный вопрос, просто используя unset
возможно, был более дешевый вариант – unset($post['one'],$post['two'],$post['three'])
. Опять же, это относится к точке, в которой это становится слишком неэффективным, и функции array_intersect лучше.