ไม่ได้ตั้งค่าคุกกี้ CSRF ของ Django


86

ฉันมีปัญหามาระยะหนึ่งแล้วพบว่าไม่ได้ตั้งค่าคุกกี้ CSRF โปรดดูรหัสด้านล่าง

Python

def deposit(request, account_num):
    if request.method == 'POST':
        account = get_object_or_404(account_info, acct_number=account_num)
        form_ = AccountForm(request.POST or None, instance=account)
        form = BalanceForm(request.POST)
        info = str(account_info.objects.filter(acct_number=account_num))
        inf = info.split()
        
        if form.is_valid():

            # cd=form.cleaned_data
            now = datetime.datetime.now()
            cmodel = form.save()
            cmodel.acct_number = account_num
            
            # RepresentsInt(cmodel.acct_number)
            cmodel.bal_change = "%0.2f" % float(cmodel.bal_change)
            cmodel.total_balance = "%0.2f" % (float(inf[1]) + float(cmodel.bal_change))
            account.balance = "%0.2f" % float(cmodel.total_balance)
            cmodel.total_balance = "%0.2f" % float(cmodel.total_balance)
            
            # cmodel.bal_change=cmodel.bal_change
            cmodel.issued = now.strftime("%m/%d/%y %I:%M:%S %p")
            account.recent_change = cmodel.issued
            cmodel.save()
            account.save()
            
            return HttpResponseRedirect("/history/" + account_num + "/")
        
        else:
            return render_to_response('history.html',
                                      {'account_form': form},
                                      context_instance=RequestContext(request))

ใน HTML นี่คือรหัส

HTML

<form action="/deposit/{{ account_num }}/" method="post">
    <table>
        <tr>
            {{ account_form.bal_change }}
            &nbsp;
            <input type="submit" value="Deposit"/>
        </tr>
        {% csrf_token %}
    </table>
</form>

ฉันติดขัดฉันล้างคุกกี้แล้วใช้เบราว์เซอร์อื่น แต่ยังไม่ได้ตั้งค่าคุกกี้ csrf


คุณมีCsrfViewMiddlewareในMIDDLEWARE_CLASSESการตั้งค่าของคุณหรือไม่?
alecxe

เพิ่ม{%csrf_token%}ในแบบฟอร์มของคุณในเทมเพลต
Rohan

4
@ โรฮานมีอยู่แล้วดูคำถาม
alecxe

1
ใช่ฉันมี CsrfViewMiddleware อยู่แล้วและฉันมี csrf_token ในรูปแบบของฉันแล้ว

ฉันใช้โมดูล Django cors และเข้าถึงผ่าน ReactJS (ทั้งคู่อยู่ใน localhost) ฉันยังมีปัญหาของ OP ฉันพบว่าการเพิ่มcredentials: 'include'ในคำขอ POST แล้วยังเพิ่มใน settings.py ของ django: CORS_ALLOW_CREDENTIALS = Trueดูเหมือนว่าจะได้รับการแก้ไขปัญหาโดยไม่จำเป็นต้องเพิ่ม@csrf_exemptในมุมมอง มันเป็นจริงในเอกสาร ... pypi.org/project/django-cors-headers-multi * ฉันรู้ว่านี้เกี่ยวข้องกับหนึ่งในคำถามข้างต้น แต่ฉันไม่สามารถแสดงความคิดเห็นและยังต้องการที่จะหวังว่าคนอื่นประหยัดเวลาที่ พาฉันไปหา t
DW

คำตอบ:


134

นอกจากนี้ยังสามารถเกิดขึ้นได้หากCSRF_COOKIE_SECURE = Trueมีการตั้งค่าและคุณกำลังเข้าถึงไซต์อย่างไม่ปลอดภัยหรือหากCSRF_COOKIE_HTTPONLY = Trueมีการตั้งค่าตามที่ระบุไว้ที่นี่และที่นี่


10
ขอบคุณ! SESSION_COOKIE_SECURE = Trueเดียวกันจะไปสำหรับ
NonameSL

74
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt 
def your_view(request):
    if request.method == "POST":
        # do something
    return HttpResponse("Your response")

61
การปิดกลไกการรักษาความปลอดภัยทั้งหมดไม่ใช่วิธีที่ดีในการแก้ไขข้อผิดพลาด
Guillaume Algis

2
หากคุณใช้ cookiecutter-django ในปี 2017 นี่คือคำตอบที่ถูกต้องในการผลิต
André Duarte

1
ทำไมถึงเป็นเช่นนั้นด้วยความอยากรู้?
Patrick Gallagher

3
คำตอบนี้ไม่ได้แนะนำให้ "ปิดใช้งานกลไกการรักษาความปลอดภัยทั้งหมด" แต่จะบอกวิธีการทำเช่นนั้นสำหรับกรณีเดียวที่คุณอาจไม่สามารถใช้โทเค็น CSRF ได้ นี่เป็นกรณีของฉันที่ฉันต้องเสนอการดำเนินการ POST ให้กับลูกค้าภายนอก
mariotomo

นี่คือรายการสิ่งที่ต้องทำที่ฉันใช้ระหว่างขั้นตอนการพัฒนาเมื่อคุณไม่สามารถให้โทเค็น csrf จาก UI ได้ แต่ไม่แนะนำสำหรับแอปถ่ายทอดสดอย่างแน่นอน
Aman Madan

24

หากคุณใช้HTML5 Fetch APIเพื่อสร้างคำขอ POST ในฐานะผู้ใช้ที่ล็อกอินและรับForbidden (CSRF cookie not set.)อาจเป็นเพราะโดยค่าเริ่มต้นfetchไม่รวมคุกกี้เซสชันส่งผลให้ Django คิดว่าคุณเป็นผู้ใช้ที่แตกต่างจากผู้ที่โหลดหน้า .

คุณสามารถรวมโทเค็นเซสชันได้โดยส่งตัวเลือกcredentials: 'include'เพื่อดึงข้อมูล:

var csrftoken = getCookie('csrftoken');
var headers = new Headers();
headers.append('X-CSRFToken', csrftoken);
fetch('/api/upload', {
    method: 'POST',
    body: payload,
    headers: headers,
    credentials: 'include'
})

ฉันขอทราบได้ไหมว่า Header () เมธอดที่คุณสร้างอินสแตนซ์คืออะไร นั่นคือวิธีการจาวาสคริปต์ทั่วโลกหรือไม่
Abz Rockers

@AbzRockers: ใช่Headersเป็นอินเทอร์เฟซจาวาสคริปต์ส่วนกลางซึ่งเป็นส่วนหนึ่งของ HTML5 Fetch API developer.mozilla.org/en-US/docs/Web/API/Headers
user85461

13

จากสิ่งนี้ คุณสามารถแก้ไขได้โดยเพิ่มมัณฑนากร sure_csrf_cookieในมุมมองของคุณ

from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def yourView(request):
 #...

หากวิธีนี้ไม่ได้ผล คุณจะพยายามแสดงความคิดเห็น csrf ในมิดเดิลแวร์ และทดสอบอีกครั้ง


5

ฉันเจอสถานการณ์ที่คล้ายกันในขณะที่ทำงานกับ DRF โซลูชันกำลังต่อท้ายเมธอด. as_view () เข้ากับ View ใน urls.py


มันจะดีกว่าถ้าคุณใส่โค้ดไว้ด้วย
Alex Jolig

1
@AlexJolig เพิ่งประสบปัญหาเดียวกันปัญหาคือฉันลืมที่จะเพิ่ม.as_view()ApiView ของฉันเพื่อให้โค้ดมีลักษณะอย่างไร: urlpatterns += path('resource', ResourceView)และนั่นคือสิ่งที่ควรจะเป็น: urlpatterns += path('resource', ResourceView.as_view())
Alveona

4

หากคุณใช้ DRF ให้ตรวจสอบว่ารูปแบบ URL ของคุณถูกต้องหรือไม่บางทีคุณอาจลืม.as_view():

ดังนั้นรหัสของฉันจึงเป็นอย่างไร:

urlpatterns += path('resource', ResourceView) 

และนั่นคือสิ่งที่ควรชอบ:

urlpatterns += path('resource', ResourceView.as_view())

1

ลองตรวจสอบว่าคุณได้ติดตั้งใน settings.py หรือไม่

 MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',)

ในเทมเพลตข้อมูลถูกจัดรูปแบบด้วย csrf_token:

<form>{% csrf_token %}
</form>

ฉันไม่มีรหัสทั้งหมดของคุณ แต่ฉันเชื่อว่ามีเรื่องอยู่ที่นี่: def Deposit (request, account_num): เปลี่ยนเป็น def Deposit (request): และหาวิธีโทรกลับ account_num ตอนนี้จะขึ้นอยู่กับว่า account_num เป็นฟิลด์ตารางหรือตัวแปร
drabo2005

เป็นตัวแปร {{account_num}} แต่สิ่งนี้ส่งผลต่อโทเค็น csrf อย่างไร

ฉันเชื่อว่าโทเค็น csrf อ้างอิงกับคำขอเท่านั้นดังนั้นจึงไม่สามารถตรวจสอบหรือจัดการกับสิ่งที่เกิดขึ้นกับตัวแปรที่นี่ได้ ตรวจสอบ djangoproject.com คุณอาจได้รับคำตอบที่ถูกต้องเกี่ยวกับ csrf_token
drabo2005

1

ปัญหานี้เกิดขึ้นอีกครั้งเมื่อเร็ว ๆ นี้เนื่องจากข้อบกพร่องใน Python เอง

http://bugs.python.org/issue22931

https://code.djangoproject.com/ticket/24280

ในบรรดาเวอร์ชันที่ได้รับผลกระทบคือ 2.7.8 และ 2.7.9 อ่านคุกกี้ไม่ถูกต้องหากค่าใดค่าหนึ่งมี[อักขระ

การอัปเดต Python (2.7.10) ช่วยแก้ปัญหาได้


1

นอกจากนี้ยังเกิดขึ้นเมื่อคุณไม่ได้ตั้งค่าการดำเนินการแบบฟอร์ม
สำหรับฉันมันแสดงข้อผิดพลาดนี้เมื่อรหัสคือ:

<form class="navbar-form form-inline my-2 my-lg-0" role="search" method="post">

เมื่อฉันแก้ไขรหัสของฉันเป็นสิ่งนี้:

<form class="navbar-form form-inline my-2 my-lg-0" action="{% url 'someurl' %}" role="search" method="post">

ข้อผิดพลาดของฉันหายไป


0

ปัญหาดูเหมือนว่าคุณไม่ได้จัดการGETคำขออย่างเหมาะสมหรือโพสต์ข้อมูลโดยตรงโดยไม่ได้รับแบบฟอร์มก่อน

เมื่อคุณเข้าถึงเพจครั้งแรกไคลเอนต์จะส่งGETคำขอในกรณีนี้คุณควรส่ง html พร้อมรูปแบบที่เหมาะสม

ต่อมาผู้ใช้กรอกแบบฟอร์มและส่ง POSTคำขอพร้อมข้อมูลแบบฟอร์ม

มุมมองของคุณควรเป็น:

def deposit(request,account_num):
   if request.method == 'POST':
      form_=AccountForm(request.POST or None, instance=account)
      if form.is_valid(): 
          #handle form data
          return HttpResponseRedirect("/history/" + account_num + "/")
      else:
         #handle when form not valid
    else:
       #handle when request is GET (or not POST)
       form_=AccountForm(instance=account)

    return render_to_response('history.html',
                          {'account_form': form},
                          context_instance=RequestContext(request))

0

ตรวจสอบว่าคุกกี้ของ Chrome ถูกตั้งค่าด้วยตัวเลือกเริ่มต้นสำหรับเว็บไซต์ อนุญาตให้ตั้งค่าข้อมูลภายในเครื่อง (แนะนำ)


0

วิธีที่ 1:

from django.shortcuts import render_to_response
return render_to_response(
    'history.html',
    RequestContext(request, {
        'account_form': form,
    })

วิธีที่ 2:

from django.shortcuts import render
return render(request, 'history.html', {
    'account_form': form,
})

เนื่องจากเมธอด render_to_response อาจทำให้เกิดปัญหาบางอย่างของคุกกี้ตอบกลับ


0

เพิ่งเคยเจอครั้งเดียววิธีแก้คือล้างคุกกี้ และอาจมีการเปลี่ยนแปลงในขณะที่กำลังแก้ไขข้อบกพร่อง SECRET_KEY ที่เกี่ยวข้อง


0

การล้างแคชของเบราว์เซอร์ช่วยแก้ปัญหานี้ให้ฉันได้ ฉันสลับไปมาระหว่างสภาพแวดล้อมการพัฒนาในพื้นที่เพื่อทำแบบฝึกหัด django-blog-zinnia หลังจากทำงานในโครงการอื่นเมื่อมันเกิดขึ้น ตอนแรกฉันคิดว่าการเปลี่ยนลำดับของ INSTALLED_APPS ให้ตรงกับบทช่วยสอนนั้นทำให้เกิดปัญหาขึ้น แต่ฉันตั้งค่าเหล่านี้กลับและไม่สามารถแก้ไขได้จนกว่าจะล้างแคช


0

ฉันเคยใช้ Django 1.10 มาก่อนดังนั้นฉันจึงประสบปัญหานี้ ตอนนี้ฉันลดระดับเป็น Django 1.9 แล้วและใช้งานได้ดี


การใช้ 1.10.3 ฉันมีปัญหานี้ การอัปเกรดเป็น 1.10.6 แก้ไขให้ฉัน
Mike Darmetko

0

ฉันมีข้อผิดพลาดเดียวกันในกรณีของฉันเพิ่ม method_decorator ช่วย:

from django.views.decorators.csrf import csrf_protect
from django.utils.decorators import method_decorator

method_decorator(csrf_protect)
def post(self, request):
    ...

0

ตรวจสอบให้แน่ใจว่าแบ็กเอนด์เซสชัน django ของคุณได้รับการกำหนดค่าอย่างถูกต้องใน settings.py จากนั้นลองสิ่งนี้

class CustomMiddleware(object):
  def process_request(self,request:HttpRequest):
      get_token(request)

เพิ่มมิดเดิลแวร์นี้settings.pyภายใต้MIDDLEWARE_CLASSESหรือMIDDLEWAREขึ้นอยู่กับเวอร์ชัน django

get_token - ส่งคืนโทเค็น CSRF ที่จำเป็นสำหรับแบบฟอร์ม POST โทเค็นเป็นค่าตัวเลขและตัวอักษร โทเค็นใหม่จะถูกสร้างขึ้นหากยังไม่ได้ตั้งค่า


-4

ในมุมมองของคุณคุณใช้มัณฑนากร csrf หรือไม่?

from django.views.decorators.csrf import csrf_protect

@csrf_protect def view(request, params): ....

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.