ผลของการเปลี่ยน SECRET_KEY ของ Django


202

ฉันทำผิดพลาดและทำให้โครงการ Django ของฉันSECRET_KEYกลายเป็นที่เก็บข้อมูลสาธารณะ

คีย์นี้ควรถูกเก็บเป็นความลับตามเอกสารhttps://docs.djangoproject.com/en/dev/ref/settings/#std:setting-SECRET_KEY

โปรเจ็กต์ Django นั้นมีการถ่ายทอดสดและได้ทำงานมาระยะหนึ่งแล้วกับผู้ใช้บางคน ฉันจะเปลี่ยนสิ่งSECRET_KEYใดได้บ้าง ผู้ใช้คุกกี้เซสชันหรืออื่น ๆ ที่มีอยู่จะได้รับผลกระทบหรือไม่ เห็นได้ชัดว่าใหม่SECRET_KEYจะไม่ถูกเก็บไว้ในที่สาธารณะ

คำตอบ:


199

แก้ไข: คำตอบนี้ขึ้นอยู่กับ django 1.5

SECRET_KEY มีการใช้งานในสถานที่ต่าง ๆ มากมายฉันจะชี้ให้เห็นสิ่งที่ได้รับผลกระทบก่อนจากนั้นลองดูรายการนั้นและอธิบายคำอธิบายที่ถูกต้องเกี่ยวกับผลกระทบ

รายการสิ่งต่าง ๆ ที่ใช้SECRET_KEYโดยตรงหรือโดยอ้อม:

ในความเป็นจริงจำนวนมากของรายการที่นี่ใช้SECRET_KEYผ่านdjango.utils.crypt.get_random_string()ที่ใช้มันเพื่อเมล็ดเครื่องมือสุ่ม SECRET_KEYนี้จะไม่ได้รับผลกระทบจากการเปลี่ยนแปลงของมูลค่า

ประสบการณ์ของผู้ใช้ที่ได้รับผลกระทบโดยตรงจากการเปลี่ยนแปลงค่าคือ:

  • เซสชันการถอดรหัสข้อมูลจะแตกซึ่งใช้ได้สำหรับแบ็กเอนด์เซสชันใด ๆ (คุกกี้ฐานข้อมูลไฟล์หรือแคช)
  • โทเค็นรีเซ็ตรหัสผ่านที่ส่งไปแล้วจะไม่ทำงานผู้ใช้จะต้องถามรหัสใหม่
  • แบบฟอร์มความคิดเห็น (หากใช้django.contrib.comments) จะไม่ตรวจสอบหากมีการร้องขอก่อนการเปลี่ยนแปลงค่าและส่งหลังจากการเปลี่ยนแปลงค่า ฉันคิดว่านี่เล็กมาก แต่อาจสับสนสำหรับผู้ใช้
  • ข้อความ (จากdjango.contrib.messages) จะไม่ตรวจสอบฝั่งเซิร์ฟเวอร์ในเงื่อนไขการกำหนดเวลาเช่นเดียวกับแบบฟอร์มความคิดเห็น

UPDATE : ตอนนี้ทำงานกับ django 1.9.5 การดูที่แหล่งที่มาอย่างรวดเร็วทำให้ฉันมีคำตอบเหมือนกัน อาจทำการตรวจสอบอย่างละเอียดในภายหลัง


1
ฉันเปลี่ยน SECRET_KEY บนเซิร์ฟเวอร์ dev ในพื้นที่ของฉันและนั่นไม่ได้ออกจากระบบดังนั้นจึงดูเหมือนว่าอย่างน้อยเซสชัน (แคช) ทำงานอย่างถูกต้องหลังการเปลี่ยนแปลง คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับสิ่งที่คุณหมายถึงdata decode will breakและอาจชี้ให้เห็นรหัส (ในโครงการ django หรือตัวอย่าง) ที่จะพัง แก้ไข: ยังคงใช้ django 1.4 - เป็นกรณีนี้หรือไม่
Kirill Zaitsev

@teferi ฉันไม่รู้เกี่ยวกับ 1.4 มันเป็นเรื่องของการดูรหัส ฉันชี้แหล่งที่มาทั้งหมดสำหรับแต่ละจุดคุณสามารถดูที่ "ปกป้องข้อมูลเซสชันและสร้างคีย์เซสชันแบบสุ่ม" เป็นเรื่องปกติที่คุณยังคงเข้าสู่ระบบ แต่คุณจะไม่สามารถอ่านข้อมูลที่อยู่ในเซสชันตามที่SECRET_KEYใช้ในsalted_hmacการแฮชข้อมูลเซสชัน
sberder

ถ้ามันใช้สำหรับการแฮ็นรหัสผ่านนั่นไม่ได้หมายความว่าต้องรีเซ็ตรหัสผ่านในฐานข้อมูล
Henning

7
@ Henning ฉันไม่คิดอย่างนั้น รหัสผ่านจะถูกเก็บไว้เป็น<algorithm>$<iterations>$<salt>$<hash>ใน auth_user ดังนั้นเกลือสุ่มจะถูกเก็บไว้ข้างรหัสผ่านในแต่ละกรณี
เดนิส Drescher

2
คำตอบจะแตกต่างกันอย่างมากสำหรับรุ่น Django หรือไม่> 1.5 (เช่นปัจจุบัน 1.9 ปัจจุบัน)
das-g

36

เนื่องจากมีการถามคำถามนี้เอกสารของ Djangoจึงเปลี่ยนเป็นคำตอบ

รหัสลับใช้สำหรับ:

  • การประชุมทั้งหมดถ้าคุณกำลังใช้แบ็กเอนด์เซสชั่นอื่น ๆ ที่ไม่ใช่หรือใช้ค่าเริ่มต้นdjango.contrib.sessions.backends.cacheget_session_auth_hash()
  • ข้อความทั้งหมดถ้าคุณกำลังใช้หรือCookieStorageFallbackStorage
  • PasswordResetViewโทเค็นทั้งหมด
  • การใช้งานของการลงนามการเข้ารหัสใด ๆ เว้นแต่มีการระบุคีย์ที่แตกต่างกัน

หากคุณหมุนรหัสลับของคุณทั้งหมดข้างต้นจะถูกยกเลิก รหัสลับไม่ได้ใช้สำหรับรหัสผ่านของผู้ใช้และการหมุนคีย์จะไม่ส่งผลกระทบต่อพวกเขา

ไม่ชัดเจนสำหรับฉันว่าฉันควรหมุนรหัสลับอย่างไร ผมพบว่าการอภิปรายของวิธีการDjango สร้างที่สำคัญสำหรับโครงการใหม่เช่นเดียวกับการสรุปสาระสำคัญที่กล่าวถึงตัวเลือกอื่นในที่สุดผมก็ตัดสินใจที่จะเพียงแค่ได้รับ Django เพื่อสร้างโครงการใหม่คัดลอกคีย์ลับใหม่ลงในโครงการเก่าของฉันแล้วลบโครงการใหม่

cd ~/junk # Go to some safe directory to create a new project.
django-admin startproject django_scratch
grep SECRET_KEY django_scratch/django_scratch/settings.py # copy to old project
rm -R django_scratch

ปรับปรุง

ดูเหมือนว่า Django จะเพิ่มget_random_secret_key()ฟังก์ชั่นในเวอร์ชั่น 1.10 คุณสามารถใช้สิ่งนั้นเพื่อสร้างรหัสลับใหม่

$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
s!)5@5s79sp=92a+!f4v!1g0d0+64ln3d$xm1f_7=749ht&-zi
$ ./manage.py shell -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
_)+%kymd=f^8o_fea1*yro7atz3w+5(t2/lm2cz70*e$2mn\g3
$

4
การสร้างรหัสลับขึ้นอยู่กับรหัสลับหรือไม่?
kdazzle

4
ไม่ @kdazzle ถ้าคุณดูซอร์สโค้ดstartprojectคุณจะเห็นว่ามันเพิ่งสร้างสตริงแบบสุ่มโดยใช้cryptoโมดูล
Don Kirkby

12
เฮ้ขอโทษ @DonKirkby เรื่องตลกไม่ดี
kdazzle

16

ตามหน้านี้https://docs.djangoproject.com/en/dev/topics/signing/ SECRET_KEY ส่วนใหญ่จะใช้สำหรับสิ่งชั่วคราว - ลงนามข้อมูลที่ส่งผ่านสายเพื่อให้คุณสามารถตรวจจับการงัดแงะ ดูเหมือนว่าสิ่งที่สามารถทำลายคือ:

  • คุกกี้ประเภทค่าที่ลงชื่อเช่น "จดจำการรับรองความถูกต้องกับคอมพิวเตอร์เครื่องนี้" ในกรณีนี้คุกกี้จะไม่ถูกต้องลายเซ็นจะไม่สามารถตรวจสอบได้และผู้ใช้จะต้องรับรองความถูกต้องอีกครั้ง
  • สำหรับผู้ใช้ที่ขอลิงค์เพื่อรีเซ็ตรหัสผ่านหรือดาวน์โหลดไฟล์ที่กำหนดเองลิงก์เหล่านั้นจะไม่สามารถใช้งานได้อีกต่อไป ผู้ใช้จะต้องขอลิงค์เหล่านั้นอีกครั้ง

บางคนที่มีประสบการณ์ Django ล่าสุดและ / หรือขายดีกว่าฉันอาจจะพูดสอดในสิ่งอื่น แต่ฉันสงสัยว่าถ้าคุณไม่ได้ทำอะไรบางอย่างกับ API การเซ็นชื่อคุณควรสร้างความไม่สะดวกสำหรับผู้ใช้ของคุณ


6
ถ้าอย่างนั้นทำไมไม่สร้างคีย์ใหม่ในแต่ละเซิร์ฟเวอร์รีสตาร์ท?
osa

4
อาจเป็นสาเหตุของปัญหาหากคุณใช้เซิร์ฟเวอร์เดียวกันโดยใช้หลายกระบวนการ
dbn

1
@ คุณต้องการออกจากระบบผู้ใช้ทุกครั้งที่คุณกดรหัส / รีสตาร์ทเซิร์ฟเวอร์หรือไม่
EralpB

6

สตริง SECRET_KEY ส่วนใหญ่จะใช้สำหรับการเข้ารหัสและ / หรือการแฮ็คข้อมูลคุกกี้ เฟรมเวิร์กจำนวนมาก (รวมถึง Django) มาถึงสิ่งนี้เนื่องจากคุกกี้เซสชั่นเริ่มต้นมีข้อเสียของตัวเอง

ลองนึกภาพว่าคุณมีรูปแบบใน django สำหรับการแก้ไขบทความด้วยเขตข้อมูลที่ซ่อนอยู่ ในฟิลด์ที่ซ่อนอยู่นี้จะถูกจัดเก็บ ID ของบทความที่คุณแก้ไข และถ้าคุณต้องการให้แน่ใจว่าไม่มีใครสามารถส่งรหัสบทความอื่น ๆ ให้คุณคุณจะเพิ่มเขตข้อมูลที่ซ่อนอยู่พิเศษด้วยรหัสแฮช ดังนั้นถ้าใครบางคนจะเปลี่ยน ID คุณจะรู้เพราะแฮชจะไม่เหมือนเดิม

แน่นอนว่านี่เป็นตัวอย่างที่น่าสนใจ แต่นี่คือวิธีที่ SECRET_KEY ใช้

Django เป็นผู้ใช้งานภายในโดยใช้ตัวอย่างสำหรับ {% csrf_token%} และอีกสองสามอย่าง มันจะไม่ส่งผลกระทบใด ๆ ต่อแอปพลิเคชันของคุณหากคุณจะเปลี่ยนตามคำถามของคุณและคุณไม่ได้ใช้งาน

มีเพียงสิ่งเดียวคือว่าบางทีค่าเซสชั่นจะลดลง ตัวอย่างเช่นผู้ใช้จะต้องลงชื่อเข้าใช้ผู้ดูแลระบบอีกครั้งเพราะ django จะไม่สามารถถอดรหัสเซสชันด้วยคีย์ที่แตกต่างกัน


1

ฉันทำผิดพลาดแบบเดียวกัน รหัสผ่านเริ่มต้นยาว 50 ดังนั้นฉันจึงใช้ powershell เพื่อสร้างสตริงสุ่มยาว 50 รายการและแทนที่ SECRET_KEY เก่าด้วย ฉันเข้าสู่ระบบและหลังจากแทนที่ SECRET_KEY เซสชันก่อนหน้าของฉันถูกใช้งานไม่ได้

ด้วย PowerShell ( แหล่งที่มา ):

# Load the .net System.Web namespace which has the GeneratePassword function
[Reflection.Assembly]::LoadWithPartialName("System.Web")

#  GeneratePassword(int length, int numberOfNonAlphanumericCharacters)
[System.Web.Security.Membership]::GeneratePassword(50,5)

ด้วย Bash ( แหล่งที่มา ):

# tr includes ABCabc123 and the characters from OWASP's "Password special characters list"
cat /dev/urandom | tr -dc 'A-Za-z0-9!"#$%&\''()*+,-./:;<=>?@[\]^_`{|}~' | head -c 100 ; echo

ณ จุดนี้ฉันคิดว่าทำไมไม่ลองใช้ปุ่มที่ใหญ่กว่านี้ดังนั้นฉันจึงลองด้วยคีย์ยาว 100 และ 1,000 ทั้งสองทำงาน หากฉันเข้าใจซอร์สโค้ดวัตถุที่ส่งคืนโดยฟังก์ชันผู้ลงนามคือ hmac hash ใน base64 RFC 2104มีสิ่งนี้เพื่อบอกว่าต้องใช้ความยาวของคีย์ลับ HMAC

แอปพลิเคชันที่ใช้คีย์ที่ยาวกว่า B ไบต์จะแฮชคีย์โดยใช้ H ก่อนจากนั้นใช้สตริง L ไบต์ที่เป็นผลลัพธ์เป็นคีย์จริงของ HMAC

กุญแจสำหรับ HMAC สามารถมีความยาวใด ๆ (คีย์ที่ยาวกว่า B ไบต์จะถูกแฮชครั้งแรกโดยใช้ H) อย่างไรก็ตามน้อยกว่า L ไบต์เป็นกำลังใจอย่างยิ่งเพราะมันจะลดความแข็งแรงของการรักษาความปลอดภัยของฟังก์ชั่น ยอมรับคีย์ที่ยาวกว่า L ไบต์ แต่ความยาวพิเศษจะไม่เพิ่มความแข็งแรงของฟังก์ชันอย่างมาก (อาจใช้คีย์ที่ยาวกว่านี้หากการสุ่มของคีย์ถือว่าอ่อนแอ)

หากต้องการแปลเป็นภาษาพูดปกติขนาดของรหัสลับจะต้องมีขนาดเท่ากับเอาต์พุต ที่สำคัญยังต้องอยู่ในบิต แต่ละหลักใน base64 หมายถึง 6 บิต ดังนั้นหากคุณมีรหัสผ่าน 50 ตัวคุณจะมีรหัสลับ 50 x 6 = 300 บิต หากคุณใช้ SHA256 คุณจะต้องใช้คีย์ 256 บิต ( sha256 ใช้ 256 บิตตามคำจำกัดความ ) ดังนั้นรหัสผ่านที่ยาว 50 ควรทำงานยกเว้นว่าคุณวางแผนที่จะใช้อัลกอริทึมการแฮชที่มีขนาดใหญ่กว่า SHA256

แต่เนื่องจากบิตเพิ่มเติมในคีย์ถูกแฮชขนาดของมันจะไม่ลดประสิทธิภาพลงอย่างเห็นได้ชัด แต่จะรับประกันได้ว่าคุณมีบิตเพียงพอสำหรับฟังก์ชั่นแฮชที่ใหญ่ขึ้น SHA-512 จะครอบคลุมโดย SECRET_KEY ยาว 100 ( 50 x 6 = 600 บิต> 512 บิต )

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