3

多くの人と同じように、私も CSRF と Django を使用する際に多くの問題を抱えてきました。

コンテキストは次のとおりです:
- ユーザーがファイルをアップロードできる https Web サイトを作成しました -
この Web サイトを作成するために Django 1.4.2 を使用し
ました - 私が望むことを行うアプリ *file_manager* を作成しました
- 私は管理者の URL からのみこのアプリを使用する

で無効django.middleware.csrf.CsrfViewMiddlewareにするMIDDLEWARE_CLASSESsettings.py、すべて正常に動作します。
Debian Squeeze のコマンド ラインで cURL を使用してテンプレートにファイルをアップロードできます。ファイルはサーバーにヒットしますが、問題ありません。
ただし、安全ではないようです。

だから私は有効django.middleware.csrf.CsrfViewMiddleware にしました もう機能しません。CSRF検証に関するあらゆる種類のエラーが発生します。

私は通常の容疑者を排除したと信じています(少なくとも望んでいます):
- {% csrf_token %}
- RequestContext
- settings.pyCsrfViewMiddleware

プロセスに関連するすべてのファイル (私が願っています) の下にあります。

ビュー.py

from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.template import Context, loader, RequestContext
from django.shortcuts import render, get_object_or_404, redirect, render_to_response
from django.core.urlresolvers import reverse

from django.core.context_processors import csrf
from django.views.decorators.csrf import csrf_exempt

from file_manager.models import MyClass
from file_manager.forms import MyClassForm

def index(request):
    latest_file_list = MyClass.objects.order_by('-name')[:5]
    context = Context({
        'latest_file_list': latest_file_list,
    })
    return render(request, 'file_manager/index.html', context)

def list(request):
    # Handle file upload
    if request.method == 'POST':
        form = MyClassForm(request.POST, request.FILES)
        if form.is_valid():
            newdoc = MyClass(name='testupl', filefield = request.FILES['docfile'], uploader='fcav')
            newdoc.save()

            # Redirect to the document list after POST
            return HttpResponseRedirect(reverse('file_manager.views.list'))

    else:
        form = MyClassForm() # A empty, unbound form

    # Load documents for the list page
    documents = MyClass.objects.all()

    # Render list page with the documents and the form
    con = {'documents': documents, 'form': form}
    con.update(csrf(request))
    return render_to_response(
        'list.html',
        con,
        context_instance=RequestContext(request)
    )

list.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Minimal Django File Upload Example</title>
    </head>
    <body>
    <!-- List of uploaded documents -->
    {% if documents %}
        <ul>
        {% for document in documents %}
            <li><a href="{{ document.filefield.url }}">{{ document.filefield.name }}</a></li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No documents.</p>
    {% endif %}

        <!-- Upload form. Note enctype attribute! -->
        <form action="{% url list %}" method="post" enctype="multipart/form-data">{% csrf_token %}
            <p>{{ form.non_field_errors }}</p>
            <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
            <p>
                {{ form.docfile.errors }}
                {{ form.docfile }}
            </p>
            <p><input type="submit" value="Upload" /></p>
        </form>
    </body>
</html>

そして、ここに私のcurlリクエストがあります:

    curl --cacert /home/fcav/apache.pem --user admin:password
-e "https://domain.com/admin/" -X POST 
-F "docfile=@/home/fcav/Downloads/basket.csv"
https://domain.com/admin/file_manager/myclass/list/

リクエストで Cookie も送信しようとすることで、curl リクエストのさまざまなバリエーションを試しましたが、cURL がアップロードを処理する方法について完全に混乱していると思います。

CSRF Coo​​kie が設定されていないか、CSRF 検証に失敗しただけです。

cURL と Django を十分に知っている人がいて、CSRF を無効にせずに自分の Web サイトにアップロードする方法についてのヒントを教えてくれれば、本当に感謝しています。

よろしく、フロリアン

4

2 に答える 2

5

CSRF 検証に合格するには、いくつかの方法があります。

  • csrftokenDjango がリクエストの検証に使用する CSRF トークンを含む CSRF cookie を渡します。
  • CSRF トークンをX-CSRFTokenHTTP ヘッダーとして渡す

でリクエストを行う場合curl、Django が CSRF で検証するページに対してリクエストを行っていますが、CSRF トークンをページに渡していないため、Django はリクエストを検証できません。

curl の使い方がわからないので、curl でそれを行う方法がわからないことをご容赦ください。ただし、次の手順が問題の解決に役立つはずです。

1ステップ 1 は、csrf トークンを取得することです。

ビューが担当GETするURLを使用して最初にリクエストすることで、それを行うことができます。listこれにより、返された内容を含む HTML ドキュメントが{% csrf_token %}返されます。そのセグメントを解析し、そこからトークン値を保存できます。

ensure_csrf_cookie 2 番目の方法は、デコレータlistビューに追加することです。csrftokenそのデコレーターは、ビューが常にリクエストで Cookie を返すようにします。その後もGETリクエストを行う必要がありますが、 の結果を解析する代わりに{% csrf_token %}、返された Cookie から csrf トークンを取得できます。

このステップでは、次のステップで使用する csrf トークンの値が提供されます。

2 csrf トークンを取得したので、リクエストを行うときに、前の手順で取得したトークンの値を含む追加のヘッダーPOSTも渡します。X-CSRFTokenトークンを渡すと、Django はリクエストを検証し、アップロードされたファイルを処理できるようになります。


これらの手順に従うと、csrf-valid リクエストを行うことができます。このアプローチでは、リクエストが HTTP を使用して行われたか HTTPS を使用して行われたかは問題ではありません。HTTPS は、データの整合性とデータの機密性を保証し、サーバーの信頼性を検証します。サーバーにクライアント検証を提供しないため、CSRF は HTTP と HTTPS の両方に適用できます。

于 2012-11-02T20:47:06.300 に答える
1

それで...私はそれを作りました...
多くのテストを行いましたが、最終的に成功しました...
cURL経由で送信する必要があるように見えました:
-サーバーからの証明書
-ドメイン名を含むリファラーヘッダー
-Cookieのcsrftokenその値
- csrf トークン値を含む追加のヘッダー
- アップロードするファイル

このようなもの:

curl --cacert /path/to/cert/apache.pem -e "https://domain.com" --cookie "csrftoken=[value]" -H "X-CSRFToken: [value]" -X POST -F "docfile=@/path/to/myfile/file.csv" https://domain.com/admin/list/
于 2012-11-05T09:30:38.257 に答える