Сайт компьютерных навыков

Уроки по PHP: типы переменных, экранирование, спецсимволы и синтаксис heredoc в PHP. Экранирование символов Что возвращает нас к

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

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

Каждому из этого контекста назначено несколько символов со специальным функционалом.

Если вы хотите передать символ буквально, не используя его специальную функцию (локальную для контекста), то в этом случае вы должны экранировать его для следующего контекста... который может нуждаться в некоторых других escape-символах, которые могут потребоваться дополнительно сбежал в предыдущем контексте (ах). Кроме того, могут быть такие вещи, как кодировка символов (наиболее коварным является utf-8, потому что он выглядит как ASCII для общих символов, но может дополнительно интерпретироваться даже терминалом в зависимости от его настроек, поэтому он может вести себя по-другому, чем атрибут кодирования HTML/XML, это необходимо для правильного понимания процесса.

Например, регулярное выражение в командной строке, начинающееся с perl -npe , должно быть передано в набор системных вызовов exec, соединяющихся как канал, который обрабатывает файл, каждый из этих системных вызовов exec просто имеет список аргументов, которые были разделены (не экранированные) пробелы и, возможно, каналы (|) и перенаправление (> N> N> & M), скобки, интерактивное расширение * и? , $(()) ... (все это специальные символы, используемые * sh, которые могут показаться мешающими символу регулярного выражения в следующем контексте, но они оцениваются по порядку: перед командной строкой. командная строка читается программой как bash/sh/csh/tcsh/zsh, по существу внутри двойной кавычки или одинарной кавычки, экранирование проще, но нет необходимости заключать в кавычки строку в командной строке, потому что в основном пробел должен начинаться с префикса с обратной косой чертой и кавычкой нет необходимости, оставляя доступной функциональность раскрытия для символов * и?, но это анализирует такой же контекст, как и в кавычке. Затем при оценке командной строки регулярное выражение, полученное в памяти (не так, как записано в командной строке) получает ту же обработку, что и в исходном файле. Для регулярного выражения в квадратных скобках есть контекст набора символов , регулярное выражение perl может быть заключено в большой набор не альфа-числовых символов (например, m//или m:/лучше/для/путь:...).

У вас есть больше деталей о символах в другом ответе, которые очень специфичны для конечного контекста регулярного выражения. Как я уже отмечал, вы упоминаете, что вы обнаруживаете, что regexp сбрасывается с попытками, что, вероятно, из-за того, что другой контекст имеет другой набор символов, который запутал вашу память о попытках (часто обратный слеш - это символ, используемый в этом другом контексте для экранирования литерального символа вместо его функции.).

3.1 Экранирование спецсимволов

Прежде чем передавать значения переменных формы в SQL-запросы, необходимо специальным образом экранировать в них некоторые символы (в частности, апостроф), например, поставить перед ними обратный слэш. Для вставки предназначена функция:

mysql_escape_string()

string mysql_escape_string(string $str)

Функция похожа на другую функцию addslashes(), однако она добавляет слэши перед более полным набором специальных символов. Практика показывает, что для текстовых данных можно применять и функцию addslashes() вместо mysql_escape_string(). Во многих скриптах так и делается.

По стандарту MySQL экранированию подвергаются символы, которые в РНР записываются так: "\х00", "\n", "\г", "\\", """, "" и "\х1А".

В это число входит символ с нулевым ASCII-кодом, а поэтому mysql_escape_string() допустимо применять не только для текстовых, но также и для бинарных данных. Можно, например, считать в переменную GIF-изображение (функция file_get_contents ()), а затем вставить его в базу данных, предварительно проэкранировав все спецсимволы. При извлечении картинка окажется в том же виде, в котором она была изначально.

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

С использованием mysql_escape_string()код предыдущего запроса выглядит так:

"DELETE FROM table WHERE name="".mysql_escape_string($name).""");

Это длинно, неуклюже и некрасиво.


3.2 Шаблоны запросов и placeholders

Рассмотрим другое решение.

Вместо явного экранирования и вставки переменных в запрос на их место помещают специальные маркеры (placeholders, "хранители места"), обычно выглядящие как?.

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

С использованием гипотетической функции mysql_qwo, код которой будет представлен ниже, предыдущий запрос может быть переписан так:

mysql_qw ("DELETE FROM table WHERE name=?", $name);

Запрос стал короче и лучше защищен: теперь мы уже при написании кода не сможем случайно пропустить вызов функции mysql_escape_string() и, таким образом, попасться на уловку хакера. Все преобразования происходят автоматически, внутри функции.

В листинге lib_mysql_qw.php содержится простейшая реализация функции mysql_qw() (qw - от англ. query wrapper, "обертка для запроса").

Имеется также библиотека lib/Placeholder.php, обеспечивающая значительно более мощную поддержку языка placeholders: http://dklab.ru/chicken/30.html.

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

Листинг lib_mysql_qw.php


Если ваши пользователи будут хорошими и добрыми, то они будут размещать цитаты старых философов, а сообщения будут иметь примерно следующий вид:

Posted by Plato on January 2, 15:31

I am said to have said "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."


Если пользователи будут умниками, то они, наверное, будут говорить о математике, и сообщения будут такие:

Posted by Pascal on November 23, 04:12

Basic math tells us that if x < n and y > n, x cannot be larger than y.


Хм... Опять эти осквернители наших скобок. Ну, с технической точки зрения они могут быть неоднозначными, но браузер простит нам это, правда?


Хорошо, СТОП, что за черт? Какой-то шутник ввел javascript теги на ваш форум? Любой, кто смотрит на это сообщение на вашем сайте, сейчас загружает и выполняет скрипты в контексте вашего сайта, которые могут сделать не весть что. А это не есть хорошо.

Не следует понимать буквально В вышеупомянутых случаях, мы хотим каким-то образом сообщить нашей БД или браузеру, что это просто текст, ты с ним ничего не делай! Другими словами, мы хотим "удалить" особые значения всех специальных символов и ключевых слов из любой информации, предоставленной пользователем, ибо мы ему не доверяем. Что же делать?

Что? Что говоришь, мальчишка? Ах, ты говоришь, "экранирование"? И ты абсолютно прав, возьми печеньку!
Если мы применим экранирование к пользовательским данным до объединения их с запросом, то проблема решена. Для наших запросов к БД это будет что-то вроде:
$name = $_POST["name"]; $name = mysql_real_escape_string($name); $query = "SELECT phone_number FROM users WHERE name = "$name""; $result = mysql_query($query);
Просто одна строка кода, но теперь больше никто не может "взломать" нашу базу данных. Давайте снова посмотрим как будут выглядеть SQL-запросы, в зависимости от ввода пользователя:
Alex
SELECT phone_number FROM users WHERE name = "Alex"
Mc"Donalds
SELECT phone_number FROM users WHERE name = "Mc\"Donalds"
Joe"; DROP TABLE users; --
SELECT phone_number FROM users WHERE name = "Joe\"; DROP TABLE users; --"
mysql_real_escape_string без разбора помещает косую черту перед всем, у чего может быть какое-то особое значение.


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

Posted by JackTR on July 18, 12:56


Обратите внимание, что значения, полученные от пользователи, на самом деле не "повреждены". Любой браузер парсит этот как HTML и выведет на экран все в правильной форме.

Что возвращает нас к... Все вышеупомянутое демонстрирует проблему, характерную для многих систем: текст в тексте должно быть подвергнут экранированию, если предполагается, что он не должен иметь специальных символов. Помещая текстовые значения в SQL, они должны быть экранированы по правилам SQL. Помещая текстовые значения в HTML, они должны быть экранированы по правилам HTML. Помещая текстовые значения в (название технологии), они должны быть экранированы по правилам (название технологии). Вот и все.Для полноты картины Есть, конечно, другие способы борьбы с пользовательским вводов, который должен или не должен содержать специальные символы:
  • Validation
    Вы можете проверить, соответствует ли пользовательский ввод некоторой заданной спецификации. Если Вы требуете ввода числа, а пользователь вводит нечто другое, программа должна сообщить ему об этом и отменить ввод. Если все это правильно организовать, то нет никакого риска схватить "DROP TABLE users" там, где, предполагалось, пользователь введет "42". Это не очень практично, для избегания HTML/SQL-инъекций, т.к. часто требуется принять текст свободного формата, который может содержать "подковырки". Обычно валидацию используют в дополнение к другим мерам.
  • Sanitization
    Вы можете так же "втихую" удалить любые символы, которые считаете опасными. Например, просто удалить что-либо похожее на HTML-тег, что избежать добавления на ваш форум. Проблема в том, что вы можете удалить вполне законные части текста.
    Prepared SQL statements
    Есть специальные функции, делающие то, чего мы и добивались: заставляют БД понять различия между самим SQL-запросом и информацией, предоставленной пользователями. В РНР они выглядят примерно так:
    $stmt = $pdo->prepare("SELECT phone_number FROM users WHERE name = ?"); $stmt->execute($_POST["name"]);
    При этом отправка происходит в два этапа, четко разграничивая запрос и переменные. БД имеет возможность сначала понять структуру запроса, а потом заполнить его значениями.

  • В реальном мире, все это используется вместе для различных ступеней защиты. Вы должны всегда использовать проверку допустимости (валидацию), чтобы быть уверенным, что пользователь вводит корректные данные. Затем вы можете (но не обязаны) сканировать введенные данные. Если пользователь явно пытается "втюхать" вам какой-то скрипт, вы можете просто удалить его. Затем, вы всегда, всегда должны экранировать пользовательские данные прежде, чем поместить их в SQL-запрос (это же касается и HTML).

Похожие публикации