Статьи

Чистим с PHP

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

  • Программа : PHP
  • Версия : 5.2.0+
  • Сложность: Начинающий
  • Расчетное время завершения: 20 минут

Я всегда чувствовал, что писать код на PHP легко и еще проще писать плохой код на PHP. Распространению PHP в сети действительно помогло его использование в популярных пакетах программного обеспечения с открытым исходным кодом, таких как WordPress, Drupal и Magento, а также в крупных веб-приложениях, таких как Facebook; поскольку PHP используется во многих различных случаях (динамические веб-сайты, подробные веб-приложения, платформы для ведения блогов, системы управления контентом и электронная коммерция являются лишь частью множества приложений PHP), возможности грязных данных и небезопасных систем многочисленны. В этом руководстве объясняются некоторые методы получения чистоты с помощью PHP: санация и проверка данных с акцентом на несколько различных форм ввода данных и способы использования фильтров PHP и пользовательских функций.

Санитарная обработка и проверка форм

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

Некоторые не популярные угрозы безопасности данных:

  • Межсайтовый скриптинг (XSS) : форма внедрения кода, при которой скрипт внедряется в веб-сайт с совершенно другого веб-сайта. Это, безусловно, самая распространенная уязвимость в сети. Два недавних, очень ярких примера этой техники — Stalk Daily и Mikeyy Twitter Worms с этого года, которые использовали плохо санированные входы для запуска Javascript через «зараженный» веб-интерфейс Twitter.
  • Внедрение SQL : Вторая наиболее распространенная уязвимость безопасности в сети, это еще одна форма внедрения кода, в которой сценарий используется для участия в одном из многочисленных эксплуатационных действий, включая (но не ограничиваясь этим) разоблачение и / или получение несанкционированного доступа к данным, изменение данные внутри базы данных или просто внедрение кода, который будет отображаться или исполняться на веб-сайте, тем самым нарушая или изменяя веб-сайт.
  • Подделка межсайтовых запросов (CSRF / XSRF) : Менее распространенный эксплойт, который больше полагается на источники данных, такие как файлы cookie браузера и сеанса, чем плохо очищенные и проверенные вводы данных, CSRF (произносится как «морской прибой») может использоваться для выполнения команд на веб-сайт без разрешения пользователя. Один популярный метод CSRF использует неправильно сформированный URI данных изображения или значение src для выполнения сценария вместо отображения изображения.
  • Неправильные данные : на самом деле не «уязвимость безопасности», неправильные данные могут вызвать множество проблем для владельца веб-сайта или администратора базы данных. Часто неправильные данные могут сломать плохо закодированные веб-сайты или привести к сбою автоматизированных систем. Примером этого является возможность изменять целые страницы профиля MySpace, публикуя сообщения с использованием всевозможных HTML / CSS-хакеров (Примечание: это все еще может работать; я долгое время не использовал MySpace).
Exploits of a Mom

Источник изображения: XKCD

Для наших целей мы сосредоточимся только на серверных методах повышения безопасности данных с помощью PHP, поэтому давайте посмотрим, как термины «очистка» и «проверка» определяются по отношению к PHP. Согласно руководству по PHP :

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

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

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

Все установки PHP не созданы равными. Хотя PHP 5.2.0 был введением фильтров, не все установки имеют одинаковый набор фильтров в своем Расширении фильтров. Большинство установок будут иметь все фильтры, которые мы собираемся пройти, но чтобы немного рассказать вам о расширении фильтров, мы выясним, что у вас есть на вашем сервере. В загрузку исходного кода я включил файл с именем getfilters.php, который после установки и запуска на вашем сервере будет отображать все ваши фильтры (как фильтры данных, доступные через функцию filter_var, так и фильтры потоков, доступные через stream_filter_append ).

1
2
3
4
5
6
7
echo «<h1>Data Filters</h1>\n<table>\n<tr>\n»;
echo «<td><strong>Filter ID</strong></td>\n»;
echo «<td><strong>Filter Name</strong></td>\n</tr>»;
foreach(filter_list() as $id =>$filter) {
    echo «<tr><td>$filter</td><td>».filter_id($filter).»</td></tr>\n»;
}
echo «</table>\n»;

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

Фильтры PHP для проверки и очистки активируются путем передачи как минимум двух значений в функцию расширения фильтров PHP filter_var . В качестве примера, давайте использовать Sanitize Filter для целого числа, например, так:

1
2
$value = ‘123abc456def’;
echo filter_var($value, FILTER_SANITIZE_NUMBER_INT);

В этом примере у нас есть переменная $ value, которая передается через функцию расширения фильтров filter_var с использованием фильтра FILTER_SANITIZE_NUMBER_INT . Это приводит к следующему выводу:

1
123456

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

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

FILTER_VALIDATE_BOOLEAN: Проверяет, являются ли данные, передаваемые в фильтр, логическим значением TRUE или FALSE . Если значение не является логическим значением, оно вернет FALSE . Приведенный ниже скрипт будет отображать «TRUE» для данных примера $ value01, но отображать «FALSE» для данных примера $ value02 :

01
02
03
04
05
06
07
08
09
10
11
12
13
$value01 = TRUE;
if(filter_var($value01,FILTER_VALIDATE_BOOLEAN)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}
echo ‘<br /><br />’
$value02 = TRUE;
if(filter_var($value02,FILTER_VALIDATE_BOOLEAN)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}

FILTER_VALIDATE_EMAIL: проверяет, являются ли данные, переданные в фильтр, потенциально действительным адресом электронной почты. Он не проверяет, существует ли адрес электронной почты на самом деле, только то, что формат адреса электронной почты является действительным. Приведенный ниже скрипт будет отображать «ИСТИНА» для данных примера $ value01, но будет отображать «ЛОЖЬ» для данных примера $ value02 (потому что у второго отсутствует необходимая часть @ domain.tld адреса электронной почты):

01
02
03
04
05
06
07
08
09
10
11
12
13
$value01 = ‘[email protected]’;
if(filter_var($value01,FILTER_VALIDATE_EMAIL)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}
echo ‘<br /><br />’
$value02 = ‘nettuts’;
if(filter_var($value02,FILTER_VALIDATE_EMAIL)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}

FILTER_VALIDATE_FLOAT: Проверяет, являются ли данные, переданные в фильтр, допустимым значением с плавающей запятой. Приведенный ниже скрипт будет отображать «TRUE» для данных примера $ value01, но отображать «FALSE» для данных примера $ value02 (потому что разделители запятых не допускаются в значениях с плавающей запятой):

01
02
03
04
05
06
07
08
09
10
11
12
13
$value01 = ‘1.234’;
if(filter_var($value01,FILTER_VALIDATE_FLOAT)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}
echo ‘<br /><br />’
$value02 = ‘1,234’;
if(filter_var($value02,FILTER_VALIDATE_FLOAT)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}

FILTER_VALIDATE_INT: проверяет, являются ли данные, переданные в фильтр, допустимым целочисленным значением. Приведенный ниже скрипт будет отображать «TRUE» для данных примера $ value01, но будет отображать «FALSE» для данных примера $ value02 (поскольку дробные / десятичные числа не являются целыми числами):

01
02
03
04
05
06
07
08
09
10
11
12
13
$value01 = ‘123456’;
if(filter_var($value01,FILTER_VALIDATE_INT)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}
echo ‘<br /><br />’
$value02 = ‘123.456’;
if(filter_var($value02,FILTER_VALIDATE_INT)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}

FILTER_VALIDATE_IP: проверяет, являются ли данные, передаваемые в фильтр, потенциально допустимым IP-адресом. Он не проверяет, будет ли разрешен IP-адрес, просто он соответствует требуемой структуре данных для IP-адресов. Приведенный ниже скрипт будет отображать «TRUE» для данных примера $ value01, но будет отображать «FALSE» для данных примера $ value02 :

01
02
03
04
05
06
07
08
09
10
11
12
13
$value01 = ‘192.168.0.1’;
if(filter_var($value01,FILTER_VALIDATE_IP)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}
echo ‘<br /><br />’
$value02 = ‘1.2.3.4.5.6.7.8.9’;
if(filter_var($value02,FILTER_VALIDATE_IP)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}

FILTER_VALIDATE_URL: проверяет, являются ли данные, переданные в фильтр, потенциально допустимым URL-адресом. Он не проверяет, будет ли разрешен URL-адрес, просто он соответствует требуемой структуре данных для URL-адресов. Приведенный ниже скрипт будет отображать «TRUE» для данных примера $ value01, но будет отображать «FALSE» для данных примера $ value02 :

01
02
03
04
05
06
07
08
09
10
11
12
13
$value01 = ‘http://net.tutsplus.com’;
if(filter_var($value01,FILTER_VALIDATE_URL)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}
echo ‘<br /><br />’
$value02 = ‘nettuts’;
if(filter_var($value02,FILTER_VALIDATE_URL)) {
 echo ‘TRUE’;
} else {
 echo ‘FALSE’;
}

FILTER_SANITIZE_STRING: по умолчанию этот фильтр удаляет все данные из строки, которая недопустима или недопустима в этой строке. Например, это удалит все теги HTML, такие как <script> или <strong> из входной строки:

1
2
$value = ‘<script>alert(‘TROUBLE HERE’);</script>’;
echo filter_var($value, FILTER_SANITIZE_STRING);

Этот скрипт удалит теги и вернет следующее:

1
alert(‘TROUBLE HERE’);

FILTER_SANITIZE_ENCODED: Многие программисты используют функцию PHP urlencode () для обработки своего кодирования URL. Этот фильтр по сути делает то же самое. Например, это закодирует любые пробелы и / или специальные символы из входной строки:

1
2
$value = ‘<script>alert(‘TROUBLE HERE’);</script>’;
echo filter_var($value, FILTER_SANITIZE_ENCODED);

Этот скрипт будет кодировать знаки пунктуации, пробелы и скобки, а затем вернуть следующее:

1
%3Cscript%3Ealert%28%27TROUBLE%20HERE%27%29%3B%3C%2Fscript%3E

FILTER_SANITIZE_SPECIAL_CHARS: этот фильтр по умолчанию будет кодировать специальные символы HTML, такие как кавычки, амперсанды и скобки (в дополнение к символам со значением ASCII меньше 32). Хотя демонстрационная страница не дает полной ясности без просмотра источника (поскольку специальные символы в кодировке HTML будут интерпретироваться и воспроизводиться), если вы посмотрите на исходный код, вы увидите кодировку на работе:

1
2
$value = ‘<script>alert(‘TROUBLE HERE’);</script>’;
echo filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);

Он преобразует специальные символы в их HTML-кодированные я:

1
&#60;script&#62;alert(&#39;TROUBLE HERE&#39;);&#60;/script&#62;

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

1
2
$value = ‘t(e)[email protected]’;
echo filter_var($value, FILTER_SANITIZE_EMAIL);

Он удаляет эти скобки, и вы возвращаете свой красивый адрес электронной почты:

Это отличный фильтр для использования в формах электронной почты совместно с FILTER_VALIDATE_EMAIL для уменьшения ошибок пользователя или предотвращения атак, связанных с XSS (поскольку некоторые прошлые атаки XSS включали возврат исходных данных, предоставленных непосредственно в необработанное поле электронной почты, непосредственно в браузер).

FILTER_SANITIZE_URL: Подобно фильтру для очистки адреса электронной почты, этот фильтр также делает то, что вы думаете. Он удаляет все символы, которые недопустимы в URL (например, некоторые символы UTF-8 и т. Д.). Например, допустим, вы случайно добавили «®» в URL своего веб-сайта (опять же, не спрашивайте, как, представьте, что это сделал велоцираптор):

1
2
$value = ‘http://net.tuts®plus.com’;
echo filter_var($value, FILTER_SANITIZE_URL);

Он удаляет нежелательные «®», и вы получаете ваш красивый URL обратно:

1
http://net.tutsplus.com

FILTER_SANITIZE_NUMBER_INT: этот фильтр похож на FILTER_VALIDATE_INT, но вместо простой проверки, является ли он целым или нет, он фактически удаляет все нецелое число из значения! Действительно, удобно для надоедливых спам-ботов и обманщиков в некоторых формах ввода:

1
2
3
4
5
$value01 = ‘123abc456def’;
echo filter_var($value01, FILTER_SANITIZE_NUMBER_INT);
echo ‘<br />’;
$value02 = ‘1.2.3.4.5.6.7.8.9’;
echo filter_var($value02, FILTER_SANITIZE_NUMBER_INT);

Эти глупые буквы и десятичные дроби выбрасываются прямо:

1
2
123456
123456789

FILTER_SANITIZE_NUMBER_FLOAT: этот фильтр похож на FILTER_VALIDATE_INT, но вместо простой проверки, является ли он целым числом или нет, он фактически удаляет все нецелое число из значения! Действительно, удобно для надоедливых спам-ботов и обманщиков в некоторых формах ввода:

1
2
3
4
5
$value01 = ‘123abc456def’;
echo filter_var($value01, FILTER_SANITIZE_NUMBER_FLOAT);
echo ‘<br />’;
$value02 = ‘1.2.3.4.5.6.7.8.9’;
echo filter_var($value02, FILTER_SANITIZE_NUMBER_FLOAT);

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

1
2
123456
123456789

Но что, если вы хотите сохранить десятичное число, как в следующем примере:

1
2
$value = ‘1.23’;
echo filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT);

Он все равно удалит его и вернет:

1
123

Одна из основных причин, по которой FILTER_SANITIZE_NUMBER_FLOAT и FILTER_SANITIZE_INT являются отдельными фильтрами, заключается в том, чтобы допустить это с помощью специального флага «FILTER_FLAG_ALLOW_FRACTION», который добавляется в качестве третьего значения, передаваемого filter_var :

1
2
$value = ‘1.23’;
echo filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);

Было бы сохранить десятичную и вернуть:

1
1.23

Флаг в этом последнем примере — это лишь одна из многих дополнительных опций, флагов и элементов управления массивами, которые позволяют более детально контролировать, какие типы данных очищаются, определения разделителей, как массивы обрабатываются фильтрами и многое другое. Вы можете узнать больше об этих флагах и других функциях, связанных с фильтрами, в разделе «Расширение фильтров» руководства по PHP.

Теперь мы рассмотрим несколько ключевых дополнительных методов очистки данных с помощью PHP, чтобы предотвратить «грязные данные», наносящие ущерб вашим системам. Они особенно полезны для приложений, все еще работающих на PHP 4, так как все они были доступны, когда он был выпущен.

htmlspecialchars : эта функция PHP преобразует 5 специальных символов в соответствующие им объекты HTML:

  • «&» (амперсанд) становится «& amp;»
  • «» (двойная кавычка) становится «& quot;» когда ENT_NOQUOTES не установлен.
  • » ‘(одинарная кавычка) становится’ & # 039; ‘ только когда установлен ENT_QUOTES.
  • «<» (меньше) становится «& lt;»
  • ‘>’ (больше чем) становится ‘& gt;’

Он используется как любая другая строковая функция PHP:

1
echo htmlspecialchars(‘$string’);

htmlentities : Как и htmlspecialchars, эта функция PHP преобразует символы в соответствующие им объекты HTML. Большая разница в том, что все символы, которые можно конвертировать, будут конвертированы. Это полезный метод обфусцирования адресов электронной почты от некоторых ботов, которые собирают адреса электронной почты, поскольку они не запрограммированы на чтение htmlentities.

Он используется как любая другая строковая функция PHP:

1
echo htmlentities(‘$string’);

mysql_real_escape_string : эта функция MySQL помогает защитить от атак SQL-инъекций. Рекомендуется (или даже обязательно) передавать все данные, отправляемые в запрос MySQL, через эту функцию. Он избегает любых специальных символов, которые могут быть проблематичными и может привести к тому, что маленькие таблицы Бобби уничтожат еще одну базу данных школьников.

1
2
$query = ‘SELECT * FROM table WHERE value=’.mysql_real_escape_string(‘$string’).’
$runQuery = mysql_query($query);

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

1
2
3
4
5
6
7
8
9
function checkZipCode($value) {
    $zipcheck = ‘SELECT COUNT(*) FROM `database`.`zipcodes` WHERE value=»‘.filter_var(mysql_real_escape_string($value),FILTER_SANITIZE_NUMBER_INT).'»‘;
    $count = mysql_query($zipcheck);
    if($count==1) {
        return TRUE;
    } else {
        return FALSE;
    }
}

Могут быть созданы другие пользовательские функции, которые не зависят от баз данных с известными значениями, и могут быть созданы путем проверки магических кавычек, удаления слешей и экранирования для вставки в базу данных:

01
02
03
04
05
06
07
08
09
10
function cleanString($string) {
    $detagged = strip_tags($string);
    if(get_magic_quotes_gpc()) {
        $stripped = stripslashes($detagged);
        $escaped = mysql_real_escape_string($stripped);
    } else {
        $escaped = mysql_real_escape_string($detagged);
    }
    return $escaped;
}

Возможности бесконечны, особенно если вы интегрируете регулярные выражения, но в большинстве случаев расширение PHP Filters должно помочь.

  • Подпишитесь на нас в Твиттере или подпишитесь на ленту Nettuts + RSS для ежедневных новостей и статей о веб-разработке.