it-swarm.com.ru

Проверка формы не пройдена из-за отсутствия CSRF

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

Теперь на ровном месте я больше не могу проверять формы. Flask утверждает, что 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 %}

Это новая ошибка?

Обновление:

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

Как предложил Мартейн, я отлаживаю следующий метод в 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.

18
Houman

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

  • токен отсутствует. Дело не в этом, вы можете увидеть токен в форме.

  • он слишком старый (срок действия по умолчанию - 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 class includes токен CSRF как скрытое поле, для его отображения достаточно скрытых полей:

{{ form.hidden_tag() }}
18
Martijn Pieters

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

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

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

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

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

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

15
Houman

На момент создания приложения:

from flask_wtf.csrf import CsrfProtect

csrf = CsrfProtect()

app = Flask(__name__)   

...

csrf.init_app(app)

...
0
caverac

Для меня проблема не в том, что Flask-WTF был плохо настроен, или в отсутствии токена. Это было из переменных окружения.

Если ваш сервер Flask не работает на localhost, то для того, чтобы заставить Flask работать должным образом, вам нужно установить переменную окружения SERVER_NAME. Скорее всего, вы забыли где-нибудь изменить значение SERVER_NAME.

Например, вы можете получить что-то подобное в config/settings.py:

SERVER_NAME = 'my-domain.com'

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

0
louis_guitton