Каковы лучшие функции очистки ввода PHP?
Я пытаюсь придумать функцию, через которую я могу передать все свои строки для очистки. Так что полученная строка будет безопасна для вставки в базу данных. Но существует так много фильтрующих функций, что я не уверен, какие из них мне нужно использовать.
Пожалуйста, помогите мне заполнить пробелы:
function filterThis($string) {
$string = mysql_real_escape_string($string);
$string = htmlentities($string);
etc...
return $string;
}
15 ответов
Стоп!
Вы делаете ошибку здесь. О, нет, вы выбрали правильные функции 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. Куки должны рассматриваться как ненадежный пользовательский ввод.
Проверка и удаление данных - это только один аспект безопасности веб-приложения. Вам следует ознакомиться с методологиями атак веб-приложений, чтобы вы могли создать защиту против них.
Наиболее эффективной санацией для предотвращения внедрения SQL является параметризация с использованием PDO
, Используя параметризованные запросы, запрос отделяется от данных, что устраняет угрозу внедрения SQL первого порядка.
С точки зрения удаления HTML, strip_tags
вероятно, лучшая идея для удаления HTML, так как он просто удалит все. htmlentities
делает то, на что это похоже, так что это тоже работает. Если вам нужно разобрать, какой HTML разрешить (то есть вы хотите разрешить некоторые теги), вы должны использовать уже существующий зрелый синтаксический анализатор, такой как HTML Purifier.
Ввод базы данных - как предотвратить SQL-инъекцию
- Убедитесь, что данные типа integer, например, действительны, убедившись, что они на самом деле являются целыми числами
- В случае не-строк вы должны убедиться, что данные на самом деле имеют правильный тип
- В случае строк необходимо убедиться, что строка в запросе заключена в кавычки (очевидно, иначе это не сработает)
- Введите значение в базу данных, избегая внедрения SQL (mysql_real_escape_string или параметризованные запросы)
- При получении значения из базы данных обязательно избегайте атак межсайтового скриптинга, следя за тем, чтобы 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'])
- Купите эту книгу, если сможете: Essential PHP Security
- Также прочитайте эту статью: Почему mysql_real_escape_string важна и некоторые ошибки
И наконец... то, что вы просили
Я должен отметить, что если вы используете объекты PDO с параметризованными запросами (правильный способ сделать это), то на самом деле нет простого способа добиться этого легко. Но если вы используете старый способ "mysql", то это то, что вам нужно.
function filterThis($string) {
return mysql_real_escape_string($string);
}
Мои 5 центов.
Никто здесь не понимает, как mysql_real_escape_string
работает. Эта функция ничего не фильтрует и не "дезинфицирует".
Таким образом, вы не можете использовать эту функцию в качестве универсального фильтра, который избавит вас от инъекций.
Вы можете использовать его только тогда, когда понимаете, как это работает и где это применимо.
У меня есть ответ на очень похожий вопрос, который я уже писал: в PHP при отправке строк в базу данных я должен заботиться о недопустимых символах с помощью htmlspecialchars() или использовать регулярное выражение?
Пожалуйста, нажмите для полного объяснения безопасности базы данных.
Что касается htmlentities - Чарльз прав, говоря вам, чтобы разделить эти функции.
Представьте, что вы собираетесь вставить данные, сгенерированные администратором, которому разрешено размещать HTML. ваша функция испортит это.
Хотя я бы посоветовал против htmlentities. Эта функция давно устарела. Если вы хотите заменить только <
, >
, а также "
символы для безопасности HTML - используйте функцию, специально разработанную для этой цели - функцию htmlspecialchars().
Как насчет этого
$string = htmlspecialchars(strip_tags($_POST['example']));
или это
$string = htmlentities($_POST['example'], ENT_QUOTES, 'UTF-8');
1) Используя нативные фильтры php, я получил следующий результат:
(исходный скрипт: https://runforgithub.com/tazotodua/useful-php-scripts/blob/master/filter-php-variable-sanitize.php)
Это зависит от типа данных, которые вы используете. В общем случае лучше всего использовать mysqli_real_escape_string
но, например, вы знаете, что HTML-контента не будет, использование strip_tags добавит дополнительную безопасность.
Вы также можете удалить символы, которые, как вы знаете, запрещены.
Для вставки базы данных все, что вам нужно, это mysql_real_escape_string
(или используйте параметризованные запросы). Как правило, вы не хотите изменять данные перед их сохранением, что произойдет, если вы использовали htmlentities
, Это может привести к искаженному беспорядку позже, когда вы прогоните его htmlentities
снова, чтобы отобразить его где-нибудь на веб-странице.
использование htmlentities
когда вы отображаете данные на веб-странице где-то.
В некотором роде, если вы отправляете отправленные данные куда-то в электронном письме, например, с помощью формы контакта, обязательно удалите новые строки из любых данных, которые будут использоваться в заголовке (например, От: имя и адрес электронной почты, тема и т. Д.).)
$input = preg_replace('/\s+/', ' ', $input);
Если вы не сделаете этого, то это всего лишь вопрос времени, когда спам-боты найдут вашу форму и злоупотребят ею, я выучил нелегкий путь.
Это один из способов, которым я сейчас занимаюсь,
- Внедрите csrf и salt tempt токен вместе с запросом, который должен быть сделан пользователем, и подтвердите их все вместе из запроса. Обратитесь сюда
- не слишком полагаться на файлы cookie на стороне клиента и обязательно практиковаться в использовании сеансов на стороне сервера
- при любом анализе данных убедитесь, что принимаете только тип данных и метод передачи (например, POST и GET)
- Обязательно используйте SSL для вашего веб-приложения / приложения
- Не забудьте также создать запрос сеанса с временной базой, чтобы намеренно ограничить спам-запросы.
- Когда данные анализируются на сервере, убедитесь, что запрос должен быть выполнен в том методе данных, который вы хотите, например json, html и т. Д., А затем продолжите
- экранировать все недопустимые атрибуты из ввода, используя escape-тип... например, realescapestring.
- после этого проверьте только чистый формат данных, которые вы хотите получить от пользователя.
Пример:
- Электронная почта: проверьте, находится ли ввод в допустимом формате электронной почты
- текст / строка: проверьте, что ввод только текстовый формат (строка)
- число: проверьте, разрешен ли только числовой формат.
- и т. д. Обратитесь к библиотеке проверки ввода php с портала php
- После проверки продолжайте, используя подготовленный оператор SQL / PDO.
- После этого не забудьте выйти и разорвать соединение
- Не забудьте очистить выходное значение после завершения.
Этого, на мой взгляд, достаточно для базового сек. Это должно предотвратить все крупные атаки хакеров.
Для безопасности на стороне сервера вы можете настроить в своем apache/htaccess ограничение доступа и предотвращение роботов, а также предотвращение маршрутизации. Для обеспечения безопасности на стороне сервера есть еще много чего, кроме sec системы на стороне сервера.
Вы можете узнать и получить копию sec с уровня htaccess apache sec (общие rpactices)
Как вы упомянули, вы используете очистку SQL, я бы рекомендовал использовать PDO и подготовленные операторы. Это значительно улучшит вашу защиту, но, пожалуйста, проведите дополнительные исследования по очистке любого пользовательского ввода, переданного в ваш SQL.
Чтобы использовать подготовленный оператор, см. следующий пример. У вас есть sql с ? для значений, затем свяжите их с 3 строками 'sss', называемыми именем, фамилией и адресом электронной почты
// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);
Для всех тех, кто здесь говорит и полагается на mysql_real_escape_string, вы должны заметить, что эта функция устарела в PHP5 и больше не существует в PHP7.
IMHO, лучший способ выполнить эту задачу - использовать параметризованные запросы с помощью PDO для взаимодействия с базой данных. Проверьте это: https://phpdelusions.net/pdo_examples/select
Всегда используйте фильтры для обработки ввода пользователя. Смотрите http://php.net/manual/es/function.filter-input.php
Дезинфицирующие средства
Sanitize - это функция для проверки (и удаления) вредоносных данных, вводимых пользователем, которые могут нанести вред программному обеспечению. Очистка пользовательского ввода - самый безопасный метод проверки пользовательского ввода, позволяющий исключить все, что не находится в белом списке.
Поддержка PHP
5.4.0 - 5.4.45, 5.5.0 - 5.5.38, 5.6.0 - 5.6.40, 7.0.0 - 7.0.33, 7.1.0 - 7.1.33, 7.2.0 - 7.2.34, 7.3.0 - 7.3.27, 7.4.0 - 7.4.15, 8.0.0 - 8.0.2
<?php
require_once("path/to/Sanitizers.php");
use Sanitizers\Sanitizers\Sanitizer;
\\ passing `true` in Sanitizer class enables exceptions
$sanitize = new Sanitizer(true);
try {
echo $sanitize->Username($_GET['username']);
} catch (Exception $e) {
echo "Could not Sanitize user input."
var_dump($e);
}
?>
См. Проект Sanitizers GitHub .
Вы используете 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-контенте.
Я всегда рекомендую использовать небольшой пакет проверки, такой как GUMP: https://github.com/Wixel/GUMP
Создайте все свои основные функции вокруг библиотеки, как это, и почти невозможно забыть санитарию. "mysql_real_escape_string" - не лучшая альтернатива для хорошей фильтрации (как объяснил "Ваш здравый смысл") - и если вы забудете использовать его только один раз, вся ваша система будет атакована с помощью инъекций и других неприятных атак.
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;
}