METANIT.COM

Безопасность входящих данных php

Большое значение в PHP имеет организация безопасности данных. Рассмотрим несколько простых механизмов, которые могут повысить безопасность нашего веб-сайта.

Но вначале возьмем форму из прошлой темы:

      if(isset($_POST["age"])) < $age = $_POST["age"]; >echo "Имя: $name 
Возраст: $age"; ?>

Форма ввода данных

Имя:

Возраст:

И попробуем ввести в нее некоторые данные. Например, введем в поле для имени ««:

Безопасность в PHP

После отправки данных в html разметку будет внедрен код javascript, который выводит окно с сообщением.

Это относительно простой и безвредный скрипт. Однако внедряемый код может быть более вредоносным. И чтобы избежать подобных проблем с безопасностью, рекомендуется применять функцию htmlentities() . В качестве параметра она принимает значение, которое надо экранировать:

$name = "не определено"; $age = "не определен"; if(isset($_POST["name"])) < $name = htmlentities($_POST["name"]); >if(isset($_POST["age"])) < $age = htmlentities($_POST["age"]); >echo "Имя: $name 
Возраст: $age";

И даже после ввода кода html или javascript все теги будут экранированы, и мы получим следующий вывод:

Функция htmlentities в PHP

Еще одна специальная функция — htmlspecialchars() похожа по действию на htmlentities :

$name = "не определено"; $age = "не определен"; if(isset($_POST["name"])) < $name = htmlspecialchars($_POST["name"]); >if(isset($_POST["age"])) < $age = htmlspecialchars($_POST["age"]); >echo "Имя: $name 
Возраст: $age";

Еще одна функция — функция strip_tags() позволяет полностью исключить теги html:

$name = "не определено"; $age = "не определен"; if(isset($_POST["name"])) < strip_tags($_POST["name"]); >if(isset($_POST["age"])) < strip_tags($_POST["age"]); >echo "Имя: $name 
Возраст: $age";

Результатом ее работы при том же вводе будет следующий вывод:

Источник

Безопасность PHP — Проверка поступивших данных

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

//———————— Процедура записи в лог фаил ————————//
function writelog($typelog, $log_text) $log = fopen(‘logs/’.$typelog.’.txt’,’a+’);
fwrite($log, «$log_text\r\n»);
fclose($log);
>
//—————————————————————————-//
Здесь особо пояснять нечего — элементарная запись текстовой строчки $log_text в фаил лога $typelog (см. работа с файлами в PHP).

Функция проверки поступивших данных

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

//——————— Процедура обработки получаемых данных —————-//
function checkrequest($textrequest) // Удираем лишние пробелы
$textrequest = trim($textrequest);
// Производим конвертацию в необходимую кодировку (нужно если у Вас проект использует кодировку отличную от UTF-8)
// $textrequest = iconv(«UTF-8», «WINDOWS-1251», $textrequest);
// Фиксируем атаки
if (preg_match(«/script|http|<|>|<|>|SELECT|UNION|UPDATE|exe|exec|INSERT|tmp/i»,$textrequest)) writelog(‘hack’, date(«y.m.d H:m:s»).»\t».$_SERVER[‘REMOTE_ADDR’].»\t».$textrequest);
$textrequest = »;
>
// Очищаем опасные запросы
if (preg_match(«/[^(\w)|(А-Яа-я-&=.,@():;)|(\s)]/»,$textrequest)) $textrequest = »;
>
// Если не число, то экранируем ковычки
if (!is_numeric($textrequest)) $textrequest = mysql_real_escape_string($textrequest);
>

  • Первой строкой кода удаляем лишние пробелы — они нам не нужны
  • Второй строкой кода производим конвертацию в необходимую кодировку. Это нам понадобиться если мы используем в проекте кодировку отличную от UTF-8 и работаем с ajax. Зачем нам это нужно? На своём личном опыте Я убедился, что несмотря на то, что везде где можно (установки сервера, базы, заголовки) указывается используемая кодировка, броузеры могут реагировать совершенно непредсказуемо и присылать запросы в кодировке UTF-8. Естественно, если Вы используете кодировку UTF-8, то данная строка не нужна, поэтому она у меня закомментирована. Хочу предупредить, что и эта строка не «панацея», так как конвертация не работает для сложных структур (например, массивов).
  • Третьей строкой кода фиксируем «нехорошие» слова в поступивших данных. Если такое слово найдено, делаем запись в лог (см. функцию выше) и очищаем переменную поступивших данных.
  • Четвёртой строкой кода проверяем поступившие данные по «белому списку». «Белый список» — это список допустимых символов, «черный список» — запрещённых символов, соответственно. Почему проверяем именно по первому списку? Потому что, иначе имеется возможность забыть указать какой-нибудь нехороший символ, т.к. их весьма-весьма много (примеры приводить не буду — об этом уже много написано до меня). В моём случаи Я разрешаю использовать только латинские и русские буквы, цифры и несколько необходимых символов. Если данные не прошли проверку, то мы их очищаем.
  • Пятой строкой кода экранируем кавычки при помощи mysql_real_escape_string. Обратите внимание, что экранируются только не числовые значения (!is_numeric). Это делается для того, чтобы не использовать лишний раз функцию mysql_real_escape_string, которая «съедает» примерно 0.0001 сек.
Читайте также:  Css свойства для таблица

Источник

Безопасность в PHP (Обработка даных полученных от пользователей)

Всегда проверяйте полученные данные от пользователя ($_POST, $_GET, $_REQUEST, $_COOKIE, $_FILES) , причем не только от разных инъекций, XSS и прочего, но и на корректность вводимых данных, например, если у вас интернет магазин, то проверяйте, чтобы количество товаров было не отрицательным и целым.

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

SQL-инъекции

  • mysql_escape_string() — для защиты строк и двоичных данных
  • mysql_real_escape_string() — для защиты строк и двоичных данных в соответствии с кодировкой, установленной на сервере (требуется соединение с сервером, иначе возвращает пустой результат)
  • intval() — для защиты целочисленных цифровых значений, intval() возвращает 0 в случае если строка не число.
  • floatval() — для защиты дробных значений, аналогичное поведение как и у intval()

XSS

PHP-инъекция

PHP-инъекция (англ. PHP injection) — один из способов взлома веб-сайтов, работающих на PHP, заключающийся в выполнении постороннего кода на серверной стороне. Читать дальше на wikipedia

Это способ взлома, когда можно исполнить любой php-код на стороне сервера, Очень наспространен благодаря функции include(), в которую новички передают перерменную, полученную от пользователя. Ошибочно думают, что код include($_GET[‘file’].».php»); спасает от такой инекции. НО ЭТО ОШИБКА. Потому что злоумышленник может передать в переменную file «ya.ru/%00»(без ковычек) что отбросит расширение .php

  • addslashes() — она экранирует NULL-символ(в html он обозначется как %00), слеш и ковычки, что позволяет избавиться от нежелательных инъекций, но лучше пользоваться оператором switch, например:

Заключение

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

Источник

Демонстрация ошибок

Это одна из стандартных PHP ошибок, которая а) некрасива для пользователя; б) потенциально опасна.
Поэтому их необходимо перехватывать и упорядочивать.

Читайте также:  Blog page html css

Во первых, функция error_reporting позволяет нам решить, какие ошибки мы хотим видеть.
В принципе, достаточно просто выключить показ всех ошибок (error_reporting(0)), но нам нужно не это, потому что об ошибках мы хотим знать.
Константа всех ошибок — E_ALL.
В пятой версии появилась константа E_STRICT, показывающая строгие замечания по поводу кода.
Разумеется, их желательно видеть, но они не входят в E_ALL, потому будем использовать числовое значение error_reporting(8191), которое вбирает всё, вплоть до новых ошибок шестой версии.

Примечание для любознательных: error_reporting(E_ALL | E_STRICT) не подходит, ибо тогда PHP 4 будет ругаться, не зная, что такое E_STRICT. С численным значением никаких проблем не будет.

Добавляем проверку на DEBUG — константу, выставленной в конфиге, и, с помощью set_error_handler, будем отлавливать ошибки в уже запущеном сервисе. Кстати, свой репортер ошибок должен возвращать true, иначе PHP выбросит стандартную ошибку.

Результат:
(Насчёт сравнения переменной с пятью параметрами я не уверен в выборе метода: in_array красивее, и гораздо медленее, а switch case case быстрее, но совсем некрасиво. Красота — субъективное дело. )

  return true; > set_error_handler('errorHandler'); > ?> 

register_globals

До версии 4.2.0 директива register_globals была в PHP включена по умолчанию.
Привело это к тому, что многие привыкли, что если в форме есть , то в PHP коде можно проверять if ($username == ‘admin’)…

Однако это потенциальная дыра, которая привела ко множеству взломов.
Поэтому к POST, GET, COOKIE переменным надо обращаться через superglobals $_POST, $_GET, $_COOKIE.
Многим это показалось слишком трудно и стала очень популярной команда import_request_variables, возвращающая всё на круги своя.
Так вот.
Не делайте этого.

Другая проблема с register_globals:

Если пользователь — не администратор, а переменная $user_level не инициализирована
(ей не придано значение 0 в начале скрипта, в надежде, что оно 0 автоматически),
то нехороший человек может дописать в адресной строке foo.php?user_level=999 и получить доступ.

Читайте также:  Bot

SQL injection и magic_quotes

опасна. Если пользователь введёт вместо пароля ‘ OR `username` = ‘admin, то система впустит его как админа.

Приведённый пример, разумеется, элементарен.
Но если не решить проблему глобально, всегда можно пропустить какой-нибудь запрос, подверженный SQL injection.
Для борьбы с этим разработчики PHP решили сделать так, чтобы вся информация, поступающая от пользователя, подвергалась обработке и все кавычки escapeились (перед ними ставится слэш, что делает команда addslashes).
Что случилось? Вся информация от пользователя приходит со слэшами. Даже та, что вроде слэши получить не должна. Например, комментарии к статье.
Мало того, это не 100-процентный способ защиты от SQL injection.

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

  elseif (!empty($value) && is_string($value)) < $value = stripslashes($value); >return $value; > $_POST = stripslashes_deep($_POST); $_GET = stripslashes_deep($_GET); $_COOKIE = stripslashes_deep($_COOKIE); > > ?> 

Создаём функцию для фильтрации (mysql_real_escape_string — длинно, да и привязанно к формату проверки. А если понадобиться поменять фильтр?)

И используем её везде. Как только какие-то динамические данных отсылаются SQLу, сразу используем quote:

Проверка данных

Проверяйте всё, что вводит пользователь.
По умолчанию он злоумышленник.

Старайтесь не фильтровать, старайтесь валидировать.
Другими словами, не создавайте чёрного списка, создавайте белый.
Вместо

Так вы будете уверены, что информация чиста и никаких неожиданностей не будет.
Если вы составляете список запрещённых символов, всегда можете просмотреть какой-нибудь нехороший %00 и подобные, о которых, скорее всего, не догадываетесь.

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

Есть несколько команд, с которыми надо обращаться очень осторожно.
Это include, require, readfile, eval, «, system, exec, create_function, dir, fopen и подобные.
Всегда посмотрите трижды, когда используете их, если в них используются данные, которые могут прийти от пользователя, будьте уверены — кто-то обязательно этим воспользуется.

Этот кусок опасен. Если злоумышленник введёт ‘../../../../../etc/passwd%00’, будет рад, а вы — вряд-ли.

Аутентификация

Не забывайте, что cookies редактируются ни чуть не сложнее, чем то, что видно в адресной строке.
Поэтому всё, что приходит как печенье, потенциально — атака.
Так что не надо хранить в cookies уровень доступа пользователя или его ID.
Лучше всего дать PHP самому разбираться с этим, используя сессии.

Кстати, в cookies вообще хранить что-либо надо очень скромно и три раза подумать, а надо ли?

Вывод

Всё время думайте о данных в переменных $_GET, $_POST, $_COOKIE, как об атаке злоумышленника.
Trust no one! 🙂

Источник

Оцените статью