Фильтрация и форматирование HTML-документов. Оглавление Выполнение команд на сервере и взаимодействие с СУБД.

Переполнение буфера

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

char str[4096];
...
sprintf(str, "INSERT INTO answer( rezult_id, q_id, answer, mark,\
 seconds) VALUES ('%s', '%s', '%s', '%s', %d)", 
 *rezult_id, *q_id, answer, row[1], sec1);

В случае если размер форматируемой строки окажется больше, чем 4096 символов, то скорее всего произойдет сбой при исполнении программы. Это приведет к сообщению, которое пользователь увидит в своем броузере Internal Server Error. Оно означает, что CGI-программа не выдала корректного содержания. Такое случается в случае аварийного завершения или неправильного заголовка Content-type. Заранее узнать точный размер форматируемой строки не представляется возможным, можно лишь сделать допущения относительно его максимального размера. Иногда эти допущения оказываются ошибочными. Мы предполагаем одно, а пользователь программы, в данном случае это посетитель веб-сайта ведет себя совершенно по-другому. Мне самому до последнего времени иногда бьют по лбу эти грабли. Для того чтобы избежать подобного рода ошибок контролируйте размер переменных поступающих на вход CGI-программы и любых других, полученных из файлов или баз данных в ходе выполнения программы. Не доверяйте контроль размера переменных атрибуту maxlength или JavaScript! Всегда помните о злоумышленниках, которые могут вызвать вашу CGI-программу со своими параметрами. Делается это очень просто. Если CGI-скрипт может принимать параметры методом GET, то в командной строке броузера злоумышленник напишет обращение к вашему скрипту: http://your_site.ru/cgi-bin/script?p1=v1&p2=v2...pk=vk. Если же скрипт принимает параметры методом POST, то злоумышленник сделает следующий HTML-документ:

<form method=post action="http://your_site.ru/cgi-bin/script">
<input type="hidden" name="p1" value="v1">
<input type="hidden" name="p1" value="v1">
...
<input type="hidden" name="pk" value="vk">
</form>

И как вы догадываетесь, имена параметров, их значения и размеры могут быть какими угодно. В лучшем случае, неправильные параметры приведут к аварийному завершению программы. В худшем, злоумышленник осуществит взлом вашего сервера. Для того чтобы обезопасить себя от вызова скриптов вышеуказанными методами, проверяйте значение HTTP_REFERER - откуда был вызван CGI-скрипт. Если пользователь нажал кнопку Submit или гиперссылку на скрипт на вашем сайте, то переменная окружения HTTP_REFERER должна содержать адрес вашего сайта. Полезно также записывать значение переменной REMOTE_ADDRESS, которая содержит IP-адрес пользователя. В случае если вам в гостевой книге напишут какие-либо нецензурные ругательства можно будет будет определить, кто это сделал. Но особо полагаться на значение HTTP_REFERER тоже нельзя, т.к. это значение посылается броузером. Хакер может взламывать ваш сайт при помощи своего броузера собственной разработки или программы telnet и подделать это значение.

Никогда не используйте функцию sprintf, вместо нее используйте snprintf или LString_Format из библиотеки ITCGI. snprintf гарантирует, что переполнения буфера не произойдет, но при этом форматируемая строка будет урезана. LString_Format работает с типом LString, под который выделяет динамически необходимое количество памяти.

char str[4096];
...
snprintf(str, 4096, "INSERT INTO answer( rezult_id, q_id, answer,\
  mark, seconds) VALUES ('%s', '%s', '%s', '%s', %d)", 
  *rezult_id, *q_id, answer, row[1], sec1);


================================

LString* sql_query = CreateString();
....
LString_Format(sql_query, "CREATE TEMPORARY TABLE IF NOT EXISTS hh \
SELECT COUNT(*) as hit, ip FROM hit \
WHERE DATE_FORMAT(it_date, '%%Y-%%m-%%d')='%s' \
GROUP BY ip ORDER BY hit DESC", *day);
....
DeleteString(sql_query);

Еще один момент, о котором стоит сказать, так это об использовании функции printf для вывода HTML-кода. Никогда не пишите printf(html);, т.к. в этом случае все проценты, которые находятся в строке html будут интерпретированы функцией printf, как формат передаваемых ей параметров. В лучшем случае, эти проценты будут просто съедены, в худшем - последствия непредсказуемы. Правильно писать:

printf("%s", html);
В этом случае вывод html-кода пройдет нормально и с процентами ничего не случится.