Каковы лучшие функции очистки ввода PHP?

161

Я пытаюсь придумать функцию, через которую я могу пропустить все свои струны для дезинфекции. Так что полученная строка будет безопасной для вставки в базу данных. Но существует так много фильтрующих функций , что я не уверен, какие из них мне нужно использовать.

Пожалуйста, помогите мне заполнить пробелы:

function filterThis($string) {
    $string = mysql_real_escape_string($string);
    $string = htmlentities($string);
    etc...
    return $string;
}
Lauren
источник
4
для вставки можно просто выполнить очистку от внедрения SQL, используя mysql_real_escape_string. Когда вы используете данные SELECT (в выводе html или в формуле / функции php), вы должны применять htmlentities
davidosomething
См. Stackoverflow.com/questions/60174/… для ответа, относящегося к очистке для вставки базы данных (он дает пример PDO, который другие упоминали ниже).
Пэт

Ответы:

433

Стоп!

Вы делаете ошибку здесь. О, нет, вы выбрали правильные функции PHP, чтобы сделать ваши данные немного безопаснее. Это хорошо. Ваша ошибка в порядке операций , а также о том, как и где использовать эти функции.

Важно понимать разницу между очисткой и проверкой пользовательских данных, экранированием данных для хранения и экранированием данных для представления.

Санитарная обработка и проверка пользовательских данных

Когда пользователи отправляют данные, вы должны убедиться, что они предоставили то, что вы ожидаете.

Санитарная обработка и фильтрация

Например, если вы ожидаете число, убедитесь, что представленные данные являются числом . Вы также можете преобразовывать пользовательские данные в другие типы. Все представленное вначале обрабатывается как строка, поэтому принудительное преобразование известных числовых данных в целое число или число с плавающей запятой делает очистку быстрой и безболезненной.

А как насчет текстовых полей свободной формы и текстовых полей? Вы должны убедиться, что в этих полях нет ничего неожиданного. Главным образом, вам нужно убедиться, что поля, которые не должны содержать никакого HTML-контента, на самом деле не содержат HTML. Есть два способа решения этой проблемы.

Во-первых, вы можете попробовать экранировать ввод HTML с помощью htmlspecialchars. Вы не должны использовать htmlentitiesдля нейтрализации HTML, поскольку он также будет выполнять кодирование ударных и других символов, которые, по его мнению, также должны быть закодированы.

Во-вторых, вы можете попробовать удалить любой возможный HTML. strip_tagsэто быстро и легко, но также небрежно. HTML Purifier выполняет гораздо более тщательную работу, убирая весь HTML, а также предоставляя выборочный белый список тегов и атрибутов.

Современные версии PHP поставляются с расширением фильтра , которое обеспечивает комплексный способ очистки пользовательского ввода.

Проверка

Убедиться, что представленные данные не содержат неожиданного контента, - это только половина работы. Вы также должны попытаться убедиться, что представленные данные содержат значения, с которыми вы действительно можете работать.

Если вы ожидаете число от 1 до 10, вам нужно проверить это значение. Если вы используете один из этих новых модных цифровых вводов эпохи HTML5 со счетчиком и шагами, убедитесь, что представленные данные соответствуют шагу.

Если эти данные поступили из того, что должно быть раскрывающимся меню, убедитесь, что введенное значение является тем, которое появилось в меню.

А как насчет ввода текста, который отвечает другим потребностям? Например, дата входы должны быть проверены путем strtotimeили класс DateTime . Данная дата должна быть между ожидаемыми диапазонами. А как насчет адресов электронной почты? Ранее упомянутое расширение фильтра может проверить, правильно ли сформирован адрес, хотя я фанат библиотеки is_email .

То же самое верно для всех других элементов управления формы. Есть радио кнопки? Проверить по списку. Есть флажки? Проверить по списку. Есть файл для загрузки? Убедитесь, что файл имеет ожидаемый тип, и обрабатывайте имя файла как нефильтрованные пользовательские данные.

Каждый современный браузер поставляется с полным набором встроенных инструментов разработчика, что позволяет каждому легко манипулировать вашей формой. Ваш код должен предполагать, что пользователь полностью снял все ограничения на стороне клиента для содержимого формы !

Экранирование данных для хранения

Теперь, когда вы убедились, что ваши данные находятся в ожидаемом формате и содержат только ожидаемые значения, вам нужно беспокоиться о сохранении этих данных в хранилище.

Каждый механизм хранения данных имеет особый способ убедиться, что данные правильно экранированы и закодированы. Если вы строите SQL, то принятый способ передачи данных в запросах - через подготовленные операторы с заполнителями .

Одним из лучших способов работы с большинством баз данных SQL в PHP является расширение PDO . Он следует общему шаблону подготовки оператора , связывая переменные с оператором , затем отправляя оператор и переменные на сервер . Если вы раньше не работали с PDO, вот хороший учебник, ориентированный на MySQL .

Некоторые базы данных SQL имеют свои собственные специальные расширения в PHP, включая SQL Server , PostgreSQL и SQLite 3 . Каждое из этих расширений имеет подготовленную поддержку операторов, которая работает так же, как и PDO. Иногда вам может понадобиться использовать эти расширения вместо PDO для поддержки нестандартных функций или поведения.

MySQL также имеет свои собственные расширения PHP. На самом деле два из них. Вы хотите использовать только тот, который называется mysqli . Старое расширение «mysql» устарело и не является безопасным или вменяемым для использования в современную эпоху.

Я лично не фанат mysqli. Способ, которым оно выполняет привязку переменных к подготовленным операторам, негибок и может быть неудобным для использования. Если есть сомнения, используйте вместо этого PDO.

Если вы не используете базу данных SQL для хранения своих данных, проверьте документацию для интерфейса базы данных, который вы используете, чтобы определить, как безопасно передавать данные через нее.

По возможности, убедитесь, что ваша база данных хранит ваши данные в соответствующем формате. Хранить номера в числовых полях. Храните даты в полях даты. Храните деньги в десятичном поле, а не в поле с плавающей запятой. Просмотрите документацию, предоставленную вашей базой данных о том, как правильно хранить различные типы данных.

Экранирование данных для презентации

Каждый раз, когда вы показываете данные пользователям, вы должны убедиться, что данные безопасно экранированы, если только вы не знаете, что их нельзя экранировать.

При испускании HTML вы почти всегда должны передавать любые данные, которые были изначально предоставлены пользователем htmlspecialchars. Фактически, единственный раз, когда вы не должны этого делать, это когда вы знаете, что пользователь предоставил HTML, и что вы знаете, что он уже был подвергнут санитарной обработке с использованием белого списка.

Иногда вам нужно сгенерировать Javascript, используя PHP. Javascript не имеет тех же правил экранирования, что и HTML! Безопасный способ предоставления пользовательских значений в Javascript через PHP - через json_encode.

И больше

Есть еще много нюансов для проверки данных.

Например, кодировка набора символов может быть огромной ловушкой . Ваша заявка должна следовать правилам, изложенным в « UTF-8 на всем протяжении ». Существуют гипотетические атаки, которые могут возникнуть, когда вы обрабатываете строковые данные как неправильный набор символов.

Ранее я упоминал инструменты отладки браузера. Эти инструменты также могут быть использованы для манипулирования данными cookie. Куки должны рассматриваться как ненадежный пользовательский ввод .

Проверка и удаление данных - это только один аспект безопасности веб-приложения. Вам следует ознакомиться с методологиями атак веб-приложений, чтобы вы могли создать защиту против них.

Чарльз
источник
И при указании этого убедитесь, что он находится в списке поддерживаемых кодировок.
Чарльз
3
И вообще не используйте htmlentities, замените его на htmlspecialchars, чтобы заменить просто <>, а не каждый символ своей сущностью
Ваш здравый смысл
6
Только не звоните htmlspecialcharsдважды, потому что он говорит об этом в части «Когда пользователи отправляют данные» и в части «При отображении данных».
Savageman
2
Upvoted. Самый полезный ответ, который я читал во многих вопросах и ответах относительно SQL-инъекций.
akinuri
Абсолютно качественный ответ с множеством объяснений и ссылок для будущих пользователей, чтобы узнать больше вариантов. Получил от меня тоже ...
Джеймс Уокер
32

Наиболее эффективной санацией для предотвращения внедрения SQL является параметризация с использованием PDO. Используя параметризованные запросы, запрос отделяется от данных, что устраняет угрозу внедрения SQL первого порядка.

С точки зрения удаления HTML, strip_tagsвероятно, лучшая идея для удаления HTML, так как он просто удалит все. htmlentitiesделает то, на что это похоже, так что это тоже работает. Если вам нужно разобрать, какой HTML разрешить (то есть вы хотите разрешить некоторые теги), вы должны использовать уже существующий зрелый синтаксический анализатор, такой как HTML Purifier.

Дерек Х
источник
2
Оу, чувак, я написал эту гигантскую стену текста только потому, что я не видел, чтобы кто-то упоминал HTML-очиститель, и здесь ты побил меня примерно на 40 минут. ;)
Чарльз
3
Разве вы не должны только раздеть HTML на выходе? ИМО, вы никогда не должны изменять входные данные - вы никогда не знаете, когда вам это нужно
Джо Филлипс
11

Ввод базы данных - как предотвратить SQL-инъекцию

  1. Убедитесь, что данные типа integer, например, действительны, убедившись, что они на самом деле являются целыми числами
    • В случае не-строк вы должны убедиться, что данные на самом деле имеют правильный тип
    • В случае строк вы должны убедиться, что строка в запросе заключена в кавычки (очевидно, иначе это не сработает)
  2. Введите значение в базу данных, избегая внедрения SQL (mysql_real_escape_string или параметризованные запросы)
  3. При извлечении значения из базы данных избегайте атак межсайтового скриптинга, следя за тем, чтобы HTML-код не мог быть введен на страницу (htmlspecialchars)

Вы должны избежать пользовательского ввода перед вставкой или обновлением его в базу данных. Вот более старый способ сделать это. Вы хотели бы использовать параметризованные запросы сейчас (вероятно, из класса PDO).

$mysql['username'] = mysql_real_escape_string($clean['username']);
$sql = "SELECT * FROM userlist WHERE username = '{$mysql['username']}'";
$result = mysql_query($sql);

Вывод из базы данных - как предотвратить XSS (межсайтовый скриптинг)

Используйте htmlspecialchars()только при выводе данных из базы данных. То же самое относится и к очистителю HTML. Пример:

$html['username'] = htmlspecialchars($clean['username'])

И наконец ... то, что вы просили

Я должен отметить, что если вы используете объекты PDO с параметризованными запросами (правильный способ сделать это), то на самом деле нет простого способа добиться этого легко. Но если вы используете старый способ «mysql», то это то, что вам нужно.

function filterThis($string) {
    return mysql_real_escape_string($string);
}
Джо Филлипс
источник
5

Мои 5 центов.

Никто здесь не понимает, как mysql_real_escape_stringработает. Эта функция ничего не фильтрует и не «дезинфицирует».
Таким образом, вы не можете использовать эту функцию в качестве универсального фильтра, который избавит вас от инъекций.
Вы можете использовать его только тогда, когда понимаете, как это работает и где это применимо.

У меня есть ответ на очень похожий вопрос, который я уже написал: в PHP при отправке строк в базу данных я должен заботиться о недопустимых символах с помощью htmlspecialchars () или использовать регулярное выражение?
Пожалуйста, нажмите для полного объяснения безопасности базы данных.

Что касается htmlentities - Чарльз прав, говоря вам, чтобы разделить эти функции.
Представьте, что вы собираетесь вставить данные, сгенерированные администратором, которому разрешено размещать HTML. ваша функция испортит это.

Хотя я бы посоветовал против ненависти. Эта функция давно устарела. Если вы хотите заменить только <, >и "символы в целях безопасности HTML - использовать функцию , которая была разработана специально для этой цели - An htmlspecialchars () один.

Ваш здравый смысл
источник
1
mysql_real_escape_stringэкранирует необходимые символы внутри строки. Он не строго фильтрует и не дезинфицирует, но заключает в кавычки строку (и все так делают, я почти никогда не видел вопроса об этом). Так что ничего не очищается, когда мы пишем SQL? Конечно нет. Что мешает внедрению SQL - это использование mysql_real_escape_string. Также в кавычках, но это делают все, и если вы проверите, что вы делаете, вы получите ошибку синтаксиса SQL с этим упущением. С действительно опасной частью справляются mysql_real_escape_string.
Savageman
@ Savageman извини приятель, ты ничего не понимаешь. Вы не понимаете, как работает mysql_real_escape_string. Эти "необходимые персонажи" являются цитатами. Ни эта функция, ни цитаты сами по себе ничего не дезинфицируют. Эти 2 вещи работают только вместе . Создание строки запроса просто синтаксически правильно, а не «безопасно от внедрения». И какую синтаксическую ошибку я бы получил за раз WHERE id = 1? ;)
Твой здравый смысл
Попробуйте WHERE my_field = two words(без кавычек) получить синтаксическую ошибку. Ваш пример плох, потому что он не нуждается ни в кавычках, ни в экранировании, просто в числовой проверке. Также я не сказал, что цитаты были бесполезны. Я сказал, что все используют их, так что это не источник проблем, связанных с SQL-инъекцией.
Savageman
1
@ Savageman так, что я сказал: Вы можете использовать его только тогда, когда вы понимаете, как это работает и где это применимо. Вы только что признали, что mysql_real_escape_string не везде применима. Что касается everyone use themвы можете проверить коды здесь на SO. Многие люди не используют кавычки с числами. Пойди разберись. Пожалуйста, имейте в виду, что я не обсуждаю здесь то, что вы сказали, а что нет. Я просто объясняю основные правила безопасности баз данных. Тебе лучше учиться, а не пусто спорить. Никто не упомянул здесь цитаты или кастинг, но m_r_e_s только как будто это волшебство. О чем я говорю
Ваш здравый смысл
1
один вверх, а также @Charles. Как новичок, взаимодействие с базой данных ... обеспечение безопасности для ввода и отображения. Специальные символы, проблемы с внедрением, были очень крутой кривой обучения. Чтение твоего поста и его (а также твоих ответов на другие вопросы по PHP) мне очень помогло. Спасибо за твой вклад.
Джеймс Уокер,
2

Все, что вам нужно для вставки базы данных mysql_real_escape_string(или использовать параметризованные запросы). Как правило, вы не хотите изменять данные перед их сохранением, что произойдет, если вы используете htmlentities. Это может привести к искаженному беспорядку позже, когда вы htmlentitiesснова прогоните его, чтобы отобразить где-то на веб-странице.

Используйте, htmlentitiesкогда вы отображаете данные на веб-странице где-то.

В некотором роде, если вы отправляете отправленные данные куда-то в электронном письме, например, с помощью контактной формы, обязательно уберите новые строки из любых данных, которые будут использоваться в заголовке (например, От: имя и адрес электронной почты, тема и т. Д.). )

$input = preg_replace('/\s+/', ' ', $input);

Если вы этого не сделаете, то это всего лишь вопрос времени, когда спам-боты найдут вашу форму и злоупотребят ею, я выучил нелегкий путь.

обкрадывать
источник
2

Это зависит от типа данных, которые вы используете. Лучше всего использовать его, mysqli_real_escape_stringно, например, вы знаете, что HTML-содержимого не будет, использование strip_tags добавит дополнительную безопасность.

Вы также можете удалить символы, которые, как вы знаете, запрещены.

Аарон Харун
источник
1

Я всегда рекомендую использовать небольшой пакет проверки, такой как GUMP: https://github.com/Wixel/GUMP

Создайте все свои основные функции вокруг библиотеки, как это, и почти невозможно забыть санитарию. «mysql_real_escape_string» - не лучшая альтернатива для хорошей фильтрации (как объяснил «Ваш здравый смысл») - и если вы забудете использовать ее только один раз, вся ваша система будет атакована с помощью инъекций и других неприятных атак.

Саймон Шнайдер
источник
1

Для всех тех, кто здесь говорит и полагается на mysql_real_escape_string, вы должны заметить, что эта функция устарела в PHP5 и больше не существует в PHP7.

IMHO, лучший способ выполнить эту задачу - использовать параметризованные запросы с помощью PDO для взаимодействия с базой данных. Проверьте это: https://phpdelusion.net/pdo_examples/select

Всегда используйте фильтры для обработки ввода пользователя. Смотрите http://php.net/manual/es/function.filter-input.php

Kuntur
источник
Это на самом деле не отвечает на вопрос. Попробуйте изменить свой ответ, чтобы включить решение.
Крис
Надеюсь, вам понравится!
Кунтур
Я делаю. Хороший ответ!
Крис
Предлагаю отметить, что в PHP 7 mysqli_real_escape_string()доступен.
Крис
Привет Крис, решения, представленные здесь, ссылаются на mysql_real_escape_string, я заметил, что с этого момента читал, что его больше нет в PHP7, и предлагал альтернативу с использованием PDO (и фильтров), а не mysqli. Не стесняйтесь добавлять примечание, объясняющее решение, используя то, что вы предлагаете. С уважением
Кунтур
0

Вы используете mysql_real_escape_string () в коде, подобном следующему.

$query = sprintf("SELECT * FROM users WHERE user='%s' AND password='%s'",
  mysql_real_escape_string($user),
  mysql_real_escape_string($password)
);

Как сказано в документации, его целью является экранирование специальных символов в строке, передаваемой в качестве аргумента, с учетом текущего набора символов соединения, чтобы можно было безопасно разместить его в mysql_query () . Документация также добавляет:

Если нужно вставить двоичные данные, необходимо использовать эту функцию.

htmlentities () используется для преобразования некоторых символов в сущности, когда вы выводите строку в HTML-контенте.

kiamlaluno
источник
0

Это один из способов, которыми я сейчас занимаюсь,

  1. Имплантируйте csrf и солевой токен собеседника вместе с запросом, который будет сделан пользователем, и проверьте их все вместе из запроса. Обратитесь сюда
  2. не слишком полагаться на куки-файлы на стороне клиента и практиковаться в использовании сеансов на стороне сервера
  3. при любом анализе данных убедитесь, что принимаются только тип данных и метод передачи (например, POST и GET)
  4. Убедитесь, что вы используете SSL для вашего webApp / App
  5. Не забудьте также сгенерировать запрос сеанса на временной основе, чтобы преднамеренно ограничить запрос на спам.
  6. Когда данные анализируются на сервере, убедитесь, что запрос должен быть выполнен в требуемом методе данных, таком как json, html и т. Д., А затем продолжите
  7. экранировать все недопустимые атрибуты из ввода, используя escape-тип ... такой как realescapestring.
  8. после этого проверьте только чистый формат типа данных, который вы хотите от пользователя.
    Пример:
    - Электронная почта: проверить, является ли ввод в правильном формате электронной почты
    - текст / строка: Проверить, что только ввод - только текстовый формат (строка)
    - номер: проверить, разрешен ли только числовой формат.
    - и т. д. Pelase ссылается на библиотеку проверки входных данных php с портала php
    - После проверки, пожалуйста, продолжайте использовать подготовленный оператор SQL / PDO.
    - После того, как это сделано, убедитесь, что выход и разрыв соединения
    - Не забудьте очистить выходное значение после того, как сделано.

Вот и все, что я считаю достаточно для базового сек. Это должно предотвратить все основные атаки хакеров.

Для обеспечения безопасности на стороне сервера вы можете установить в своем apache / htaccess ограничение доступа и предотвращение роботов, а также предотвращение маршрутизации. Есть много дел для обеспечения безопасности на стороне сервера, помимо безопасности системы на стороне сервера.

Вы можете узнать и получить копию sec с уровня htaccess apache sec (общие примеры)

Ахмад Ануар
источник
0
function sanitize($string,$dbmin,$dbmax){
$string = preg_replace('#[^a-z0-9]#i', '', $string); //useful for strict cleanse, alphanumeric here
$string = mysqli_real_escape_string($con, $string); //get ready for db
if(strlen($string) > $dbmax || strlen($string) < $dbmin){
    echo "reject_this"; exit();
    }
return $string;
}
stkmedia
источник
0

как насчет этого

$string = htmlspecialchars(strip_tags($_POST['example']));

или это

$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
jerryurenaa
источник