Архив октября 2008

Подтверждение действия

Пятница, 24 октября, 2008

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

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

Пример: ссылка для удаления сообщения: <a href=”index.php?a=delete&post=1″ >Удалить</a>. Добавляем в эту ссылку событие onClick=”if (confirm(’Вы действительно хотите это удалить?’)) { this.href+=’&confirm=1′; return true; } else return false;”.

Далее  в процедуре удаления выполняем проверку Далее…

Статья о PHP-безопасности

Понедельник, 13 октября, 2008

Весьма полезная статья про типовые уязвимости PHP-скриптов: http://vingrad.ru/blogs/dominus/rokovyie-oshibki-php/ и вторая часть http://vingrad.ru/blogs/dominus/rokovyie-oshibki-php-v2/

Оптимизация MySQL-запросов

Воскресенье, 12 октября, 2008

Несколько советов по оптимизации MySQL-запросов.

  1. Для изучения того, как выполняется запрос, можно использовать ключевое слово EXPLAIN (добавляется перед текстом запроса). EXPLAIN показывает, в каком порядке таблицы связываются, какие ключи при этом используются и сколько строк выбирается из каждой таблицы.
  2. Если количество строк, которое надо выбрать, заранее известно точно (например, нужна всего одна строка), в конец запроса имеет смысл добавить LIMIT 1. В этом случае при связывании каждой таблицы будет искаться только первая запись, соответствующая критерию. (Исключением являются случаи, когда все таблицы связываются по первичному/уникальному ключу, в этом случае LIMIT 1 не даст каких-либо выгод.)
  3. Если таблица содержит большие текстовые или бинарные поля, а при выводе требуется ее сортировка по какому-то другому полю (например, дате или номеру) или выборка по сложному критерию, не затрагивающему эти текстовые поля, то имеет смысл разбить ее на две таблицы, в одной из которых будет поле для сортировки, а в другой — текстовое. В этом случае сортировка/выборка значительно ускорится.
  4. При использовании LEFT JOIN таблицы связываются в том порядке, в котором они перечислены. Этим следует пользоваться для того, чтобы вынести в конец запроса “тяжелые” таблицы, которые присоединяются для получения информации и не участвуют в выборке данных по сложным критериям (т.е. привязываются к предыдущим по первичному ключу). Примером такой ситуации является таблица с текстыми/бинарными данными из п.3. В начало запроса следует выносить те таблицы, выборка по которомы значительно сокращает количество строк данных, выбираемых в следующих таблицах (это можно узнать с помощью EXPLAIN).
  5. Для выборки максимума можно воспользоваться сортировкой по искомому столбцу и LIMIT 1.
  6. При создании индексов нужно не забывать, что если для первого столбца индекса совпадает более 30% значений, то этот индекс не используется при выборке. Поэтому в ситуациях, когда таблица индексируется по двум столбцам, в одном из которых значение меняется редко, этот столбец должен обязательно идти последним. Пример: один столбец col1 — двоичный признак, в который пишутся значения 0 и 1, причем записей с 1 значительно больше, чем с 0, а второй col2 — дата, и выборка производится всех сообщений с признаком 1 в определенном диапазоне дат. Если индекс будет определен как (col1,col2), он будет проигнорирован, так как записей с 1 более 30%, и для выборки по дате придется просматривать всю таблицу. Если же определить индекс как (col2,col1), то он сработает нормально.
  7. В некоторых ситуациях, когда требуется сделать выборку по сложному условию из нескольких таблиц и часть этого условия не совпадает ни с одним индексом, может оказаться выгоднее вынести эту часть условия в HAVING, а связывание таблиц делать исключительно по индексам. Но это утверждение верно только в случаях, когда количество записей с дополнительным условием не сильно отличается от количества записей, извлеченных только по ключам.
  8. В некоторых слуачаях вместо операции UPDATE оказыается более целесообразным делать DELETE/INSERT и периодически выполнять оптимизацию по cron, чтобы уменьшить время блокировок.

Уязвимость через разрешенные теги или Зачем различать GET и POST на стороне сервера

Пятница, 10 октября, 2008

На сайтах, где пользователям разрешается отправлять свои сообщения/комментарии с использованием некоторого ограниченного количества HTML-тегов (в частности, <img src=”"> или <a href=”"> или их BBCode-аналоги ), возможна следующая уязвимость: злоумышленник вставляет в страницу ссылку, выполняющую какое-то нежелательное действие штатными средствами скрипта (например, удаление комментария предыдущего пользователя). Далее, если на эту страницу заходит модератор или администратор, его броузер заходит по этой ссылке, пытаясь скачать вставленную картинку, а вместо этого выполняет удаление сообщения, причем даже не заметив этого факта.

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

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

Пример такой ситуации. Пусть index.php?action=delete&post=111 — ссылка для удаления комментария. Если проверок на POST-метод или ключ не выполняется, то злоумылшенник может отправить сообщение с картинкой <img src=”index.php?action=delete&post=111″>, и если в тему зайдет модератор, сообщение 111 будет удалено. При добавлении проверки по ключу ссылка для модератора принимает вид index.php?action=delete&post=111&key=случайный_ключ, при этом ключ хранится в сессии модератора и никому, кроме него неизвестен. При попытке выполнить удаление без ключа (или с неправильным ключом) действие просто не будет выполнено, в результате чего атака злоумышленника провалится.


Rambler's Top100