function sanitizeString($var) { $var = stripslashes($var); $var = htmlentities($var); $var = strip_tags($var); return $var; } function sanitizeMySQL($var) { $var = mysql_real_escape_string($var); $var = sanitizeString($var); return $var; }
Я получил эти две функции из книги, и автор говорит, что, используя эти два, я могу быть дополнительно безопасным против XSS (первая функция) и SQL-инъекций (2-й func). Все это необходимо?
Также для дезинфекции я использую подготовленные заявления для предотвращения инъекций sql.
Я бы использовал его так:
$variable = sanitizeString($_POST['user_input']); $variable = sanitizeMySQL($_POST['user_input']);
EDIT: избавиться от strip_tags для первой функции, потому что она ничего не делает. Будет ли использование этих двух функций достаточным для предотвращения большинства атак и будет хорошо для публичного сайта?
Это правда, но этот уровень побега может быть неуместным во всех случаях. Что делать, если вы хотите хранить HTML в базе данных?
Лучшая практика диктует, что вместо того, чтобы избегать получения значений, вам следует избегать их при их отображении. Это позволяет вам отображать как HTML из базы данных, так и не-HTML из базы данных, и на самом деле этот тип кода логически принадлежит.
Другим преимуществом дезинфекции исходящего HTML является то, что новый вектор атаки может быть обнаружен, и в этом случае дезинфекция входящего HTML не будет делать ничего для значений, которые уже находятся в базе данных, тогда как исходящая санация будет применяться ретроактивно, не делая ничего специального
Также обратите внимание, что strip_tags
в вашей первой функции, вероятно, не будет иметь никакого эффекта, если все <
и >
стали <
и >
,
Честно говоря, я думаю, что автор этой функции не знает, что такое XSS и SQL-инъекции или что именно делает эта функция.
Просто чтобы назвать две странности:
stripslashes
после того, как mysql_real_escape_string
удаляет слэши, которые были добавлены mysql_real_escape_string
. htmlentities
заменяет символы символов <
и >
, которые используются в strip_tags
, чтобы идентифицировать теги. Кроме того: функции, которые снова защищают XSS, не подходят для защиты повторных SQL-инъекций и наоборот. Потому что у каждого языка и контекста есть свои специальные символы, о которых нужно позаботиться.
Мой совет состоит в том, чтобы узнать, почему и как возможна инъекция кода, и как защитить его. Изучайте языки, с которыми работаете, особенно специальные персонажи и способы их устранения.
Редактировать Вот пример (возможно, странный): представьте, что вы позволяете своим пользователям вводить некоторое значение, которое должно использоваться в качестве сегмента пути в URI, который вы используете в некотором JavaScript-коде, в значении атрибута onclick
. Поэтому языковой контекст выглядит так:
И чтобы сделать его более увлекательным: вы храните это входное значение в базе данных.
Теперь, чтобы правильно сохранить это входное значение в вашей базе данных, вам просто нужно использовать правильную кодировку для контекста, который вы собираетесь вставить в свой язык базы данных (например, SQL); остальное не имеет значения (пока). Поскольку вы хотите вставить его в объявление строки SQL, контекстные специальные символы – это символы, которые позволяют вам изменять этот контекст. Что касается строковых объявлений, эти символы являются (особенно) символами "
, '
и « \
которые должны быть экранированы. Но, как уже было сказано, готовые заявления делают все это для вас, поэтому используйте их.
Теперь, когда у вас есть значение в вашей базе данных, мы хотим вывести их правильно. Здесь мы переходим от самого внутреннего к внешнему контексту и применяем правильную кодировку в каждом контексте:
/
(оставить текущий путь пути) ?
, и #
(оба оставляют контекст пути URI). Для этого мы можем использовать rawurlencode
. "
, '
и « \
. Мы можем использовать json_encode
для этого (если есть). &
, "
, '
и <
. Для этого мы можем использовать htmlspecialchars
. Теперь все вместе:
'… onclick="'.htmlspecialchars('window.open("http://example.com/'.json_encode(rawurlencode($row['user-input'])).'")').'" …'
Теперь, если $row['user-input']
является "bar/baz"
выход:
… onclick="window.open("http://example.com/"%22bar%2Fbaz%22"")" …
Но использование всех этих функций в этих контекстах не является излишним. Поскольку контексты могут иметь похожие специальные символы, они имеют разные escape-последовательности. URI имеет так называемую процентную кодировку, JavaScript имеет escape-последовательности, такие как \"
а HTML имеет ссылки на символы типа "
. И не использование только одной из этих функций позволит разбить контекст.
Вы делаете htmlentities
(который превращает все >
в >
), а затем вызывается strip_tags
который в этот момент не достигнет ничего большего, поскольку нет тегов.
Если вы используете подготовленные операторы и заполнители SQL и никогда не интерполируете вход пользователя непосредственно в ваши строки SQL, вы можете полностью пропустить санацию SQL.
Когда вы используете заполнители, структура оператора SQL ( SELECT foo, bar, baz FROM my_table WHERE id = ?
) Отправляется в механизм базы данных отдельно от значений данных, которые (в конечном итоге) привязаны к заполнителям. Это означает, что, не допуская серьезных ошибок в движке базы данных, абсолютно невозможно понять, что значения данных неверно интерпретируются как инструкции SQL, поэтому это обеспечивает полную защиту от атак SQL-инъекций, не требуя от вас блокировки ваших данных для хранения.
Нет, это не слишком много, это уязвимость.
Этот код полностью уязвим для SQL Injection. Вы делаете mysql_real_escape_string (), а затем выполняете stripslashes (). Таким образом, "
будет становиться \"
после mysql_real_escape_string (), а затем вернуться к "
после stripslashes (). Только для mysql_real_escape_string () лучше всего остановить SQL-инъекцию. Используются такие библиотеки запросов, как PDO и ADODB, а запросы с параметризацией делают это очень легко полностью остановить SQL-инъекции.
Пройдите тест на свой код:
$variable = sanitizeString($_POST['user_input']); $variable = sanitizeMySQL($_POST['user_input']); mysql_query("select * from mysql.user where Host='".$variable."'");
Что если:
$_POST['user_input'] = 1' or 1=1 /*
Исправленный:
mysql_query("select * from mysql.user where Host='".mysql_real_escape_string($variable)."'");
Этот код также уязвим для некоторых типов XSS:
$variable = sanitizeString($_POST['user_input']); $variable = sanitizeMySQL($_POST['user_input']); print("<body background='http://localhost/image.php?".$variable."' >");
Что если:
$_POST['user_input']="' onload=alert(/xss/)";
исправлено:
$variable=htmlspecialchars($variable,ENT_QUOTES); print("<body background='http://localhost/image.php?".$variable."' >");
htmlspeicalchars кодирует одиночные и двойные кавычки, убедитесь, что переменная, которую вы печатаете, также заключена в кавычки, что делает невозможным «вырваться» и выполнить код.
Ну, если вы не хотите изобретать велосипед, вы можете использовать HTMLPurifier . Это позволяет вам точно определять, что вы хотите и чего не хотите, и предотвращает атаки XSS и такие
Я задаюсь вопросом о концепции санитарии. Вы сообщаете Mysql о том, что вы хотите сделать: запустите запрос, частично созданный пользователем веб-сайта. Вы уже строите предложение динамически, используя пользовательский ввод – конкатенацию строк с данными, предоставленными пользователем. Вы получаете то, о чем просите.
Во всяком случае, вот еще несколько методов санитарии …
1) Для числовых значений всегда выполняйте вручную, по крайней мере, где-то до или во время построения строки запроса: «SELECT field1 FROM tblTest WHERE (id =». (Int) $ val. ")";
2) Для дат сначала преобразуйте переменную в временную метку unix. Затем используйте функцию Mysql FROM_UNIXTIME (), чтобы преобразовать ее обратно в дату. "SELECT field1 FROM tblTest WHERE (date_field> = FROM_UNIXTIME (". Strtotime ($ val). ")" ;. Это фактически необходимо иногда в любом случае решать, как Mysql интерпретирует и сохраняет даты, отличные от уровней сценария или ОС.
3) Для коротких и прогнозируемых строк, которые должны соответствовать определенному стандарту (имя пользователя, адрес электронной почты, номер телефона и т. Д.), Вы можете: a) делать подготовленные заявления; или b) регулярное выражение или другое подтверждение данных.
4) Для строк, которые не будут соответствовать никакому реальному стандарту и которые могут иметь или не иметь предварительно или дважды сбежавший и исполняемый код повсюду (текст, заметки, разметка wiki, ссылки и т. Д.), Вы можете: a) сделать подготовленные заявления; или b) хранить и преобразовывать из формы binary / blob – преобразовывать каждый символ в двоичное, шестнадцатеричное или десятичное представление, прежде чем передавать значение в строку запроса и преобразовывать обратно при извлечении. Таким образом, вы можете больше сосредоточиться только на проверке html, когда вы вернете сохраненное значение обратно.