bcrypt มีเกลือในตัวได้อย่างไร


617

บทความของ Coda Hale "วิธีเก็บรหัสผ่านอย่างปลอดภัย"อ้างว่า:

bcrypt มีเกลือในตัวเพื่อป้องกันการโจมตีของตารางสายรุ้ง

เขาอ้างอิงบทความนี้ซึ่งกล่าวว่าในการดำเนินการของ OpenBSD bcrypt:

OpenBSD สร้างเกลือ bcrypt 128- บิตจากกระแสหลักของ arcfour (arc4random (3)) ซึ่งประกอบด้วยข้อมูลแบบสุ่มที่เคอร์เนลรวบรวมจากการจับเวลาอุปกรณ์

ฉันไม่เข้าใจวิธีการทำงานนี้ ในความคิดของฉันของเกลือ:

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

เมื่อฉันใช้ Devise (ผู้จัดการการเข้าสู่ระบบ Rails) กับ bcrypt ไม่มีคอลัมน์เกลือในฐานข้อมูลดังนั้นฉันจึงสับสน หากเกลือถูกสุ่มและไม่ได้เก็บไว้ที่ใดเราจะทำขั้นตอนการแฮชซ้ำได้อย่างน่าเชื่อถือได้อย่างไร

ในระยะสั้นbcrypt สามารถมีเกลือในตัวได้อย่างไร

คำตอบ:


789

นี่คือ bcrypt:

สร้างเกลือสุ่ม ปัจจัย "ต้นทุน" ได้รับการกำหนดค่าล่วงหน้า รวบรวมรหัสผ่าน

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

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

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


เก็บไว้ในฐานข้อมูลbcrypt"แฮช" อาจมีลักษณะดังนี้:

$ 2a $ 10 $ vI8aWBnW3fID.ZQ4 / zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

นี่เป็นสามฟิลด์จริงๆคั่นด้วย "$":

  • 2aระบุbcryptรุ่นอัลกอริทึมที่ใช้
  • 10เป็นปัจจัยต้นทุน 2 10การใช้ฟังก์ชั่นการสืบทอดคีย์ (ซึ่งไม่เพียงพอโดยวิธีฉันขอแนะนำค่าใช้จ่าย 12 หรือมากกว่า)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTaคือเกลือและข้อความตัวเลข, ตัดแบ่งและเข้ารหัสใน Base-64 ที่ดัดแปลง อักขระ 22 ตัวแรกถอดรหัสเป็นค่า 16 ไบต์สำหรับเกลือ อักขระที่เหลือเป็นข้อความรหัสที่จะนำมาเปรียบเทียบเพื่อการตรวจสอบความถูกต้อง

ตัวอย่างนี้นำมาจากเอกสารประกอบการใช้ทับทิมของ Coda Hale


7
คุณจะมีรายละเอียดเพิ่มเติมว่าทำไมปัจจัยต้นทุน 10 ไม่เพียงพอหรือไม่ ใน Grails ฉันสังเกตเห็นว่า 10 เป็นค่าเริ่มต้นสำหรับ cost factor / รอบการบันทึกสำหรับ bcrypt ดังนั้นจึงควรปรับปรุงตามคำแนะนำของคุณ
pm_labs

57
ปัจจัยต้นทุนสำหรับ bcrypt นั้นเป็นแบบเอ็กซ์โพเนนเชียลหรือมากกว่านั้นคือปัจจัยต้นทุน 10 หมายถึง 2 ^ 10 รอบ (1024), ปัจจัยต้นทุนของ 16 จะหมายถึง 2 ^ 16 รอบ (65536) มันเป็นธรรมชาติแล้วจะใช้เวลา 5-10 วินาที ควรใช้เวลาประมาณ 64 ครั้งตราบใดที่ค่าใช้จ่ายเท่ากับ 10 เพื่อล้างข้อมูลที่ผิดอื่นฟังก์ชัน crypt ของ PHP ใช้ไลบรารี crypt unix ซึ่งนำมาใช้ใน c
thomasrutter

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

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

1
@NLV มันเป็นสตริงที่กำหนดไว้ในสเปค bcrypt:"OrpheanBeholderScryDoubt"
erickson

182

ฉันเชื่อว่าวลีควรได้รับการใช้คำดังต่อไปนี้

bcrypt มีเกลืออยู่ในแฮชที่สร้างขึ้นเพื่อป้องกันการโจมตีแบบสายรุ้ง

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


20
ตกลงดังนั้นฉันสมัครไซต์และเลือกรหัสผ่าน "foo" Bcryptเพิ่มเกลือแบบสุ่มของ "akd2! *" ส่งผลให้ "fooakd2! *" ซึ่งถูกแฮชและเก็บไว้ ต่อมาฉันพยายามลงชื่อเข้าใช้ด้วยรหัสผ่าน "บาร์" หากต้องการดูว่าฉันถูกต้องจะต้องแฮ "barakd2! *" หากเกลือถูกสร้างขึ้นแบบสุ่มเพื่อเริ่มต้นจะทราบได้อย่างไรว่าจะเพิ่มกลับไปที่ "บาร์" ก่อนที่จะ hashing และเปรียบเทียบได้อย่างไร
นาธานลอง

46
@Nathan: bcryptรู้วิธีแยกเกลือออกจากเอาต์พุตที่สร้างขึ้น (ซึ่งเก็บไว้ในฐานข้อมูล) เมื่อถึงเวลาที่ต้องรับรองความถูกต้องให้bcryptแยกเอาท์พุทต้นฉบับออกเป็นองค์ประกอบแฮชและเกลือ ส่วนประกอบของเกลือถูกนำไปใช้กับรหัสผ่านขาเข้าที่พิมพ์โดยผู้ใช้
Adam Paynter

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

11
@ นาธาน แต่ผู้โจมตีสามารถลบเกลือที่รู้จักในรหัสผ่านทั้งหมดแล้วสร้างตารางกับพวกเขาได้หรือไม่?
ออสการ์

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

0

เพื่อให้สิ่งต่าง ๆ ชัดเจนยิ่งขึ้น

ทิศทางการลงทะเบียน / เข้าสู่ระบบ ->

รหัสผ่าน + เกลือถูกเข้ารหัสด้วยรหัสที่สร้างขึ้นจาก: ต้นทุนเกลือและรหัสผ่าน cipher textที่เราเรียกว่าการเข้ารหัสค่า จากนั้นเราแนบเกลือกับค่านี้และเข้ารหัสโดยใช้ base64 แนบค่ากับมันและนี่คือสตริงที่ผลิตจากbcrypt:

$2a$COST$BASE64

ค่านี้จะถูกเก็บไว้ในที่สุด

ผู้โจมตีจะต้องทำอย่างไรจึงจะสามารถค้นหารหัสผ่านได้ (ทิศทางอื่น <-)

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

มีความสำคัญมากกว่า: ไม่มีการแฮ็กในกระบวนการนี้ แต่เป็นการเข้ารหัสที่มีราคาแพงของ CPU - การถอดรหัส ตารางรุ้งจึงเกี่ยวข้องน้อยกว่าที่นี่


-2

นี่คือจากเอกสารประกอบอินเตอร์เฟสของ PasswordEncoder จาก Spring Security

 * @param rawPassword the raw password to encode and match
 * @param encodedPassword the encoded password from storage to compare with
 * @return true if the raw password, after encoding, matches the encoded password from
 * storage
 */
boolean matches(CharSequence rawPassword, String encodedPassword);

ซึ่งหมายความว่าจะต้องตรงกับ rawPassword ที่ผู้ใช้จะป้อนอีกครั้งเมื่อเข้าสู่ระบบถัดไปและจับคู่กับรหัสผ่านที่เข้ารหัส Bcrypt ที่เก็บในฐานข้อมูลในระหว่างการเข้าสู่ระบบ / การลงทะเบียนก่อนหน้า


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