ชนิดข้อมูลใดที่จะใช้สำหรับฟิลด์รหัสผ่านที่แฮชและความยาวเท่าใด


268

ฉันไม่แน่ใจว่ารหัสผ่านการแฮชทำงานอย่างไร (จะนำมาใช้ในภายหลัง) แต่ต้องสร้างสคีมาฐานข้อมูลทันที

ฉันคิดถึงการ จำกัด รหัสผ่านให้เหลือเพียง 4-20 ตัวอักษร แต่อย่างที่ฉันเข้าใจหลังจากเข้ารหัสสตริงแฮชจะมีความยาวต่างกัน

ดังนั้นวิธีการเก็บรหัสผ่านเหล่านี้ในฐานข้อมูล?


ดูที่กรอบการแฮชรหัสผ่าน PHPของ Openwall (PHPass) แบบพกพาและแข็งต่อการโจมตีทั่วไปจำนวนมากในรหัสผ่านผู้ใช้ คนที่เขียนกรอบ (SolarDesigner) เป็นคนเดียวกับที่เขียนจอห์นเดอะริปเปอร์และนั่งเป็นผู้พิพากษาในรหัสผ่าน Hashing การแข่งขัน ดังนั้นเขาจึงรู้สิ่งหนึ่งหรือสองเกี่ยวกับการโจมตีรหัสผ่าน
jww

2
โปรดอย่า จำกัด รหัสผ่านของคุณ คุณกำลังแฮ็ชพวกเขาไม่มีเหตุผลในการจัดเก็บสำหรับขีด จำกัด บน หากคุณกังวลเกี่ยวกับการโจมตี DoS โดยใช้แฮชรหัสผ่าน 1,000 หรือ 1024 เป็นขีด จำกัด บนที่สมเหตุสมผล
Iiridayn

เหตุใดจึงจำกัดความยาวของรหัสผ่าน อย่างน้อยให้ผู้ใช้สร้างรหัสผ่านที่ 100 ตัวอักษร :)
แอนดรู

ตัวละคร 4 ตัวนั้นอันตรายน้อยมากสำหรับรหัสผ่านเนื่องจากรหัสผ่านมีความแตกต่างเล็กน้อย อย่างน้อยที่สุดก็ใช้ 8 แต่ 14 หรือ 16 ดีกว่ามาก
quikchange

นี่เป็นคำถามเก่าแก่ที่มีคำตอบที่ล้าสมัย ดูคำตอบของ Gilles เพื่อทราบข้อมูลล่าสุด
kelalaka

คำตอบ:


448

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

สำหรับรหัสผ่านให้ใช้อัลกอริทึมแฮชที่เพิ่มความแข็งแกร่งเช่น Bcrypt หรือ Argon2i ตัวอย่างเช่นใน PHP ใช้ฟังก์ชัน password_hash ()ซึ่งใช้ Bcrypt เป็นค่าเริ่มต้น

$hash = password_hash("rasmuslerdorf", PASSWORD_DEFAULT);

ผลลัพธ์ที่ได้คือสตริงที่มีความยาว 60 ตัวอักษรคล้ายกับที่แสดงต่อไปนี้ (แต่ตัวเลขจะแตกต่างกันไปเพราะมันสร้างเกลือที่ไม่ซ้ำกัน)

$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

ใช้ชนิดข้อมูล SQL CHAR(60)เพื่อเก็บการเข้ารหัสแฮช Bcrypt นี้ หมายเหตุฟังก์ชั่นนี้ไม่ได้เข้ารหัสเป็นสตริงของเลขฐานสิบหกดังนั้นเราจึงไม่สามารถ unhex เก็บไว้ในไบนารีได้อย่างง่ายดาย

ฟังก์ชันแฮชอื่น ๆ ยังคงมีการใช้งานอยู่ แต่ไม่ใช่สำหรับการจัดเก็บรหัสผ่านดังนั้นฉันจะเก็บคำตอบดั้งเดิมไว้ด้านล่างซึ่งเขียนในปี 2008


ขึ้นอยู่กับอัลกอริทึมการแปลงแป้นพิมพ์ที่คุณใช้ การแฮ็ชสร้างผลลัพธ์ที่มีความยาวเท่ากันเสมอโดยไม่คำนึงถึงอินพุต มันเป็นเรื่องปกติที่จะเป็นตัวแทนของผลการแฮชไบนารีในข้อความเป็นชุดของตัวเลขฐานสิบหก หรือคุณสามารถใช้UNHEX()ฟังก์ชั่นเพื่อลดสตริงของเลขฐานสิบหกลงครึ่งหนึ่ง

  • MD5 สร้างค่าแฮช 128 บิต คุณสามารถใช้ CHAR (32) หรือ BINARY (16)
  • SHA-1 สร้างค่าแฮช 160 บิต คุณสามารถใช้ CHAR (40) หรือ BINARY (20)
  • SHA-224 สร้างค่าแฮช 224 บิต คุณสามารถใช้ CHAR (56) หรือ BINARY (28)
  • SHA-256 สร้างค่าแฮช 256 บิต คุณสามารถใช้ CHAR (64) หรือ BINARY (32)
  • SHA-384 สร้างค่าแฮช 384 บิต คุณสามารถใช้ CHAR (96) หรือ BINARY (48)
  • SHA-512 สร้างค่าแฮช 512 บิต คุณสามารถใช้ CHAR (128) หรือ BINARY (64)
  • BCrypt สร้างค่าแฮชที่ขึ้นอยู่กับการนำไปใช้งาน 448 บิต คุณอาจต้องการ CHAR (56), CHAR (60), CHAR (76), BINARY (56) หรือ BINARY (60)

ตั้งแต่ปี 2015 NIST แนะนำให้ใช้ SHA-256 หรือสูงกว่าสำหรับแอปพลิเคชันของฟังก์ชันแฮชที่ต้องการการทำงานร่วมกัน แต่ NIST ไม่แนะนำให้ใช้ฟังก์ชันแฮชแบบง่ายเหล่านี้ในการจัดเก็บรหัสผ่านอย่างปลอดภัย

อัลกอริธึมการแฮชที่น้อยกว่ามีการใช้งาน (เช่นภายในแอปพลิเคชันไม่ใช่เพื่อการแลกเปลี่ยน) แต่เป็นที่ทราบกันดีว่าสามารถถอดรหัสได้


47
@Hippo: โปรดอย่าใช้ชื่อผู้ใช้เป็นเกลือ สร้างเกลือสุ่มต่อผู้ใช้
Bill Karwin

11
ใช่ไม่มีเหตุผลที่จะไม่เก็บไว้ในแถวเดียวกัน แม้ว่าผู้โจมตีจะสามารถเข้าถึงฐานข้อมูลของคุณได้ แต่พวกเขาจำเป็นต้องสร้างตารางสายรุ้งตามเกลือนั้น และนี่เป็นเพียงการคาดเดารหัสผ่าน
Bill Karwin

5
@SgtPooki: คุณต้องการอีกคอลัมน์หนึ่งเพื่อเก็บเกลือไว้ในรูปแบบธรรมดา จากนั้นคุณสามารถแฮชรหัสผ่านของผู้ใช้ด้วยเกลือเดียวกันเมื่อพวกเขาพิมพ์และเปรียบเทียบผลกับแฮชย่อยที่เก็บไว้ในตาราง
Bill Karwin

12
หากคุณกำลังเก็บเกลือไว้ในตารางเดียวกัน (หรือตำแหน่งอื่น ๆ ที่มีสิทธิ์การเข้าถึงเดียวกัน) ไม่มีเหตุผลที่จะไม่ใช้ชื่อผู้ใช้เป็นเกลือเพราะมันจะไม่ซ้ำกันต่อผู้ใช้ อย่างไรก็ตามเกลือที่รู้จักกันดีใด ๆ ที่ทำให้กัญชานั้นอ่อนแอกว่าหากไม่มีเกลือที่รู้จัก เกลือจะเพิ่มมูลค่าก็ต่อเมื่อไม่ทราบเช่นกัน
fijiaaron

9
ฉันไม่เข้าใจข้อตกลงกับเกลือที่รู้จักและไม่รู้จัก หากคุณกำลังใช้งานเว็บไซต์คุณจำเป็นต้องทราบถึงหน้าเกลือ / script / sevice ที่ใช้ทดสอบรหัสผ่าน ดังนั้น - คุณสนับสนุนเกลือ "ไม่รู้จัก" - คุณคิดว่ารหัสสำหรับกระบวนการเข้าสู่ระบบไม่เป็นที่รู้จักของผู้โจมตีหรือไม่? ไม่เช่นนั้น - ผู้โจมตีจะไม่รู้จักเกลือเสมอไม่ว่าจะเป็นแบบสุ่มไม่ซ้ำกันจัดเก็บพร้อมรหัสผ่านที่แฮชหรือแยกจากกัน
mattstuehler

13

คุณสามารถใช้CHAR(ความยาวของแฮช)เพื่อกำหนดประเภทข้อมูลของคุณสำหรับ MySQL ได้เนื่องจากอัลกอริทึมการแฮชแต่ละครั้งจะประเมินจำนวนอักขระที่เท่ากันเสมอ ตัวอย่างเช่นSHA1ส่งกลับตัวเลขฐานสิบหก 40 ตัวเสมอ


1
SHA-1 ไม่เหมาะสำหรับการแฮ็กรหัสผ่าน
Gilles 'ดังนั้นหยุดความชั่วร้าย'

10

ใช้อัลกอริทึมการแฮชรหัสผ่านทุกครั้ง: Argon2 , scrypt , bcryptหรือ PBKDF2

Argon2ชนะการแข่งขัน hashing รหัสผ่าน 2015 Scrypt , bcryptและ PBKDF2เป็นอัลกอริทึมที่เก่ากว่าซึ่งถือว่าเป็นที่ต้องการน้อยลงในขณะนี้ แต่ก็ยังฟังดูดีกว่าดังนั้นหากแพลตฟอร์มของคุณไม่รองรับ Argon2 คุณก็สามารถใช้อัลกอริทึมอื่นได้แล้ว

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

กัญชารหัสผ่านมีคุณสมบัติที่แตกต่างจากกัญชาตารางแฮชหรือกัญชาเข้ารหัสลับ อย่าใช้แฮชการเข้ารหัสลับทั่วไปเช่น MD5, SHA-256 หรือ SHA-512 ในรหัสผ่าน อัลกอริทึมการแฮชรหัสผ่านใช้เกลือซึ่งเป็นลักษณะเฉพาะ (ไม่ได้ใช้สำหรับผู้ใช้รายอื่นหรือในฐานข้อมูลของผู้อื่น) จำเป็นต้องมีเกลือเพื่อให้ผู้โจมตีไม่สามารถคำนวณแฮชของรหัสผ่านทั่วไปล่วงหน้าได้ด้วยเกลือพวกเขาต้องเริ่มการคำนวณใหม่สำหรับทุกบัญชี อัลกอริทึมการแฮชรหัสผ่านนั้นช้ามาก - ช้าที่สุดเท่าที่จะทำได้ ความเชื่องช้าทำให้ผู้โจมตีทำร้ายมากกว่าคุณเพราะผู้โจมตีต้องลองใช้รหัสผ่านที่แตกต่างกันมากมาย สำหรับข้อมูลเพิ่มเติมโปรดดูที่วิธีการรหัสผ่านกัญชาปลอดภัย

แฮชรหัสผ่านเข้ารหัสข้อมูลสี่ส่วน:

  • ตัวบ่งชี้ของอัลกอริทึมที่ใช้ นี่เป็นสิ่งจำเป็นสำหรับความคล่องตัว : คำแนะนำการเข้ารหัสเปลี่ยนไปตามกาลเวลา คุณต้องสามารถเปลี่ยนเป็นอัลกอริทึมใหม่
  • ตัวบ่งชี้ความยากลำบากหรือความแข็ง ยิ่งค่านี้สูงขึ้นเท่าใดการคำนวณก็ยิ่งจำเป็นต้องมีการคำนวณแฮช นี่ควรเป็นค่าคงที่หรือการกำหนดค่าส่วนกลางในฟังก์ชั่นการเปลี่ยนรหัสผ่าน แต่ควรเพิ่มขึ้นเมื่อเวลาผ่านไปเมื่อคอมพิวเตอร์เร็วขึ้นดังนั้นคุณต้องจำค่าสำหรับแต่ละบัญชี อัลกอริทึมบางตัวมีค่าตัวเลขเดียวส่วนอื่น ๆ มีพารามิเตอร์เพิ่มเติมที่นั่น (ตัวอย่างเช่นเพื่อปรับการใช้งาน CPU และการใช้ RAM แยกต่างหาก)
  • เกลือ. เนื่องจากเกลือจะต้องไม่ซ้ำกันทั่วโลกจึงต้องเก็บไว้สำหรับแต่ละบัญชี ควรสร้างเกลือแบบสุ่มในการเปลี่ยนรหัสผ่านแต่ละครั้ง
  • แฮชที่เหมาะสมคือผลลัพธ์ของการคำนวณทางคณิตศาสตร์ในอัลกอริทึมการแปลงแป้นพิมพ์

ห้องสมุดหลายแห่งมีฟังก์ชั่นการจับคู่ที่สะดวกในการบรรจุข้อมูลนี้เป็นสายเดี่ยว: อันที่ใช้ตัวบ่งชี้อัลกอริทึม, ตัวบ่งชี้ความแข็งและรหัสผ่าน, สร้างเกลือแบบสุ่มและส่งคืนแฮชสตริงเต็ม และอีกอันที่ใช้รหัสผ่านและสตริงแฮชแบบเต็มเป็นอินพุตและส่งคืนบูลีนที่ระบุว่ารหัสผ่านนั้นถูกต้อง ไม่มีมาตรฐานสากล แต่การเข้ารหัสทั่วไปคือ

$ อัลกอริทึม $ พารามิเตอร์ $ เกลือ $เอาท์พุท

โดยที่algorithmเป็นตัวเลขหรือสตริงตัวอักษรผสมตัวเลขสั้น ๆ ที่เลือกใช้อัลกอริทึมparametersเป็นสตริงที่พิมพ์ได้และsaltและoutputถูกเข้ารหัสใน Base64 โดยไม่ยกเลิก=โดยไม่ต้องยกเลิก

16 ไบต์เพียงพอสำหรับเกลือและเอาท์พุท (ดูเช่นคำแนะนำสำหรับ Argon2 ) เข้ารหัสใน Base64 นั่นคือ 21 ตัวอักษรแต่ละตัว อีกสองส่วนขึ้นอยู่กับอัลกอริทึมและพารามิเตอร์ แต่ตัวอักษร 20–40 เป็นเรื่องปกติ นั่นคือทั้งหมดประมาณ 82 อักขระ ASCII ( CHAR(82)และไม่จำเป็นต้องใช้ Unicode) ซึ่งคุณควรเพิ่มระยะขอบความปลอดภัยถ้าคุณคิดว่ามันยากที่จะขยายสนามในภายหลัง

หากคุณเข้ารหัสแฮชในรูปแบบไบนารี่คุณสามารถลดขนาดได้ถึง 1 ไบต์สำหรับอัลกอริธึม, 1–4 ไบต์สำหรับความแข็ง (ถ้าคุณเขียนโค้ดพารามิเตอร์บางตัว) และ 16 ไบต์สำหรับเกลือและเอาท์พุท รวมเป็น 37 ไบต์ พูด40 ไบต์ (BINARY(40) ) ให้มีอย่างน้อยสองสามไบต์ โปรดทราบว่าสิ่งเหล่านี้เป็นไบต์ 8 บิตไม่ใช่อักขระที่พิมพ์ได้โดยเฉพาะอย่างยิ่งฟิลด์สามารถรวมไบต์ว่าง

โปรดทราบว่าความยาวของแฮชไม่เกี่ยวข้องกับความยาวของรหัสผ่านโดยสมบูรณ์


9

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


2
มันคุ้มค่ามากจริงๆ (+1) แต่มันไม่ตอบคำถาม! (-1)
Bill Karwin

3
ใช่ แต่มีความเกี่ยวข้องอย่างแน่นอนในบริบทนี้ (+1)
Treb

7

เป็นสตริงที่มีความยาวคงที่ (VARCHAR (n) หรือ MySQL เรียกว่า) แฮชมีความยาวคงที่เสมอตัวอย่างเช่น 12 อักขระ (ขึ้นอยู่กับอัลกอริทึมแฮชที่คุณใช้) ดังนั้นรหัสผ่าน 20 อักขระจะถูกลดลงเป็น 12 อักขระแฮชและรหัสผ่าน 4 อักขระก็จะให้แฮช 12 อักขระ


3
'หรือ MySQL เรียกว่า' - MySQL เรียกว่า CHAR ชนิดนี้ใช้สำหรับค่าความยาวคงที่ ดังนั้นฉันคิดว่า CHAR ดีกว่า VARCHAR
t298712383

4

คุณควรใช้TEXT(การจัดเก็บอักขระไม่ จำกัด จำนวน) เพื่อความเข้ากันได้ของฟอร์เวิร์ด อัลกอริทึมการแปลงแป้นพิมพ์ (จำเป็น) จะแข็งแกร่งขึ้นเมื่อเวลาผ่านไปและฟิลด์ฐานข้อมูลนี้จะต้องสนับสนุนอักขระมากขึ้นเมื่อเวลาผ่านไป นอกจากนี้ขึ้นอยู่กับกลยุทธ์การย้ายข้อมูลของคุณคุณอาจต้องเก็บแฮชใหม่และเก่าในฟิลด์เดียวกันดังนั้นไม่แนะนำให้กำหนดความยาวเป็นแฮชประเภทหนึ่ง


3

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


3

แฮชคือลำดับของบิต (128 บิต 160 บิต 256 บิต ฯลฯ ขึ้นอยู่กับอัลกอริทึม) คอลัมน์ของคุณควรเป็นแบบไบนารีไม่ใช่ข้อความ / ตัวอักษรพิมพ์ถ้า MySQL อนุญาต (ประเภทข้อมูล SQL Server เป็นbinary(n)หรือvarbinary(n)) คุณควรเค็มเกลือ เกลืออาจเป็นข้อความหรือไบนารีและคุณจะต้องมีคอลัมน์ที่เกี่ยวข้อง


ความยุติธรรมถูกต้องอย่างสมบูรณ์ที่นี่ - MySQL จะเก็บค่าเหล่านี้เป็นค่าตัวเลขและจะทำการค้นหาในคอลัมน์นี้มีประสิทธิภาพมากกว่าการจับคู่สตริง แต่เกลือไม่ควรเก็บไว้ในฐานข้อมูลข้างข้อมูลเกลือซึ่งช่วยขจัดความปลอดภัยที่เกลือให้ .
Tony Maro

6
เกลือไม่ใช่ความลับ เพียงความลับคือรหัสผ่าน เพียงตรวจสอบให้แน่ใจว่ารหัสผ่านใหม่ทุกอันได้รับเกลือใหม่ ทุกครั้งที่ผู้ใช้เปลี่ยนรหัสผ่านระบบควรสร้างเกลือใหม่สำหรับรหัสผ่านนั้น เกลือควรมีความยาวและแบบสุ่มเช่น 16 ไบต์ที่สร้างจาก PRNG ที่ปลอดภัยด้วยการเข้ารหัส
yfeldblum

1
@TonyMaro ไม่แน่ใจว่าสตริงรหัสผ่านตรงกันกับระดับ SQL เป็นกลยุทธ์ที่ดีหรือไม่ กล่าวอีกนัยหนึ่งคุณไม่ควรค้นหารหัสผ่านของฐานข้อมูลของคุณแทนที่จะดึงผู้ใช้ตามชื่อผู้ใช้ของเขาและเปรียบเทียบรหัสผ่านเป็นรหัสแทนที่จะเป็น SQL
บาร์ต

1

ฉันทดสอบเสมอเพื่อค้นหาความยาวสตริงสูงสุดของสตริงเข้ารหัสและตั้งค่าเป็นความยาวอักขระของประเภท VARCHAR ขึ้นอยู่กับจำนวนระเบียนที่คุณจะมีมันสามารถช่วยขนาดฐานข้อมูลได้จริง


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