LoginSignup
24
21

More than 5 years have passed since last update.

Djangoで二重サブミット抑止

Last updated at Posted at 2017-03-16

二重サブミット・二重送信とは?

二重サブミットとは同じリクエストが複数送られてしまうことです。
POSTリクエストを受け付けた際に行う処理が複数回実行されることによって、想定していない処理が行われる恐れがあります。
ブラウザの再読込ボタン等によっても発生しうるため、何らかの対策をするのが望ましいです。

参考

さいきょうの二重サブミット対策

Djangoに二重サブミット対策の機能はある?

根気よく探しましたがなさそうだったので、簡単に自分で作りました。
ボタンの非活性化等クライアントサイドではなく、サーバーサイドでの二重サブミット判定です。

def set_submit_token(request):
    submit_token = str(uuid.uuid4())
    request.session['submit_token'] = submit_token
    return submit_token

def exists_submit_token(request):
    token_in_request = request.POST.get('submit_token')
    token_in_session = request.session.POP('submit_token', '')

    if not token_in_request:
        return False
    if not token_in_session:
        return False

    return token_in_request == token_in_session

使い方

サンプルでは、以下の流れとなっています。
1. (サーバ -> クライアント) index画面アクセス時にsubmit_tokenをセッション内に保持し、同時にクライアント渡す
2. (クライアント -> サーバ) index画面でのsubmitボタン押下時に、リクエストにsubmit_tokenを含ませる
3. (サーバ) submit_tokenがセッションの中にあるか確認する

exists_submit_token()では一度使ったsubmit_tokenはpopによりセッションから破棄するため、同じリクエストが複数回送られた場合は、error.htmlを返却する処理を行います。

views.py
def index(request):
    submit_token = set_submit_token(request)
    return render(request, 'todo/index.html', {"submit_token": submit_token})

def post(request):
    if not exists_submit_token(request):
        return render(request, 'todo/error.html', {})
    else:
        return render(request, 'todo/complete.html', {})
index.html
<form action="{% url 'todo:post' %}" method="post">
{% csrf_token %}
{{ submit_token }}
<input type="hidden" name="submit_token" value="{{ submit_token }}" />
<input type="submit" value="Submit" />
</form>

最後に

もっとシンプルでわかりやすい方法があればそれを使いたいのですが、上記の実装で一旦妥協してしまいました。
また、Struts2におけるSessionTokenのように、同じリクエストの二回目以降も、処理はしないけど全く同じ画面を返却すると言うのも出来るようにしたいですね…。
良さげなライブラリや、もっとこうしたほうが良いとか、自分はこうやったがあれば、ぜひコメントでご教示ください。

24
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
21