Ошибка проверки формы из-за отсутствия CSRF

Несколько дней назад у меня есть reset моя локальная фляга без захвата зависимостей через pip freeze, прежде чем я удалю ее. Поэтому мне пришлось переустановить последнюю версию всего пакета.

Теперь, когда я сижу, я больше не могу проверять формы. Заявки на фляжи CSRF будут отсутствовать.

def register():
    form = RegisterForm()
    if form.validate_on_submit():
       ...
    return make_response("register.html", form=form, error=form.errors)

При первом отправке Get я получаю пустой form.errors, как и ожидалось. Теперь я заполняю форму и отправлю ее, а form.errors показывает: {'csrf_token': [u'CSRF token missing']}

Это так странно. Интересно, изменилась ли Flask-WTF, и я неправильно ее использую.

Я отчетливо вижу, что существует form.CSRF_token, так почему он утверждает, что он отсутствует?

CSRFTokenField: <input id="csrf_token" name="csrf_token" type="hidden" value="1391278044.35##3f90ec8062a9e91707e70c2edb919f7e8236ddb5">

Я никогда не касался рабочего шаблона, но я размещаю его здесь тем не менее:

{% from "_formhelpers.html" import render_field %}
{% extends "base.html" %}
{% block body %}
<div class="center simpleform">
    <h2>Register</h2>
    {% if error %}<p class=error><strong>Error:</strong> {{ error }}{% endif %}
    <form class="form-signin" action="{{ url_for('register') }}" method=post>
        {{form.hidden_tag()}}
        <dl>
            {{ render_field(form.name) }}
            {{ render_field(form.email) }}
            {{ render_field(form.password) }}
            {{ render_field(form.confirm) }}
            <dd><input type=submit value=Register class='btn btn-primary'>
        </dl>
    </form>
</div>
{% endblock %}

Является ли это новой ошибкой?

UPDATE:

Я переустановил все, и проблема не устранена.

Как предположил Мартийн, я отлаживаю следующий метод в flask_wtf:

def validate_csrf_token(self, field):
        if not self.csrf_enabled:
            return True
        if hasattr(request, 'csrf_valid') and request.csrf_valid:
            # this is validated by CsrfProtect
            return True
        if not validate_csrf(field.data, self.SECRET_KEY, self.TIME_LIMIT):
            raise ValidationError(field.gettext('CSRF token missing'))

Последнее условие вызывает ошибку проверки.

field.data = "1391296243.8##1b02e325eb0cd0c15436d0384f981f06c06147ec"
self.SECRET_KEY = None (? Is this the problem)
self.TIME_LIMIT = 3600

И вы были правы, сравнение HMAC не удалось.... оба значения в каждый раз разные.

return hmac_compare == hmac_csrf

У меня есть как SECRET_KEY, так и CSRF_SESSION_KEY в моей конфигурации.

Ответы

Ответ 1

Инфраструктура CSRF Flask-WTF отклоняет токен, если:

  • отсутствует токен. Не здесь, вы можете увидеть токен в форме.

  • он слишком старый (по умолчанию для истечения срока действия установлено 3600 секунд или час). Установите атрибут TIME_LIMIT для форм, чтобы переопределить это. Вероятно, здесь не так.

  • если в текущем сеансе отсутствует ключ 'csrf_token'. По-видимому, вы можете видеть токен сеанса, так что тоже.

  • Если подпись HMAC не соответствует; подпись основана на случайном значении, установленном в сеансе под ключом 'csrf_token', секретной стороне сервера и временной меткой истечения срока действия в токене.

Устраняя первые три возможности, вам нужно проверить, почему 4-й шаг выходит из строя. Вы можете отладить проверку в файле flask_wtf/csrf.py в функции validate_csrf().

Для вашей установки вам необходимо убедиться, что настройка сеанса верна (особенно если вы не используете конфигурацию сеанса по умолчанию) и что вы используете правильную секретность на стороне сервера. Сама форма может иметь атрибут SECRET_KEY, но нестабильна для всех запросов, или изменилось приложение WTF_CSRF_SECRET_KEY (последнее по умолчанию соответствует значению app.secret_key).

Поддержка CSRF была добавлена ​​в версии 0.9.0, если вы обновили ее, просмотрите конкретную документацию по защите CSRF. Стандартный класс Flask-WTF Form включает токен CSRF в качестве скрытого поля, при этом скрытые поля достаточно для его включения:

{{ form.hidden_tag() }}

Ответ 2

Наконец-то я нашел проблему после почти дня работы над ней.:( Большое спасибо Мартину, хотя за его помощь.

Реальная проблема заключается в том, как работает последний flask_wtf.csrf. Изготовители полностью отреагировали на это.

Вы должны заменить все {{form.hidden_tag()}} в своих шаблонах <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>.

И теперь вы должны включить защиту CSRF явно, добавив CsrfProtect(app).

Документация теперь явно отражает это, но я не знал, что это изменилось и преследовало призраков.

Это большая проблема с устаревшей функциональностью, не уведомляя разработчика как-то. Любой, кто обновляется до последней версии, будет преследовать призраков, как я. Но это также моя вина, не сделав снимок моих зависимостей. Урок усвоил трудный путь.