Деловая неделя

Главная опасность PHP, подстерегающая начинающего программиста, – возможность писать код как попало. На более строгих языках (например, Java), такое невозможно.

ЕЖЕНЕДЕЛЬНАЯ РЕКЛАМНАЯ ГАЗЕТА ДЛЯ ПРЕДПРИЯТИЙ «Деловая неделя» (Иркутск)

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

Про безопасность в веб-программировании нужно знать две вещи: 1) защититься от злого умысла невозможно; 2) опасности, от которых нужно защищаться, бывают разного рода. Пропустим плохое и начнём сразу со второго тезиса. С самого плохого во втором тезисе.

Главная опасность PHP, подстерегающая начинающего программиста, – возможность писать код как попало. Например, можно написать if ($x) $y=1; echo $y; – и, если $x==false, на странице вылезет ошибка (потому что $y не был объявлен раньше). На более строгих языках (например, Java), такое невозможно: вы не увидите подобной ошибки на странице, потому что страницы не будет вообще – процесс остановится на этапе компиляции. Защита, которую можно предложить в этом случае для PHP, – писать в начале каждого скрипта error_reporting(E_ALL); ini_set("display_errors", true);. Правда, потом, перед сдачей проекта заказчику, нужно не забыть написать всё обратно: error_reporting(0); ini_set("display_errors", false);. Т.е. простой, надёжной защиты от главной опасности – «от дурака» – в PHP нет. Поэтому переходим дальше – к более предсказуемым проблемным областям.

Основное назначение PHP – работать посредником между клиентом (браузером) и базой данных (Mysql). PHP помещает данные в базу (БД) и извлекает их оттуда; PHP выдаёт данные (в виде HTML-страниц) браузеру и принимает данные (в виде GET и POST запросов) от браузера. Более редкая (но тоже необходимая) работа – с третьим источником-получателем, с файлами: например, бывает необходимо выгрузить данные из БД в файл, чтобы перенести на другой хостинг; или считать данные из файла, который является шаблоном в системе управления сайтом. Таким образом, существует 3 (как минимум) объекта (браузер, БД, файл), между которыми возможен обмен в двух направлениях (получить – отдать данные). Что и порождает второй по численности массив ошибок PHP.

Путаницу усугубляют бесконечно-популярные советы вида «ничему не доверять и всё обрабатывать функцией addCslashes()» (вариант: mysql_real_escape_string()). Эти советы, разумеется, не могут повредить тому, кто не прошёл ещё первый этап защиты PHP – «от дурака». Но более продвинутым разработчикам могут попортить немало крови.

Почему всё обрабатывать addslashes – плохо?

Мы не собираемся передёргивать, под «всё» здесь понимаются только данные, получаемые от пользователя (браузера). Так вот, тупо обрабатывать все данные от пользователя addslashes и после этого жить спокойно – тупой совет. По двум причинам.

1. Мы не знаем заранее, куда потом пойдут эти данные. Достаточно типична ситуация, когда они отправляются не в БД, а обратно в браузер. Например, пользователь в одно из полей вводит своё имя (Джон), после чего на странице в правом верхнем углу появляется надпись: «Привет, Джон!». Нахрена, спрашивается, тут addslashes? А главное зло в том, что эти данные обязательно надо обрабатывать, но совсем другой функцией!

Представьте себе, что пользователь ввёл в поле со своим именем ещё и закрывающий тэг </table> (а у вас на странице табличная вёрстка) – что будет с вашей страницей? Это ещё не идёт речь о злом умысле (а только о неумелых пользователях). А если пользователь умелый попадётся, и введёт тэг <iframe>?

Все уже догадались, что данные, выводимые в браузер, надо обрабатывать функцией htmlspecialchars() (или strip_tags(), в зависимости от политики хозяев сайта). «Данные» в этом контексте – это кусок текста, не написанный руками программиста прямо в PHP-скрипте, а полученный из любого другого источника (файл, БД, браузер). Если, конечно, этот кусок (вместе со всеми его тэгами) не был специально в таком виде помещён в источник (файл, БД) самим программистом.

2. Если не думая пихать везде addslashes – плохо, то писать $name=addslashes(@$_POST["name"]); – дважды плохо. Вторая причина – не учитывается состояние magic_quotes_gpc. Если это состояние «on» («включено»), слэши добавятся дважды, и посетители сайта начнут наслаждаться видом экранированных кавычек.

Правильная обработка данных для безопасности

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

1) не надо обрабатывать данные в момент получения, пишите просто: $name=@$_POST["name"];

2) данные надо обрабатывать перед отправкой и в зависимости от того, куда именно они отправляются:

  1. $name=addslashes($name); mysql_query("update `users` set `name`='$name' where `id`='$id'");
  2. $name=strip_tags($name); echo "Привет, $name!";

3) если планируете использовать addslashes (или mysql_escape_string(), или другие похожие способы обработки) надо при получении данных проверять состояние magic_quotes_gpc и сразу приводить данные к норме:

То есть, по-хорошему, чаще приходится использовать stripslashes, чем addslashes!

Разветвления алгоритма

При выводе в браузер могут возникнуть дополнительные проблемы. Например, такой PHP код:

– выведет в браузере окно ввода текста с одной буквой "d". И addslashes() тут тоже не поможет. Нужна какая-то другая, специальная функция. Или документация к уже упомянутым. Иногда полезно бывает почитать документацию. Там, в частности, написано, что у функции htmlspecialchars есть необязательный второй параметр – в нашем случае поможет, если его значение установить в ENT_QUOTES: $name=htmlspecialchars($name, ENT_QUOTES);.

При выводе таблицы БД в файл (так называемый «дамп») лучше использовать не addslashes(), а функцию mysql_escape_string(), которая экранирует не только кавычки и бэкслэш, но и ещё несколько важных для Mysql символов (в скобках после шестнадцатеричного указан десятичный код): Newline (\n) \x0a (10), Carriage return (\r) \x0d (13), Ctrl+z (\z) \x1a (26). Обе эти функции экранируют также символ NULL (\0) \x00.

Чаще всего полученные от пользователя данные приходится передавать и в БД, и в браузер: надо ведь не только загрузить данные в базу, но и отобразить HTML-форму в том состоянии, в котором её отправил на сайт пользователь (кому приятно заполнять заново форму после неудачной отправки?). Поэтому в целом алгоритм будет такой:

Маленькие хитрости и уточнения

В PHP бывает по две разных внешне похожих функции, их не нужно путать.

  1. addcslashes (с буквой "c") – не надо использовать! Она экранирует только те символы, которые вы специально укажете (а если используете её по ошибке вместо обычной addslashes, она не будет экранировать ничего)!
  2. mysql_real_escape_string() делает в точности то же самое, что и mysql_escape_string(), только использует ещё и подключение к БД, вызывая натуральную (real! круто!) функцию сервера Mysql. А оно вам надо – лишний раз дёргать сервер БД? Дополнительное преимущество real-функции вроде бы в том, что она экранирует символы в соответствии с кодировкой БД. Но это вам не поможет, если соответствие кодировок PHP и Mysql настроено криво. Т.е. если между ними НЕТ соответствия.

О кодировке веб-сервера. В стародавние времена, когда PHP ещё носило другое имя – Perl, с локализацией Apache (и вообще Линукса) в России всё было плохо. Оттуда нам в наследство досталась кодировка KOI8-R, которую до сих пор можно встретить на некоторых сайтах (и особенно в почтовых сообщениях).

В новейшее время модной стала кодировка Юникод (UTF-8). Следуя советам установить её в Mysql и на сайте, ещё нахлебаетесь горя. Иногда, конечно, она бывает необходима. Но в большинстве случаев нужно использовать то, что работает просто и надёжно (и стало стандартом де-факто): cp1251. Пока не поймёте, что вам для чего-то ну совершенно необходим Юникод, пишите всегда и везде:

Не ищите приключений, на большинстве современных хостингов всё это будет прекрасно работать.

В заключение последний маленький совет: никогда не используйте в PHP-скриптах завершающий знак "?>". Особенно в тех, которые вставляются через include. Сам по себе этот знак особого вреда не принесёт, но если вы случайно нажмёте после него Энтер (а ведь обязательно нажмёте!), замучаетесь потом искать, почему header() не работает...

D.M., admin

Читать все комментарии (0)

Добавить комментарий:

*Автор:
E-Mail:
*Текст: