Блог


Прошивка формы.

Вчера случился казус на нашем Блоге, глюкнула система комментариев статей. Был сбой связи и скрипт засчитал несколько попыток добавления. В итоге вместо одного комментария появилось четыре. Такое часто встречается на разных сайтах, где нет защиты от этих глюков и откровенного флуда. До сего момента не было и у нас, так как блог у нас самодельный, разработан на наших уроках, служит примером для подражания )

Но раз казус произошел, нужно что то с ним делать. А за одно извлечем из этой неприятности пользу - напишем сюда же статью. Всем будет полезно.

Итак, обрисуем проблему. Представим себе жииирного, лоснящегося тролля, у которого сосет под ложечкой и который ищет себе жертву на завтрак. И вот его глазки заблестели, он нашел некую гостевую книгу: Ну от F5 сейчас худо бедно все защитились, но в браузере еще есть кнопка "назад". И если тролль пользуется продвинутым браузером типа Оперы или Хрома, то запостив единожды какую-нибудь чушь, он с помощью комбинации клавиш alt+left может заполонить всю книгу однообразным сообщениями, сиречь флудом.

 

Кроме того, как уже говорилось, это может произойти не со зла. Из-за сбоя связи или иных глюков, от нас не зависящих. Особенно этим грешат телефоны почему то.

 

Так вот, есть очень простой и действенный способ этого избежать - прошивка формы сессией. В теории делается так. В момент открытия формы генерируется рандомное число, которое пишется в сессию и скрытое поле формы. Когда комментарий добавляется, сверяем эти два числа (подобие капчи). Если совпадают, замечательно. Нет - давай до свидания.

Посмотрим на простеньком примере:

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

    
// Нам понадобится сессия
    
session_start();
    
// Если форма отправлена, небольшая валидация
    
if(!empty($_POST) && !empty($_POST['text']))
    {
        
// Сверяем контрольные числа
        
if($_POST['filum'] == $_SESSION['filum'])
        {
            
// Если все в порядке - постим
            
file_put_contents('example.txt'$_POST['text']."\n"FILE_APPEND);
        }
        
// Уничтожаем сессию
        
unset($_SESSION['filum']);
    }

    
// В скрытое поле и сессию пишем контрольное число
    
$filum $_SESSION['filum'] = rand(100010000);

    
// Смотрим, что получилось
    
echo nl2br(htmlspecialchars(@file_get_contents('example.txt')));
    
?>

<form action="" method="post">
<input name="text" type="text" />
<input name="filum" type="hidden" value="<?php echo $filum?>" />
<input name="ok" type="submit" value="Пуск" />
</form>

 Я намеренно не стал ставить редирект, что бы можно было увидеть механизм работы скрипта. Сейчас можно попробовать в Опере воспользоваться кнопкой "назад" и посмотреть, возможно ли заняться флудом. В боевом применении редирект обязателен, прошивка формы не спасает от F5, если есть валидация и возврат данных в форму. Она уберегает только от флуда и глюков.

 

Теперь применительно к блогу, рассматриваемому на наших уроках. Добавляем в форму добавления комментариев скрытое поле:
skins/tpl/blog/form.tpl

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
14
15
16
17
18
<!-- /skins/tpl/blog/form.tpl begin -->
 <?php if(empty($tpl_ready)){ ?>
 <br />
     <input class="but" name="form[array1][0]" type="submit" value="Написать комментарий">
  
 <?php }else{ ?>
 <br />
 <?php include IRB_ROOT .'/skins/tpl/bbcode.tpl' ?>
     <textarea id="text" name="form[value1]" cols="80" rows="8"></textarea>
     <input name="form[value2]" type="hidden" value="<?php echo $tpl_id_parent; ?>" />
     <!-- Добавим еще одно скрытое поле для антифлуда -->
     <input name="form[value3]" type="hidden" value="<?php echo $tpl_filum; ?>" />
 <br />
     <input class="but" name="ok" type="submit" value="Отправить" />
 <?php } ?>
  
 <!-- /skins/tpl/blog/form.tpl end -->

 

Ну и контрольное число в скрытое поле и сессию:
models/blog_model.php

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
14
15
16
17
18
19
20
21
22
23
24
25

/**
* Метод представления.
* @param string $template
* @param string $mod
* @param string $link
* @return string 
*/      
    
public function createRows($template$mod$link)
    {
        global 
$GET$POST;
        
$rows  '';    
        
$tpl   getTpl($template);
       
        foreach(
$this->res as $row)
        {
            
$this->title       = !empty($row['m_title']) 
                               ? htmlChars($row['m_title']) : '';
            
$this->keywords    = !empty($row['m_keywords']) 
                               ? htmlChars($row['m_keywords']) : '';
            
$this->description = !empty($row['m_description'])
                               ? htmlChars($row['m_description']) : '';
         
            
$row['title']     = htmlChars($row['title']);
            
$row['link']      = $link;
            
// Если открыта форма 
            
if($row['ready'] = !empty($POST['array1']))
            {
                
// Добавим в сессию и скрытое поле рандомное число
                
$row['filum'] = $_SESSION['filum'] = rand(100010000);    
            }

 

А теперь в контроллере в блок добавления комментариев поставим проверку:
controllers/blog_controller.php

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
14
15
16
17
18
19
20
21
22
23
24
25

            
// Добавим проверку на совпадение контрольного числа  
            
if($ok && $POST['value3'] == $_SESSION['filum'])
            {
                
$error $comm -> addComment($POST['value1'],
                                              
$POST['value2'],
                                              
$_SESSION['userdata']['id'],
                                              
$_SESSION['userdata']['login']
                                              );
                
                if(empty(
$error))
                {
// Если все в порядке, уничтожаем сессионную переменную
                    
unset($_SESSION['filum']);
                   
// И очищаем форму
                    
reDirect();
                }
                
            }
            elseif(
$ok)
                
$info[] = IRB_LANG_ERROR_USERDATA .'<br>'

 

Ну вот и всё, нам не страшен серый волк.

 

Николай aka twin

 

Теги: PHP | HTML

Комментарии (12)

kdes70
21-03-2013
отлично!!!! спасибо!!!
twen а не мог бы ты покозать еще каким оброзом можно расширить фунционал BBcodera(добавить новые смаилики, цитату, скрытое поле)
twin
21-03-2013
Добавим как-нибудь
Fable92
21-03-2013
А как защититься от назойливого тролля, который будет отправлять и отправлять,  одним за одним сообщения, или например, что еще хуже от бота. Неужели кроме каптчи никак? Может быть еще катко выставлять лимит на кол-во запросов или сообщений  (извините если что за глупый вопрос )
twin
21-03-2013
Это извечный вопрос и довольно обширный. Боты атакуют, мы защищаемся. Чем сильнее защиты. тем изощреннее боты. Способы есть, мало кто хочет делиться просто

Взял на карандашик, напишу про этот аспект.
Savage
21-03-2013
А что это за оператор такой странный &∓& в первом листинге, что он означает? Или ∓ просто лишний?
twin
21-03-2013
Глюк-с Это WYSIWYG норовить навставлять чего попало.
Иван
05-04-2013
Такие вещи должны уже быть в движке и при создании формы, автоматом проверяться.
В тех что я знаю готовых бесплатных движках и фреймворках вижу что имеется такая проверка. Это по сути проверка на аутентичность отправки формы.
А не как у вас, в каждую форму и в контроллер вручную каждый раз добавлять
twin
06-04-2013
Даже не знаю что сказать. А вообще товарищ в курсе, что не все пользуются фреймворками и готовыми дщвижками?
Иван
08-04-2013
При чем тут эти не все? Те кто не пользуются готовыми, пользуются своими, и если в этих своих не учтены те удобства, которые элементарно уже давно реализовываются в готовых, то эти самоделки еще сыры и неудобны. Как вот ваш пример добавления проверки.
twin
08-04-2013
Каждый волен выбирать сам, чем ему пользоваться. Подобные инсенуации смотрятся так же, как если бы автолюбитель поучал велосипедиста. Зачем крутить педали, если давно изобретен ДВС. А может людям нравится.  Да и к тому же все универсальные решеия громоздки. В погоне за экономией двух строк кода приходится таскать монструозные генераторы форм, которые еще и напрочь искажают язык размети своими суррогатными подменами.  По мне так лучше написать более длинный, но прозрачный и упрвляемый код, чем экономить (читай: лениться) строки в ущерб прозрачности.  Да и экономия эта эфимерна, если подсчитать символы.

 
Наверх