ทางเลือกในการส่งรหัสผ่านข้อความธรรมดาขณะเข้าสู่ระบบ
หมายเหตุ: ฉันได้อ่านแล้วสามารถส่งรหัสผ่านข้อความธรรมดาผ่าน HTTPS ได้หรือไม่? และความปลอดภัย https - ควรแฮชรหัสผ่านฝั่งเซิร์ฟเวอร์หรือฝั่งไคลเอ็นต์? แต่นี่เป็นวิธีการเปลี่ยนเฉพาะ (ดูด้านล่าง)
หลังจากอ่านบทความเกี่ยวกับวิธีการตรวจสอบสิทธิ์แบบใหม่ในบล็อก Cloudflareฉันได้ตรวจสอบPOST
คำขอที่ส่งไปขณะตรวจสอบสิทธิ์ด้วย "เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์> เครือข่าย" เว็บไซต์ยอดนิยมหลายแห่ง (Reddit, HN และอื่น ๆ ) ยังคงส่งรหัสผ่านเป็นข้อความธรรมดาในPOST
คำขอ ( SSL-secure) (ดูภาพหน้าจอด้านล่าง)
วิธีการเข้าสู่ระบบนี้ยังคงเป็นมาตรฐานอุตสาหกรรมหรือไม่?
ทางเลือกต่อไปนี้ปลอดภัยกว่าการส่งรหัสผ่านข้อความธรรมดาผ่าน HTTPS หรือไม่?
การสมัคร: ไคลเอนต์สร้างแบบสุ่ม
salt
และส่งทูเพิล(username, salt, hash(plain_password + salt))
ผ่านการPOST
ร้องขอ จากนั้นรหัสผ่านข้อความธรรมดาจะไม่ไปถึงเซิร์ฟเวอร์การเข้าสู่ระบบที่ตามมา: เซิร์ฟเวอร์ต้องส่ง
salt
กลับไปยังไคลเอนต์ใด ๆที่พยายามเข้าสู่ระบบด้วยที่กำหนดusername
เพื่อให้ไคลเอนต์สามารถแฮชด้วยเกลือเดียวกันได้ ดังนั้นหมายความว่าเซิร์ฟเวอร์กำลังเปิดเผยsalt
ต่อทุกคนที่พยายามเข้าสู่ระบบด้วยชื่อผู้ใช้ที่กำหนดประโยชน์: เซิร์ฟเวอร์เก็บรหัสผ่านที่ถูกแฮช + เค็ม (ซึ่งเป็นมาตรฐาน) แต่เซิร์ฟเวอร์ยังไม่เคยเห็นรหัสผ่านข้อความธรรมดาเลยแม้แต่ครั้งเดียว (ดังนั้นหากเซิร์ฟเวอร์ถูกบุกรุกความเสี่ยงจะถูก จำกัด )
หมายเหตุ:
ตั้งแต่
H = hash(plain_password + salt)
ตอนนี้ทำงานนิด ๆ หน่อย ๆ เหมือนใหม่plaintext
(ดูคำตอบที่ 2 ของศูนย์ความรู้หลักฐานรหัสผ่าน: ทำไม hashing รหัสผ่านบนฝั่งไคลเอ็นต์ที่ไม่ได้เป็น ZKP ) แล้วตัดสามารถจัดเก็บในฐานข้อมูลแทน(username, salt, server_salt, hash(H + server_salt))
(username, salt, H)
เพื่อลดความเสี่ยงสำหรับการโจมตีซ้ำเซิร์ฟเวอร์ยังสามารถส่งข้อมูลที่ไม่ซ้ำกัน
nonce
พร้อมกับsalt
การเข้าสู่ระบบแต่ละครั้งที่หมดอายุหลังจากพยายามเข้าสู่ระบบหนึ่งครั้งเป้าหมายหลักที่นี่คือเซิร์ฟเวอร์ไม่เคยเข้าถึงรหัสผ่านข้อความธรรมดาหรือแฮชง่ายๆเลย (ซึ่งมักจะย้อนกลับด้วยตารางรุ้งเดียวสำหรับทั้งไซต์) ฉันตกลงกับความเสี่ยงที่ผู้โจมตีมีการคำนวณตารางรุ้งหนึ่งต่อผู้ใช้
ตัวอย่างการโจมตีที่ฉันต้องการลด: หากเซิร์ฟเวอร์สามารถเข้าถึงรหัสผ่านข้อความธรรมดาและถูกบุกรุก (ตัวอย่างเช่น Spectre / Meltdown vuln.) รหัสผ่านข้อความธรรมดาของผู้ใช้ (อาจใช้ซ้ำในเว็บไซต์อื่น) อาจถูกขโมยก่อนที่จะถูกเค็ม - แฮชและบันทึกลงในฐานข้อมูล
คำตอบ
ฉันไม่เห็นว่าข้อเสนอของคุณดีไปกว่าแนวทางการแฮชฝั่งไคลเอ็นต์ที่มีอยู่ แต่ฉันพบว่ามีความซับซ้อนในการนำไปใช้มากกว่าข้ออื่น ๆ น่าเสียดายที่คุณไม่ได้อธิบายถึงความเสี่ยงเฉพาะที่คุณพยายามเข้าถึงดังนั้นฉันจึงถือว่าภัยคุกคามทั่วไปที่พบเห็นได้ทั่วไป
Man in the Middle Attacker
ในกรณีนี้มันจะสันนิษฐานได้ว่าบางคนที่อยู่ตรงกลางที่มีการเข้าถึงการจราจรเช่นเพราะมันถูกบุกรุกบางสกัดกั้นการจราจร TLS ที่เชื่อถือได้ในไฟร์วอลล์ขององค์กรหรือได้ถือใน CA ที่เชื่อถือเช่นในกรณีของSuperfish
ในสถานการณ์สมมตินี้โจมตีได้รับการเข้าถึงเช่นเดียวกับที่พวกเขาทำมาก่อนด้วยH
plain_password
ตั้งแต่H
เป็นทุกสิ่งที่จำเป็นสำหรับการตรวจสอบผู้บุกรุกจะประสบความสำเร็จจึงและวิธีการของคุณไม่ได้เพิ่มการป้องกันใด ๆ เพิ่มเติมที่นี่
การซ่อนรหัสผ่านที่ไม่รัดกุมและการใช้รหัสผ่านซ้ำ
อาร์กิวเมนต์ทั่วไปสำหรับการแฮชฝั่งไคลเอ็นต์คือการไม่เปิดเผยรหัสผ่านที่อ่อนแอหรือใช้ซ้ำกับเซิร์ฟเวอร์ แต่ให้พิสูจน์ตัวตนด้วยรหัสผ่านที่ได้รับที่ซับซ้อนแทน แนวทางของคุณทำเช่นนี้ด้วยการแฮชplain_password
กับผู้ใช้บางรายที่สร้างแบบสุ่มsalt
จากนั้นส่งH
และsalt
ไปยังเซิร์ฟเวอร์ในการตั้งค่ารหัสผ่าน
แม้ว่าจะใช้งานได้ทุกการรับรองความถูกต้องในขณะนี้ต้องมีขั้นตอนเพิ่มเติม : ก่อนอื่นต้องดึงเกลือที่ใช้ก่อนหน้านี้สำหรับผู้ใช้จากผู้ใช้จากนั้นจึงสามารถใช้สิ่งนี้salt
เพื่อแฮชไฟล์plain_password
. ขั้นตอนเพิ่มเติมนี้ทำให้การพิสูจน์ตัวตนซับซ้อนขึ้นตั้งแต่แรกต้องตรวจสอบผู้ใช้กับเซิร์ฟเวอร์จากนั้นจึงตรวจสอบรหัสผ่านได้ นอกจากนี้การใช้งานที่ไม่สำคัญนี้จะเป็นการเปิดการรั่วไหลของข้อมูลเนื่องจากทำให้สามารถตรวจสอบได้ว่ามีผู้ใช้อยู่ตั้งแต่แรก (เกลือที่ส่งคืนหรือไม่) โดยไม่ต้องมีการตรวจสอบสิทธิ์เพิ่มเติม
การรั่วไหลของข้อมูลนี้สามารถปิดได้โดยเซิร์ฟเวอร์ส่งคืนเกลือบางส่วนไม่ว่าผู้ใช้จะมีอยู่หรือไม่ก็ตาม แน่นอนว่านี่ไม่สามารถเป็นเพียงเกลือแบบสุ่มได้เนื่องจากมิฉะนั้นผู้โจมตีสามารถตรวจสอบผู้ใช้คนเดียวกันได้สองครั้งและสรุปได้ว่าไม่มีผู้ใช้หากเกลือที่ส่งคืนแตกต่างกัน ดังนั้นเกลือจึงต้องได้รับการแก้ไขสำหรับผู้ใช้ที่ไม่มีอยู่นั่นคือได้มาจากชื่อผู้ใช้
และนี้ยังแสดงให้เห็นถึงเส้นทางไปสู่การลดความซับซ้อนของวิธีการของคุณ : แทนการสร้างเกลือสุ่มโดยผู้ใช้เก็บไว้ที่เซิร์ฟเวอร์และเรียกในภายหลังอีกครั้งหนึ่งก็อาจจะเป็นผลมาจากเกลือชื่อผู้ใช้ที่ฝั่งไคลเอ็นต์ ง่ายsalt=hash(username+domain)
จะเพียงพอที่จะสร้างเกลือซึ่งเป็นเอกลักษณ์ต่อโดเมนและทำให้ทั้งสองsalt
และH
ที่แตกต่างกันแม้ว่าusername
และplain_password
ได้นำกลับมาใช้ในโดเมนที่แตกต่างกัน และตรงกันข้ามกับแนวทางของคุณไม่จำเป็นต้องมีการเดินทางไปยังเซิร์ฟเวอร์เพิ่มเติมเพื่อดึงเกลือที่ใช้ก่อนหน้านี้ให้กับผู้ใช้ก่อน
กล่าวโดยย่อ: วิธีการที่เรียบง่ายนี้โดยทั่วไปจะส่งhash(plain_password+username+domain)
แทนรหัสผ่านเดิม โดเมนจะถูกเพิ่มเพื่อให้แน่ใจว่าแม้ว่าusername
และplain_password
จะนำกลับมาใช้ในโรงงานต่างๆรหัสผ่านมาที่ไม่ได้นำมาใช้ใหม่
นี่คือปัญหาที่โปรโตคอลเช่น PAKE และSRPมุ่งมั่นที่จะแก้ไข ด้วย PAKE / SRP ไคลเอนต์และเซิร์ฟเวอร์จะพิสูจน์ตัวตนซึ่งกันและกันตามรหัสผ่านที่ไคลเอ็นต์รู้จัก (และรหัสผ่านที่เซิร์ฟเวอร์รู้จัก)
ไคลเอ็นต์สาธิตให้เซิร์ฟเวอร์ทราบรหัสผ่านโดยที่ไคลเอ็นต์ไม่ส่งรหัสผ่าน (หรือข้อมูลที่เทียบเท่ารหัสผ่าน) ไปยังเซิร์ฟเวอร์ ในตอนท้ายของกระบวนการไคลเอนต์และเซิร์ฟเวอร์แชร์ความลับร่วมกัน
เซิร์ฟเวอร์ไม่เก็บรหัสผ่าน (หรือข้อมูลที่เทียบเท่ารหัสผ่าน) และไม่เสี่ยงต่อการโจมตีจากพจนานุกรม ผู้ดักฟังหรือ man-in-the-middle ที่สามารถดูข้อความธรรมดาที่ส่งผ่านสายจะไม่สามารถรับข้อมูลเพียงพอที่จะได้รับรหัสผ่าน วิธีนี้ช่วยป้องกันการโจมตีจากคนตรงกลางโดยใช้ใบรับรองปลอมได้อย่างมีประสิทธิภาพและป้องกันไม่ให้ไซต์ 'ฟิชชิง' ขโมยรหัสผ่านของผู้ใช้
หากต้องการทราบรายละเอียดที่ดีเกี่ยวกับวิธีการใช้ 1 รหัสผ่าน SRP โปรดดู https://blog.1password.com/developers-how-we-use-srp-and-you-can-too/
นอกจากคำตอบของ Steffen Ullrich :
หากในระหว่างการเข้าสู่ระบบผู้ใช้ส่งเฉพาะแฮชผู้โจมตีไม่จำเป็นต้องรู้รหัสผ่าน มันเพียงพอที่จะขโมยฐานข้อมูลรหัสผ่าน จากนั้นในระหว่างการร้องขอการเข้าสู่ระบบผู้โจมตีจะส่งแฮชจากฐานข้อมูล เซิร์ฟเวอร์จะไม่แยกความแตกต่างว่าไคลเอนต์ใช้รหัสผ่านและแฮชหรือหากไคลเอนต์ (ผู้โจมตี) เพียงแค่ส่งแฮช
บทความเกี่ยวกับที่อยู่ OPAQUE ก็มีปัญหาเช่นกัน: การขโมยฐานข้อมูลรหัสผ่านจะไม่ช่วยผู้โจมตี หนึ่งจะต้องรู้รหัสผ่านผู้ใช้ธรรมดา
หากผู้โจมตีโจมตีเซิร์ฟเวอร์ของคุณพวกเขาอยู่ในการควบคุมไม่เพียง แต่ซอฟต์แวร์ที่ทำงานบนเซิร์ฟเวอร์ของคุณเท่านั้น แต่ยังรวมถึงซอฟต์แวร์ที่ทำงานบนไคลเอนต์ด้วย
ไม่ว่าคุณจะออกแบบรูปแบบการรับรองความถูกต้องที่ออกแบบมาอย่างสวยงามผู้โจมตีสามารถแก้ไขได้ก่อนที่จะส่งไปยังเบราว์เซอร์
ตอนนี้คุณมีปัญหาไก่ไข่: คุณไม่สามารถรักษารหัสผ่านให้ปลอดภัยได้หากผู้โจมตีควบคุมวิธีรวบรวมและส่งไปยังเซิร์ฟเวอร์ของคุณ
หากคุณกังวลเกี่ยวกับการละเมิดข้อมูลวิธีการของคุณจะใช้เป็นการป้องกัน แต่รหัสผ่านที่เหมาะสมก็จะแฮชฝั่งเซิร์ฟเวอร์เช่นกัน
หากคุณกังวลเกี่ยวกับการโจมตีของ MITM TLS จะแก้ไขได้
หากคุณกังวลเกี่ยวกับการโจมตี MITM บน TLS อย่างที่ฉันอยากจะบอกว่าการป้องกันที่ดีต่อพวกเขามักจะเริ่มต้นด้วยคู่มือ Krav Maga ผู้โจมตีที่มีทรัพยากรเพียงพอที่จะทำลาย TLS ได้อย่างต่อเนื่องไม่มีปัญหาในการได้รับสิ่งที่ต้องการจากบุคคลที่ไม่ได้รับการฝึกฝนอย่างถูกต้องและได้รับการฝึกฝนมาเป็นพิเศษ (ใช่ฉันกำลังพูดถึงการทรมานการแบล็กเมล์การลักพาตัวและการฆาตกรรม)
หากคุณกังวลเกี่ยวกับผู้คุกคามที่สามารถอ่านได้เฉพาะข้อมูลที่เซิร์ฟเวอร์ได้รับมาแนวทางของคุณ (ตามที่ Steffen แก้ไขแล้ว) จะต่อต้านพวกเขา อย่างไรก็ตามนี่เป็นสถานการณ์ที่แปลกและหายากซึ่งมักเกิดจากเซิร์ฟเวอร์ที่กำหนดค่าผิดอย่างร้ายแรงและแนวทางปฏิบัติที่ไม่ดีในการพัฒนา (เช่นการส่งข้อมูลรับรองผ่านคำขอ GET และการจัดเก็บบันทึกการเข้าถึงแบบสาธารณะ) การแก้ไขข้อผิดพลาดเหล่านี้ง่ายกว่าการคิดค้นโปรโตคอลเพียงเพื่อจัดการกับข้อผิดพลาดเหล่านี้
โปรดทราบว่าช่องโหว่ทั้งสองที่คุณกล่าวถึง (จริงๆแล้วเป็นเพียงช่องโหว่เดียวเนื่องจาก Meltdown เป็นตัวแปรทางเทคนิคของ Spectre) ในที่สุดจะส่งผลให้มีการเพิ่มสิทธิ์ในพื้นที่ทำให้ผู้โจมตีสามารถควบคุมเว็บเซิร์ฟเวอร์ของคุณได้อย่างเต็มที่ เน้นย้ำอีกครั้งว่าสถานการณ์ที่ผู้โจมตีเข้าถึงข้อมูลที่ได้รับจากเว็บเซิร์ฟเวอร์ของคุณนั้นหายากเพียงใด
ดังนั้นเหตุผลที่ไซต์ใหญ่ ๆ หลายแห่งไม่ใช้มันเป็นเพราะมันไม่ได้เพิ่มอะไรเลยนอกจากในสถานการณ์เฉพาะที่มักจะมีการกำหนดค่าผิดพลาด นอกจากนี้ยังเป็นที่น่าสังเกตว่าหากผู้โจมตีสามารถอ่านข้อมูลที่กำลังเปลี่ยนไปที่เซิร์ฟเวอร์ของคุณได้แสดงว่าคุณเป็นฝ่ายแพ้ของเกม โปรดทราบว่าเป็นเรื่องดีที่จะมีการป้องกันแบบหลายชั้น แต่เป้าหมายหลักของคุณไม่ใช่ให้เกิดขึ้นตั้งแต่แรก และการมุ่งเน้นไปที่สิ่งนั้นจะช่วยให้คุณไม่ต้องคิดค้นแผนการใหม่ ๆ
อย่างไรก็ตามตามที่ Steffen แสดงให้เห็นว่าแผนการที่คุณเสนออาจใช้รูปแบบการโจมตีแปลก ๆ ได้อีก ฉันจะยังคงใช้hash(hash(domain + username) + password)
แทนที่จะใช้hash(domain + username + password)
เพื่อควบคุมความเป็นไปได้ระยะไกลที่domain + username + password
ยังคงเป็นคำในพจนานุกรม
ดังที่ mti2935 แสดงให้เห็นว่า SRP เป็นทางเลือกที่น่าสนใจกว่า การรับรองความถูกต้องโดยใช้ใบรับรอง (เช่นการจัดการโดยเบราว์เซอร์) เป็นอีกทางเลือกหนึ่ง (ซึ่งฉันพบว่าดีกว่าการทำด้วยตนเองในสคริปต์ JS ที่อาจปนเปื้อนซึ่งอาจเป็นอันตรายตามที่คุณเสนอไว้ในความคิดเห็น)