web-dev-qa-db-ja.com

CSRFがないためフォームの検証が失敗する

数日前に、ローカルのflask環境をリセットする前に、_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 %}
_

これは新しいバグですか?

更新:

すべてを再インストールしましたが、問題は解決しません。

Martijnが示唆したように、私は_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の両方があります。

22
Houman

Flask-WTF CSRFインフラストラクチャは、次の場合にトークンを拒否します。

  • トークンがありません。ここではそうではありませんが、フォームでトークンを見ることができます。

  • 古すぎます(デフォルトの有効期限は3600秒、つまり1時間に設定されています)。これをオーバーライドするには、フォームに_TIME_LIMIT_属性を設定します。おそらくここではそうではありません。

  • 現在のセッションで_'csrf_token'_キーが見つからない場合。どうやらセッショントークンを見ることができるので、それも公開されています。

  • HMAC署名が一致しない場合;署名は、_'csrf_token'_キーの下のセッションで設定されたランダムな値、サーバー側の秘密、およびトークンの有効期限のタイムスタンプに基づいています。

最初の3つの可能性を排除したら、4番目のステップが失敗する理由を確認する必要があります。 validate_csrf()関数の_flask_wtf/csrf.py_ファイルで検証をデバッグできます。

セットアップでは、セッションのセットアップが正しいこと(特にデフォルトのセッション構成を使用しない場合)、および正しいサーバー側のシークレットを使用していることを確認する必要があります。フォーム自体に_SECRET_KEY_属性が設定されている可能性がありますが、リクエスト間で安定していないか、アプリの_WTF_CSRF_SECRET_KEY_キーが変更されています(後者のデフォルトは _app.secret_key_ value )。

CSRFサポートはバージョン0.9.0で追加されました。アップグレードした場合は、特定の CSRF保護ドキュメント を確認してください。標準のFlask-WTF FormクラスincludesCSRFトークンを非表示フィールドとして、非表示フィールドをレンダリングするだけでそれを含めることができます。

_{{ form.hidden_tag() }}
_
20
Martijn Pieters

ほぼ1日作業して問題を見つけました。 :( Martijnのご協力に感謝します。

実際の問題は、最新の_flask_wtf.csrf_の動作にあります。メーカーは完全にオーバーホールしました。

テンプレート内のすべての{{form.hidden_tag()}}<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>に置き換える必要があります。

そして、CsrfProtect(app)を追加してCSRF保護を明示的に有効にする必要があります。

documentation は明らかにそれを反映していますが、これが変わって幽霊を追いかけていることは知りませんでした。

開発者に何らかの形で通知せずに廃止された機能に関する大きな問題。今すぐ最新バージョンにアップグレードした人はだれでも、私と同じように幽霊を追いかけます。ただし、依存関係のスナップショットを取得できなかったということも問題です。レッスンは難しい方法を学びました。

16
Houman

アプリの作成時:

from flask_wtf.csrf import CsrfProtect

csrf = CsrfProtect()

app = Flask(__name__)   

...

csrf.init_app(app)

...
1
caverac

私にとっては、Flask-WTFの構成が不適切なことや、トークンが欠落していることが原因ではありませんでした。来ていました環境変数から

Flask= localhostでサーバーが実行されていない場合、Flask=を適切に機能させるには、SERVER_NAME環境変数を設定する必要があります。どこかでSERVER_NAME値を変更するのを忘れている可能性があります。

たとえば、config/settings.pyには次のようなものがあります。

SERVER_NAME = 'my-domain.com'

詳細については、 this great resource をご覧ください。

1
louis_guitton