Мой сайт

Сайт обо всем по порядку

WpFatFree. Формы


Форм на сайте много. Помимо стандартных вход-выход и контакты, вся работа в админке идет естественно через них. Все они построены по стандартной схеме. Стандартной для бутстрапа. В некоторых случаях использовался AJAX. В частности, при редактировании постов и страниц, для предотвращения перезагрузки страницы и потери содержимого, в случае возникновения ошибок. 
Проверка вводимых данных организована и на стороне клиента, и на стороне сервера. Простенькая защита в виде флажка от ботов. Если это еще работает. Проверка на уровне браузера осуществлена также посредством бутстрап. В смысле стилизации формы в случае неправильного ввода.
Для предотвращения отправки невалидных данных использован скрипт. В случае ошибки данные не отправятся. Правда я не знаю, реализовано ли это для всех форм. По идее он универсальный. Код скрипта приведен ниже. Стандартный из документации бутстрапа. Разве что добавлена проверка переключателя флажка. 
 

(function () {
  'use strict';
  window.addEventListener('load', function () {
    // Get the forms we want to add validation styles to
    var forms = document.getElementsByClassName('needs-validation');
    // Loop over them and prevent submission
    var validation = Array.prototype.filter.call(forms, function (form) {
      form.addEventListener('submit', function (event) {
        if (form.checkValidity() === false) {
          $('#formCheck').prop("checked", false);
          event.preventDefault();
          event.stopPropagation();
        }
        form.classList.add('was-validated');
      }, false);
    });
  }, false);
})

Проверка на стороне сервера осуществляется посредством класса Validator.php. Любезно предоставленным мне гитхабом. Хотя многие проверки пришлось добавлять самому, благо сделать это не сложно. Там во всех подобных классах основной упор сделан на типы данных, а мне пока это не надо. Пришлось дописать регулярки.

Мне лично класс понравился. Забил поля формы ему и ни о чем больше заботится не надо. Потом он все ошибки вернет в массиве. Вывести который – дело техники. Добавляем в проверку поля. Того же массива POST.
 

$v = new \Validator($this->f3->get('POST'));

  И назначаем полям правила проверки.        

$v->rules([
                    'lengthBetween' => [
                        ['name', 4, 200],
                        ['slug', 4, 200]
                    ],
                    'regex' => [['name', '/^[a-zA-Zа-яА-Я0-9\s?!\.,:\']+$/u']],
                    'required' => ['name','slug'],
                    'slug' => ['slug']
]);

Далее, в случае неудачной проверки данных выводим ошибки в массив.

$errors = $v->errors();
                if(!empty($errors)){
                    foreach($errors as $error => $val){
                        \Flash::instance()->addMessage('поле ' . $error .':');
                        foreach($val as $err)
                            \Flash::instance()->addMessage('Ошибка: ' . $err);
                    }
}


И тут еще один замечательный класс Flash. Который, как я понял, существует до первого вывода. То есть то, что надо в большинстве случаев. Вывел потом эти ошибки и забыл. Flash опять готов к работе совершенно чистый от старых данных. Не ломая голову над тем, где сохранять результаты вывода.

<div class="form-error bg-danger text-white mt-2 text-center">
            <repeat group="{{ \Flash::instance()->getMessages() }}" value="{{ @msg }}">
                <div class="message {{ @msg.status }}">
                    {{ @msg.text | esc }}
                </div>
            </repeat>
</div>

   

CSRF атаки. Защита.

Пожалуй про формы все.  Коротко опишу проблему защиты от CSRF атаки. Я бы не стал ее делать, потому, как и не знал про нее, да и сейчас не особо представляю, как можно подсунуть чужую форму или что там еще. Но в примерах по фреймворку она была, и я тупо перенес ее себе.
При каждом запуске index.php фреймворк формирует токен, если проще какой-то код. Насколько помню восьмизначный. Но не суть. Вот этот токен мы и прописываем скрытому полю формы. Формируем в индексе и копируем его в переменную.

new Session(NULL,'CSRF');
$f3->copy('CSRF','SESSION.csrf');

Заполняем этим значением поле формы.

 <!--  INPUT  hidden token  defenden CSRF ATTAkS-->
 <input type="hidden" name="token" value="{{ @CSRF }}" />

И уже при проверке сравниваем это поле. Плохой человек, по идее, в своей фальшивой форме этого значения знать не может. Если я все правильно понимаю. В результате форма не пройдет валидацию.

if($this->f3->get('POST.token') != $this->f3->get('SESSION. CSRF)) {
//проверка
}

Все бы ничего, но при отправке формы происходит перезагрузка страницы и код формируется новый. Который, конечно, не совпадет с кодом, прописанным в форме. Примеры, из которых я почерпнул эти проверки на поверку оказались нерабочими. А защита в них была, но код не выполнялся. Либо я чего-то не понял. Но в результате моя проверка всегда заканчивалась неудачей.

Поиск ничего не дал. Видимо уж слишком специфичная проблема. А отступать то не хотелось. По тем двум-трем ответам, которые я нашел в интернете, куда я только не помещал формирование токена – все-равно он формировался новый. Либо еще что. Решение пришло не сразу, но пришло.

Я запоминаю код, сформированный во время показа формы, и сравниваю уже с ним, а не с вновь сформированным во время отправки формы.

 

$this->f3->set('SESSION.csrf_old', $this->f3->CSRF);

И проверка идет уже с ним.

  if($this->f3->get('POST.token') != $this->f3->get('SESSION.csrf_old')) {}

В общем то основные правила соблюдены. Так мне хочется думать.

Нет комментариев
  • Оставьте свой комментарий первым
Быстрый ответ [Окно ответа]