Нет не так.
Во-первых, это не защищает от SQL-инъекции, но об этом позже.
1) Нет никаких причин вызывать для данных функцию htmlspecialchars() перед тем как записать эти данные в БД. Данные в БД стоит записывать в том виде, в котором они пришли. (Причина такой организации объяснять не буду)
Если то, сколько места занимает база — не важно, а вывод данных из базы на страницу (конечному пользователю) происходит очень часто, то рациональнее использовать твой вариант. Т.е. скажем если есть большой текст, и он показывается на каждой странице сайта и берётся из базы, то тут логичнее хранить в базе уже обработанный с помощью htmlspecialchars вариант.
Другим случаем, когда такой вариант надо применять является случай, когда текст может содержать некоторые html-теги, но наряду с этим, может содержать теги, которые не должны отображаться как теги
Для примера можно рассмотреть phpBB2: там html-теги в постингах отображались как просто текст, но тем не менее, можно было вставить (вручную, правкой базы) в постинг html-код, который не превратится в "просто текст" при отображении топика. Вобщем-то, в phpBB2 была возможность разрешать некоторые html-теги для использования внутри постингов. Собственно для этого и было выбрано хранение в базу уже обработанного варианта.
Теперь насчёт SQL-инъекции.
Хитрецы могут сформировать такой GET-запрос, значения аргументов которого, будучи вставленными в твой SQL-запрос, раздробят его на две или более частей, среди которых может оказаться и drop database.
Нехитрецы могут сформировать строчку, содержащий такой символ (например одинарную кавычку), что при вставке этой строчки в SQL-запрос последний станет иметь невалидный синтаксис.
(Пример: $username = "Janna D'Ark"; $where_clause = "where u_name = '$username' and ...";)
Чтобы этого не произошло, все символы, которую в SQL имеют особый смысл, но должны быть истолкованы парсером запросов как обычные символы, следует заэкранировать.
В вопросе об экранировании есть несколько аспектов:
- В обычном PHP стандартным способ заэкранировать строчку является вызов функции addslashes(). Чтобы разэкранировать строчку, надо, соотвественно, вызывать stripslashes().
- Эти функции экранирует то, что сами считают нужными. Не исключено, что окажется, что они заэкранируют что-то, что не нужно (для исопльзования внутри MySQL), и наборот, забудут заэкранировать что-то, что должно быть заэкранировано для использования в MySQL).
Поэтому, MySQL имеет свою функцию для экранирования, которая гарантировано заэкранирует все те символы, что должны быть заэкранированны именно для MySQL. Речь идёт о функции mysql_real_escape_string(). - В PHP есть такая фишка, как MagicQuotes. Это security-технология, которая сама (без твоего веления) экранирует все входящие в скрипт (т.е. потенциально опасные) данные. Дело в том, что эта фишка может быть во-первых либо включена, либо выключена. Во-вторых, она может обрабатыватьт только $_GET-параметры, только $_POST или только $_COOKIE. Все эти параметры поведения MagicQuotes устанавливаются в php.ini (параметры начинаются на "magic_quotes", например "magic_quotes_gpc").
Понятно, что если входящие данные уже были заэкранированы (не нами), нам повторно экранировать их не нужно (потому что тогда в базу попадёт одно лишнее ненужное экранирование, что очень нехорошо). И наоборот, нельзя полагаться, что MQ включено и нам ничего экранировать не надо — MQ могут с успехом выключить.
Чтобы узнать, подверглись ли параметры $_GET, $_POST, $_COOKIE (далее GPC-параметры) подвергнуты (MQ-экранированию), есть функция get_magic_quotes_gpc(). Если она возвращает true, то всё уже заэкранировано, в противном случае, нам надо экранировать всё самим.
Как её использовать — твоё дело, может каждый раз вызывать её и делать проверку, но я в своём движке (который многие тут отказались называть движком, и признали фреймворком) сделал на самом-самом нижнем уровне следующее:
- Код: Выделить всё
if($config['ssp']!='auto')
{
if($config['ssp']=='force' || (!get_magic_quotes_gpc()))
{
$_GET = security_add_gpc_array_slashes($_GET);
$_POST = security_add_gpc_array_slashes($_POST);
$_COOKIE = security_add_gpc_array_slashes($_COOKIE);
}
}
if($config['gpc_processing']!='auto')
{
if(($config['gpc_processing']=='force') || (ini_get('register_globals') ))
if(is_array($_GET)) {while(list($kkey)=each($_GET)) {unset($GLOBALS[$kkey]); }}
if(is_array($_POST)) {while(list($kkey)=each($_POST)) {unset($GLOBALS[$kkey]); }}
if(is_array($_COOKIE)){while(list($kkey)=each($_COOKIE)){unset($GLOBALS[$kkey]); }}
}
(где security_add_gpc_array_slashes() — функция, рекурсивно обходящая дерево-массив, и квотящее в нём всё строковое)
Здесь второй блок не имеет никакого отношения к MQ, но это тоже security-трюк против register_globals.
Таким образом, мой движок обезопасивает сайт от того, какие настройки имеет PHP (и главное от того, что они внезапно кем-нибудь будут изменены). Так что для кода моих сайтов всегда абсолютно точно можно сказать, что все GPC-данные гаратировано экранированы.
- Помимо addslashes() и stripslashes() есть addсslashes() и stripсslashes(), которые экранируют то, что подлежит экранированию в языке С.