แฮชและเกลือที่ปลอดภัยสำหรับรหัสผ่าน PHP


1174

ปัจจุบันมีการกล่าวกันว่า MD5 นั้นไม่ปลอดภัยบางส่วน เมื่อคำนึงถึงเรื่องนี้ฉันต้องการทราบว่ากลไกใดที่จะใช้สำหรับการป้องกันรหัสผ่าน

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

ฉันใช้ PHP ฉันต้องการระบบเข้ารหัสรหัสผ่านที่ปลอดภัยและรวดเร็ว การแฮ็กรหัสผ่านเป็นล้านครั้งอาจปลอดภัยกว่า แต่ก็ช้าลงเช่นกัน วิธีการบรรลุสมดุลที่ดีระหว่างความเร็วและความปลอดภัย? นอกจากนี้ฉันต้องการผลลัพธ์ที่จะมีจำนวนตัวอักษรคงที่

  1. กลไกการแปลงแป้นพิมพ์ต้องพร้อมใช้งานใน PHP
  2. มันจะต้องปลอดภัย
  3. มันสามารถใช้เกลือได้ (ในกรณีนี้เกลือทั้งหมดนั้นดีเท่ากันหรือไม่มีวิธีใดที่จะสร้างเกลือที่ดี?)

นอกจากนี้ฉันควรเก็บสองฟิลด์ในฐานข้อมูล (ตัวอย่างเช่นใช้ MD5 และอีกฟิลด์หนึ่งใช้ SHA เป็นต้น) มันจะทำให้ปลอดภัยหรือไม่ปลอดภัยหรือไม่?

ในกรณีที่ฉันยังไม่ชัดเจนพอฉันต้องการทราบว่าควรใช้ฟังก์ชัน hashing ใดและวิธีเลือกเกลือที่ดีเพื่อให้มีกลไกการป้องกันรหัสผ่านที่ปลอดภัยและรวดเร็ว

คำถามที่เกี่ยวข้องที่ไม่ค่อยครอบคลุมคำถามของฉัน:

ความแตกต่างระหว่าง SHA และ MD5 ในการ
เข้ารหัสรหัสผ่านPHP อย่างง่าย
วิธีการรักษาความปลอดภัยในการจัดเก็บคีย์รหัสผ่านสำหรับ asp.net
คุณจะใช้รหัสผ่านเค็มใน Tomcat 5.5 อย่างไร


13
openwall.com/phpassเป็นห้องสมุดที่ดีมากด้วย
Alfred

51
Md5 ไม่ปลอดภัยอย่างสมบูรณ์ในขณะนี้
JqueryToAddNumbers

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

12
PHP 5.5+ มีแฮชรหัสผ่านที่ปลอดภัยที่สร้างขึ้นในphp.net/manual/en/function.password-hash.php
Terence Johnson

คำตอบ:


982

การปฏิเสธความรับผิด : คำตอบนี้ถูกเขียนในปี 2008

ตั้งแต่นั้นมา PHP ได้ให้เราpassword_hashและpassword_verifyและตั้งแต่การแนะนำพวกเขาพวกเขาเป็นวิธีการแฮชรหัสผ่านและตรวจสอบที่แนะนำ

ทฤษฎีของคำตอบยังคงอ่านได้ดี

TL; DR

Don'ts

  • อย่า จำกัด สิ่งที่ผู้ใช้สามารถป้อนรหัสผ่านได้ คนโง่เท่านั้นที่ทำสิ่งนี้
  • อย่าจำกัดความยาวของรหัสผ่าน หากผู้ใช้ของคุณต้องการประโยคที่มี supercalifragilisticexpialidocious อยู่ในนั้นอย่าป้องกันพวกเขาจากการใช้มัน
  • อย่าดึงหรือหนี HTML และอักขระพิเศษในรหัสผ่าน
  • อย่าเก็บรหัสผ่านของผู้ใช้เป็นข้อความธรรมดา
  • อย่าส่งอีเมลรหัสผ่านให้กับผู้ใช้ของคุณยกเว้นเมื่อพวกเขาทำรหัสผ่านหายและคุณส่งรหัสชั่วคราว
  • ไม่เคยบันทึกรหัสผ่านในลักษณะใด ๆ
  • อย่าแฮรหัสผ่านด้วยSHA1หรือ MD5 หรือแม้แต่ SHA256! แครกเกอร์ที่ทันสมัยสามารถมีแฮ็ชได้มากกว่า 60 และ 180 พันล้านต่อวินาที
  • อย่าผสมbcrypt และกับเอาต์พุตดิบของ hash ()ไม่ว่าจะใช้ hex output หรือ base64_encode (สิ่งนี้ใช้กับอินพุตใด ๆ ที่อาจมีการโกง\0ในซึ่งสามารถลดความปลอดภัยอย่างจริงจัง)

Dos

  • ใช้ scrypt เมื่อคุณสามารถ; bcrypt หากคุณไม่สามารถ
  • ใช้ PBKDF2 หากคุณไม่สามารถใช้ bcrypt หรือ scrypt โดยที่มีแฮช SHA2
  • รีเซ็ตรหัสผ่านของทุกคนเมื่อฐานข้อมูลถูกบุกรุก
  • ใช้ความยาวต่ำสุดที่เหมาะสม 8-10 ตัวอักษรและต้องมีตัวอักษรตัวพิมพ์ใหญ่อย่างน้อย 1 ตัวอักษรตัวพิมพ์เล็ก 1 ตัวตัวเลขและสัญลักษณ์ วิธีนี้จะช่วยปรับปรุงรหัสผ่านของเอนโทรปีทำให้ยากต่อการถอดรหัส (ดูหัวข้อ "อะไรคือรหัสผ่านที่ดี?" เพื่อการอภิปรายบางส่วน)

ทำไมต้องใช้รหัสผ่านแฮช

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

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

Jeremiah Grossman, CTO ของ Whitehat Security ระบุไว้ในบล็อก White Hat Securityหลังจากการกู้คืนรหัสผ่านเมื่อเร็ว ๆ นี้ซึ่งจำเป็นต้องใช้การป้องกันด้วยรหัสผ่านของเขา:

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

(ของฉันเน้น)

อะไรที่ทำให้รหัสผ่านที่ดีอยู่ดี

เอนโทรปี (ไม่ใช่ว่าฉันสมัครรับมุมมองของ Randall อย่างเต็มที่)

กล่าวโดยสรุปเอนโทรปีคือความผันแปรภายในรหัสผ่าน เมื่อรหัสผ่านเป็นอักษรโรมันตัวพิมพ์เล็กเท่านั้นนั่นเป็นเพียง 26 ตัวอักษร นั่นไม่แตกต่างกันมาก รหัสผ่านที่เป็นตัวเลขและตัวอักษรจะดีกว่าโดยมี 36 ตัวอักษร แต่การอนุญาตให้ใช้ตัวพิมพ์เล็กและใหญ่ด้วยสัญลักษณ์มีความยาวประมาณ 96 อักขระ มันดีกว่าแค่ตัวอักษร ปัญหาหนึ่งคือการทำให้รหัสผ่านของเราเป็นที่น่าจดจำเราได้ใส่รูปแบบซึ่งช่วยลดการใช้พลังงานเอนโทรปี อ๊ะ!

รหัสผ่านเอนโทรปีถูกประมาณได้อย่างง่ายดาย การใช้ช่วงเต็มของอักขระ ASCII (ประมาณ 96 อักขระที่พิมพ์ได้) ให้เอนโทรปีของ 6.6 ต่อตัวอักษรซึ่งที่ 8 ตัวอักษรสำหรับรหัสผ่านยังต่ำเกินไป (เอนโทรปี 52.679 บิต) เพื่อความปลอดภัยในอนาคต แต่ข่าวดีก็คือ: รหัสผ่านที่ยาวขึ้นและรหัสผ่านที่มีอักขระ Unicode เพิ่มรหัสผ่านของเอนโทรปีและทำให้แตกได้ยากขึ้น

มีการถกเถียงเรื่องรหัสผ่านเอนโทรปีบนไซต์Crypto StackExchangeอีกต่อไป การค้นหาของ Google ที่ดีจะทำให้ได้ผลลัพธ์จำนวนมาก

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

เท่าที่ฉันสามารถบอกได้การสร้างรหัสผ่านที่ดีที่สุดในโลกคือ Catch-22 ไม่ว่าจะเป็นที่น่าจดจำคาดเดาได้สั้นเกินไปตัวอักษรยูนิโค้ดมากเกินไป (ยากที่จะพิมพ์บนอุปกรณ์ Windows / Mobile) ยาวเกินไป ฯลฯ ไม่มีรหัสผ่านที่ดีพอสำหรับวัตถุประสงค์ของเราดังนั้นเราจึงต้องปกป้องพวกเขาราวกับว่าพวกเขา อยู่ในฟอร์ทน็อกซ์

ปฏิบัติที่ดีที่สุด

Bcrypt และscryptเป็นแนวทางปฏิบัติที่ดีที่สุดในปัจจุบัน Scryptจะดีกว่า bcrypt ในเวลา แต่มันยังไม่เห็นว่าการยอมรับเป็นมาตรฐานโดย Linux / Unix หรือโดย webservers และยังไม่มีการตรวจสอบขั้นตอนวิธีเชิงลึกที่โพสต์ แต่ถึงกระนั้นอนาคตของอัลกอริทึมก็ดูสดใส หากคุณทำงานกับ Ruby มีscrypt gemที่จะช่วยคุณได้และตอนนี้ Node.js มีแพ็คเกจscryptของตัวเอง คุณสามารถใช้ Scrypt ใน PHP ผ่านส่วนขยายScryptหรือส่วนขยายLibsodium (ทั้งสองมีให้บริการใน PECL)

ฉันขอแนะนำให้อ่านเอกสารสำหรับฟังก์ชัน cryptหากคุณต้องการเข้าใจวิธีการใช้ bcrypt หรือค้นหาwrapper ที่ดี หรือใช้สิ่งที่ต้องการเช่นPHPASSสำหรับการใช้งานแบบดั้งเดิมมากขึ้น ฉันแนะนำ bcrypt อย่างน้อย 12 รอบถ้าไม่ใช่ 15 ถึง 18

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

การปฏิบัติโดยเฉลี่ย

ฉันแทบจะนึกภาพสถานการณ์นี้ไม่ได้อีกแล้ว PHPASSรองรับ PHP 3.0.18 ถึง 5.3 ดังนั้นจึงสามารถใช้งานได้ในเกือบทุกการติดตั้งเท่าที่จะเป็นไปได้และควรใช้หากคุณไม่ทราบว่าระบบของคุณรองรับ bcrypt หรือไม่

แต่สมมติว่าคุณไม่สามารถใช้ bcrypt หรือ PHPASS ได้เลย ถ้าเช่นนั้นจะเป็นอย่างไร

ลองใช้PDKBF2กับจำนวนรอบสูงสุดที่สภาพแวดล้อม / แอปพลิเคชัน / การรับรู้ของผู้ใช้ของคุณสามารถทนได้ จำนวนต่ำสุดที่ฉันแนะนำคือ 2500 รอบ นอกจากนี้ตรวจสอบให้แน่ใจว่าใช้hash_hmac ()หากสามารถทำให้การดำเนินการทำซ้ำยากขึ้น

แนวทางปฏิบัติในอนาคต

มาใน PHP 5.5 เป็นรหัสผ่านห้องสมุดคุ้มครองเต็มรูปแบบที่ abstracts ออกไปความเจ็บปวดของการทำงานกับ bcrypt ใด ๆ ในขณะที่พวกเราส่วนใหญ่ติดอยู่กับ PHP 5.2 และ 5.3 ในสภาพแวดล้อมที่พบบ่อยที่สุดโดยเฉพาะโฮสต์ที่ใช้ร่วมกัน @ircmaxell ได้สร้างเลเยอร์ที่เข้ากันได้สำหรับ API ที่กำลังจะมาซึ่งสามารถใช้งานร่วมกับ PHP 5.3.7 ได้

สรุปการเข้ารหัสและข้อสงวนสิทธิ์

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

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

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


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

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

6
@ หมัดตัวเล็กฉันไม่ได้โต้เถียงกับคุณ เพียงแค่ชี้ให้เห็นว่าความซับซ้อนและซับซ้อนของงานนี้ของเราเป็นอย่างไร ฉันหวังเป็นอย่างยิ่งว่าจะได้รับการเรียนรู้จากแนวปฏิบัติที่ชาญฉลาดและเป็นที่สุดเพื่อการตั้งค่าระบบการจัดการเนื้อหาของเว็บไซต์ขนาดเล็ก ฉันยังเรียนอยู่ที่นี่ ... ทุกครั้งที่ฉันอ่านอะไรที่มันสมเหตุสมผลฉันจะสังเกตเห็นอีก 5 โพสต์ที่ขัดแย้งกับมัน ที่รอบและรอบที่ได้รับ dizzying อย่างรวดเร็ว :)
M42

4
การแก้ไขที่น่าสนใจ รหัสผู้ใช้ (เช่นเพิ่มอัตโนมัติ BIGINT) เป็นสิ่งที่ดีหรือไม่? หรือเพราะมันไม่สุ่มมันไม่ดีเลยเหรอ? นอกจากนี้ฉันจะต้องเก็บ nonce สำหรับผู้ใช้แต่ละคนในฐานข้อมูล ... คีย์ไซต์ + nonce + HMAC ให้ความปลอดภัยที่ดีขึ้นอย่างมีนัยสำคัญผ่านทางเค็ม (พร้อม ID ผู้ใช้) hash ซ้ำหลายครั้งหรือไม่ ในทำนองเดียวกันการทำซ้ำ HMAC หลายครั้งดีสำหรับความปลอดภัยหรือไม่
luiscubal

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

138

คำตอบที่สั้นกว่าและปลอดภัยกว่ามาก - อย่าเขียนกลไกรหัสผ่านของคุณเลยใช้กลไกที่ผ่านการทดลองและทดสอบแล้ว

  • PHP 5.5 หรือสูงกว่า: password_hash ()มีคุณภาพดีและเป็นส่วนหนึ่งของ PHP core
  • เวอร์ชัน PHP เวอร์ชันเก่ากว่า: ห้องสมุดphpassของ OpenWall ดีกว่าโค้ดที่กำหนดเองส่วนใหญ่ - ใช้ใน WordPress, Drupal และอื่น ๆ

โปรแกรมเมอร์ส่วนใหญ่ไม่มีความเชี่ยวชาญในการเขียนรหัสที่เกี่ยวข้อง crypto อย่างปลอดภัยโดยไม่แนะนำช่องโหว่

การทดสอบตัวเองอย่างรวดเร็ว: การยืดรหัสผ่านคืออะไรและคุณควรใช้ซ้ำกี่ครั้ง หากคุณไม่ทราบคำตอบคุณควรใช้password_hash()เนื่องจากการยืดรหัสผ่านตอนนี้เป็นคุณสมบัติที่สำคัญของกลไกรหัสผ่านเนื่องจาก CPU ที่เร็วกว่ามากและการใช้GPU และ FPGAเพื่อถอดรหัสรหัสผ่านด้วยอัตราการเดานับพันต่อวินาที (ด้วย GPU )

ตัวอย่างเช่นคุณสามารถถอดรหัสรหัสผ่าน Windows 8 ตัวละครทั้งหมดใน 6 ชั่วโมงโดยใช้ 25 GPUs ที่ติดตั้งในคอมพิวเตอร์ตั้งโต๊ะ 5 เครื่อง นี่คือการบังคับให้เดรัจฉานคือการแจกแจงและตรวจสอบรหัสผ่าน Windows 8 ตัวอักษรทุกตัวรวมถึงตัวอักษรพิเศษและไม่ใช่การโจมตีด้วยพจนานุกรม นั่นคือในปี 2012 ในปี 2018 คุณสามารถใช้ GPU น้อยลงหรือแตกเร็วขึ้นด้วย 25 GPUs

นอกจากนี้ยังมีการโจมตีรุ้งกินน้ำบนรหัสผ่าน Windows ที่ทำงานบน CPU ทั่วไปและรวดเร็วมาก ทั้งหมดนี้เป็นเพราะ Windows ยังคง ไม่ใส่เกลือหรือยืดรหัสผ่านแม้ใน Windows 10 - อย่าทำผิดแบบเดียวกับที่ Microsoft ทำ!

ดูสิ่งนี้ด้วย:


1
แต่ระบบเหล่านี้เป็นที่รู้จักกันดีและอาจถูกบุกรุกอยู่แล้ว แต่มันทำให้ตัวคุณเองเมื่อคุณไม่รู้ว่าคุณทำอะไรอยู่
JqueryToAddNumbers

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

เมื่อพิจารณาจากการแฮ็ชรหัสผ่านล่าสุดจาก LinkedIn, Last.fm และอื่น ๆ นี่เป็นหัวข้อที่ค่อนข้างเฉพาะ คุณอยู่ใน บริษัท ที่ดีไม่ทราบวิธีการเขียนกลไกรหัสผ่านของคุณเอง!
RichVel

3
@PP - โอกาสของอัลกอริทึมการแฮ็กรหัสผ่านแบบ peer-reviewed ที่มี backdoor ของ NSA นั้นต่ำมากในมุมมองของฉัน โอกาสของคนที่ไม่ใช่ผู้เชี่ยวชาญการเข้ารหัสลับที่แท้จริงเขียนกลไกการแฮ็กรหัสผ่านใหม่โดยไม่มีช่องโหว่อื่น ๆ จะต่ำกว่ามาก และ webapp ทั่วไปใช้แค่ MD5 หรือ SHA-1 hashing ซึ่งแย่มาก - แม้แต่หนังสือ Essential PHP Security ของ Chris Shiflett ก็แนะนำ MD5 ...
RichVel

1
@RichVel - ฟังก์ชัน password_hash () ดังกล่าวก่อนหน้านี้มันถูกสร้างขึ้นใน PHP core (aka / ext / standard)
CubicleSoft

43

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


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

2
ขออภัยฉันอ่านคำตอบของคุณผิดโดยแนะนำให้ใช้สองแฮช ... คุณจริงแล้วถูกต้อง การใช้แฮชสองตัวจะทำให้ระบบอ่อนแอในกรณีที่ใช้รหัสผ่านเนื่องจากต้องแบ่งแฮชที่อ่อนแอกว่า
frankodwyer

40

ในฐานะของ PHP 5.5, PHP มีฟังก์ชั่นที่ง่ายและปลอดภัยสำหรับการแฮชและการยืนยันรหัสผ่าน, password_hash ()และpassword_verify ()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

เมื่อpassword_hash()มีการใช้งานจะสร้างเกลือแบบสุ่มและรวมไว้ในแฮชเอาต์พุต (รวมถึงต้นทุนและอัลกอริทึมที่ใช้) password_verify()จากนั้นอ่านแฮชนั้นและกำหนดวิธีเกลือและการเข้ารหัสที่ใช้และตรวจสอบกับรหัสผ่านธรรมดาที่ระบุ

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

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

โปรดทราบว่าแม้ว่าอัลกอริทึมการแฮชเริ่มต้นอาจเปลี่ยนไป แต่แฮชเก่าจะยังคงตรวจสอบได้ดีเพราะอัลกอริทึมที่ใช้นั้นถูกเก็บไว้ในแฮชและpassword_verify()หยิบขึ้นมา


33

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

คำอธิบายเพิ่มเติมสามารถดูได้ที่ - http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

เมื่อเร็ว ๆ นี้ฉันมีการสนทนาว่าแฮ็ชรหัสผ่านด้วยบิตสุ่มมีความปลอดภัยมากกว่าเค็มที่มีเกลือที่เดาได้ มาดูกัน: หากระบบการจัดเก็บรหัสผ่านถูกบุกรุกรวมถึงระบบที่เก็บเกลือแบบสุ่มผู้โจมตีจะสามารถเข้าถึงแฮชและเกลือได้ดังนั้นไม่ว่าเกลือนั้นจะสุ่มหรือไม่ก็ตาม ผู้โจมตีสามารถสร้างตารางสายรุ้งที่คำนวณล่วงหน้าเพื่อถอดรหัสแฮช นี่คือส่วนที่น่าสนใจ - มันไม่สำคัญเลยที่จะสร้างตารางที่คำนวณล่วงหน้า ให้เรานำตัวอย่างของรูปแบบความปลอดภัย WPA รหัสผ่าน WPA ของคุณจะไม่ถูกส่งไปยัง Wireless Access Point แต่จะถูกแฮชด้วย SSID ของคุณ (เช่นชื่อเครือข่าย Linksys, Dlink เป็นต้น) คำอธิบายที่ดีมากเกี่ยวกับการทำงานของที่นี่ เพื่อดึงรหัสผ่านจากแฮ คุณจะต้องรู้รหัสผ่านเช่นเดียวกับเกลือ (ชื่อเครือข่าย) Church of Wifi มีตารางแฮชที่คำนวณล่วงหน้าไว้แล้วซึ่งมี 1,000 SSID สูงสุดและรหัสผ่านประมาณ 1 ล้านรหัส ขนาดของตารางทั้งหมดอยู่ที่ประมาณ 40 GB อย่างที่คุณสามารถอ่านได้บนไซต์ของพวกเขามีคนใช้อาร์เรย์ FGPA 15 ครั้งเป็นเวลา 3 วันเพื่อสร้างตารางเหล่านี้ สมมติว่าเหยื่อกำลังใช้ SSID เป็น“ a387csf3″ และรหัสผ่านเป็น“ 123456″ มันจะแตกด้วยตารางเหล่านั้นหรือไม่ No! .. มันไม่สามารถ แม้ว่ารหัสผ่านจะอ่อนแอ แต่ตารางก็ไม่มีแฮชสำหรับ SSID a387csf3 นี่คือความงามของการมีเกลือแบบสุ่ม มันจะยับยั้งแครกเกอร์ที่เจริญเติบโตบนโต๊ะที่คำนวณล่วงหน้า มันสามารถหยุดแฮ็กเกอร์ที่กำหนดได้หรือไม่ อาจจะไม่. แต่การใช้เกลือแบบสุ่มจะช่วยเพิ่มระดับการป้องกัน ขณะที่เราอยู่ในหัวข้อนี้ ให้เราคุยถึงข้อดีเพิ่มเติมของการจัดเก็บเกลือแบบสุ่มในระบบแยกต่างหาก สถานการณ์ที่ 1: แฮ็ชรหัสผ่านถูกเก็บไว้ในระบบ X และค่าเกลือที่ใช้สำหรับแฮชจะถูกเก็บไว้ในระบบ Y ค่าเกลือเหล่านี้สามารถคาดเดาได้หรือเป็นที่รู้จัก (เช่นชื่อผู้ใช้) สถานการณ์แฮช # 2: รหัสผ่านแฮช การแฮชถูกเก็บไว้ในระบบ Y ค่าเกลือเหล่านี้เป็นแบบสุ่ม ในกรณีที่ระบบ X ถูกโจมตีคุณสามารถเดาได้ว่ามีประโยชน์อย่างมากในการใช้เกลือแบบสุ่มในระบบที่แยกต่างหาก (สถานการณ์สมมติ # 2) ผู้โจมตีจะต้องเดาค่าเพิ่มเติมเพื่อให้สามารถแฮชแตกได้ หากใช้เกลือ 32 บิตจะต้องใช้การทำซ้ำ 2 ^ 32 = 4,294,967,296 (ประมาณ 4.2 พันล้าน) สำหรับแต่ละรหัสผ่าน แฮชรหัสผ่านถูกเก็บไว้ในระบบ X และค่าเกลือที่ใช้สำหรับการแฮชจะถูกเก็บไว้ในระบบ Y ค่าเกลือเหล่านี้สามารถคาดเดาได้หรือเป็นที่รู้จัก (เช่นชื่อผู้ใช้) สถานการณ์ # 2: แฮชรหัสผ่านจะถูกเก็บไว้ในระบบ X และค่าเกลือที่ใช้สำหรับการแฮช ระบบ Y. ค่าเกลือเหล่านี้สุ่ม ในกรณีที่ระบบ X ถูกโจมตีคุณสามารถเดาได้ว่ามีประโยชน์อย่างมากในการใช้เกลือแบบสุ่มในระบบที่แยกต่างหาก (สถานการณ์สมมติ # 2) ผู้โจมตีจะต้องเดาค่าเพิ่มเติมเพื่อให้สามารถแฮชแตกได้ หากใช้เกลือ 32 บิตจะต้องใช้การทำซ้ำ 2 ^ 32 = 4,294,967,296 (ประมาณ 4.2 พันล้าน) สำหรับแต่ละรหัสผ่าน แฮชรหัสผ่านถูกเก็บไว้ในระบบ X และค่าเกลือที่ใช้สำหรับการแฮชจะถูกเก็บไว้ในระบบ Y ค่าเกลือเหล่านี้สามารถคาดเดาได้หรือเป็นที่รู้จัก (เช่นชื่อผู้ใช้) สถานการณ์ # 2: แฮชรหัสผ่านจะถูกเก็บไว้ในระบบ X และค่าเกลือที่ใช้สำหรับการแฮช ระบบ Y. ค่าเกลือเหล่านี้สุ่ม ในกรณีที่ระบบ X ถูกโจมตีคุณสามารถเดาได้ว่ามีประโยชน์อย่างมากในการใช้เกลือแบบสุ่มในระบบที่แยกต่างหาก (สถานการณ์สมมติ # 2) ผู้โจมตีจะต้องเดาค่าเพิ่มเติมเพื่อให้สามารถแฮชแตกได้ หากใช้เกลือ 32 บิตจะต้องใช้การทำซ้ำ 2 ^ 32 = 4,294,967,296 (ประมาณ 4.2 พันล้าน) สำหรับแต่ละรหัสผ่าน ค่าเกลือเหล่านี้เป็นแบบสุ่ม ในกรณีที่ระบบ X ถูกโจมตีคุณสามารถเดาได้ว่ามีประโยชน์อย่างมากในการใช้เกลือแบบสุ่มในระบบที่แยกต่างหาก (สถานการณ์สมมติ # 2) ผู้โจมตีจะต้องเดาค่าเพิ่มเติมเพื่อให้สามารถแฮชแตกได้ หากใช้เกลือ 32 บิตจะต้องใช้การทำซ้ำ 2 ^ 32 = 4,294,967,296 (ประมาณ 4.2 พันล้าน) สำหรับแต่ละรหัสผ่าน ค่าเกลือเหล่านี้เป็นแบบสุ่ม ในกรณีที่ระบบ X ถูกโจมตีคุณสามารถเดาได้ว่ามีประโยชน์อย่างมากในการใช้เกลือแบบสุ่มในระบบที่แยกต่างหาก (สถานการณ์สมมติ # 2) ผู้โจมตีจะต้องเดาค่าเพิ่มเติมเพื่อให้สามารถแฮชแตกได้ หากใช้เกลือ 32 บิตจะต้องใช้การทำซ้ำ 2 ^ 32 = 4,294,967,296 (ประมาณ 4.2 พันล้าน) สำหรับแต่ละรหัสผ่าน


7
แม้ว่าผู้โจมตีจะได้รับเกลือสตริง "sitesalt: usersalt: users" ยังคงทนทานต่อตารางที่คำนวณไว้ล่วงหน้าเนื่องจากผู้โจมตีต้องการสร้างตารางสำหรับผู้ใช้ทุกคน (ดังนั้นการโจมตีจะช้ากว่า) เว้นแต่ผู้ใช้เฉพาะจะเจาะจง กำลังถูกกำหนดเป้าหมาย ...
luiscubal

เกี่ยวกับ "แม้ว่าผู้โจมตีจะได้รับเกลือสตริง" sitesalt: usersalt: users "รหัสผ่านยังคงทนทานต่อตารางที่คำนวณล่วงหน้าได้" ตกลงทั้งหมด ประเด็นของฉันคือว่าไซต์จะถูกสร้างแบบสุ่มและใช้เวลานานจะทำให้ระบบมีความปลอดภัยมากกว่าที่คาดการณ์ไว้ (ไซต์) ฉันเคยเห็นบางคนแนะนำให้ใช้รหัสอีเมล ฯลฯ เป็นเกลือและฉันไม่สนับสนุนสิ่งนั้น
Gaurav Kumar

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

28

ผมแค่อยากจะชี้ให้เห็นว่า PHP 5.5 รวมถึงAPI รหัสผ่านคร่ำเครียดcrypt()ที่ให้รอบเสื้อคลุม API นี้ช่วยลดความยุ่งยากของงานการแฮชการตรวจสอบและการแฮชรหัสผ่านใหม่ ผู้เขียนได้เปิดตัวแพ็คที่เข้ากันได้ (ในรูปแบบของไฟล์ password.php เดียวที่คุณrequireใช้) สำหรับผู้ที่ใช้ PHP 5.3.7 ขึ้นไปและต้องการใช้งานในตอนนี้

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

API เปิดเผยสี่ฟังก์ชัน:

  • password_get_info() - ส่งคืนข้อมูลเกี่ยวกับแฮชที่กำหนด
  • password_hash() - สร้างแฮรหัสผ่าน
  • password_needs_rehash()- ตรวจสอบว่าแฮชที่ให้นั้นตรงกับตัวเลือกที่กำหนดหรือไม่ มีประโยชน์ในการตรวจสอบว่าแฮชสอดคล้องกับเทคนิค / รูปแบบค่าใช้จ่ายในปัจจุบันของคุณหรือไม่ซึ่งช่วยให้คุณสามารถทำการปรับปรุงใหม่หากจำเป็น
  • password_verify() - ตรวจสอบว่ารหัสผ่านตรงกับแฮช

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

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


19

ฉันใช้Phpassซึ่งเป็นคลาส PHP แบบไฟล์เดียวที่สามารถนำไปใช้ได้อย่างง่ายดายในเกือบทุกโปรเจ็ค PHP ดูเพิ่มเติมความ H

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

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

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

ในการตรวจสอบรหัสผ่านสามารถใช้:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

14

สิ่งที่ต้องจำ

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

SERVER

พอร์ต

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

USERNAME

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

รหัสผ่าน

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

ฐานข้อมูล

SERVER

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

USER

ให้แอปพลิเคชันของคุณมีบัญชีของตนเองเพื่อเข้าถึงฐานข้อมูลเสมอและให้สิทธิ์ที่จำเป็นเท่านั้น

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

เช่นเคยอย่าทำให้รากนี้หรือสิ่งที่คล้ายกัน

รหัสผ่าน

ปฏิบัติตามแนวทางเดียวกันกับรหัสผ่านที่ดีทั้งหมด นอกจากนี้อย่านำรหัสผ่านเดิมซ้ำไปใช้กับบัญชี SERVER หรือ DB ใด ๆ ในระบบเดียวกัน

PHP

รหัสผ่าน

ไม่เคยเก็บรหัสผ่านไว้ในฐานข้อมูลของคุณแทนที่จะเก็บกัญชาและเกลือที่เป็นเอกลักษณ์ฉันจะอธิบายว่าทำไมในภายหลัง

คร่ำเครียด

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

มีฟังก์ชันการแฮ็กที่ดีมากมาย ( password_hash,, hashฯลฯ ... ) แต่คุณต้องเลือกอัลกอริทึมที่ดีเพื่อให้แฮชมีประสิทธิภาพ (bcrypt และอันที่คล้ายกับมันเป็นอัลกอริธึมที่เหมาะสม)

เมื่อความเร็วในการ hashing เป็นกุญแจสำคัญยิ่งการโจมตีของ Brute Force นั้นช้าลง

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

เกลือ

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

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

ผู้ใช้สร้างรหัสผ่าน

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

ยังทำให้ผู้ใช้สร้างรหัสผ่านที่ปลอดภัยมันง่ายและควรทำเสมอผู้ใช้จะขอบคุณสำหรับมันในที่สุด

ในที่สุดไม่ว่ามาตรการรักษาความปลอดภัยที่คุณไม่ได้ทำจะปลอดภัย 100% ยิ่งเทคโนโลยีขั้นสูงยิ่งขึ้นในการปกป้องมากเท่าไหร่การโจมตีก็จะยิ่งมากขึ้นเท่านั้น แต่การทำตามขั้นตอนเหล่านี้จะทำให้ไซต์ของคุณปลอดภัยและเป็นที่ต้องการน้อยกว่าสำหรับผู้โจมตี

นี่คือคลาส PHP ที่สร้างแฮชและเกลือสำหรับรหัสผ่านได้อย่างง่ายดาย

http://git.io/mSJqpw


1
คุณควรโจมตี SHA512 จากรายการแฮชอัลกอริธึมที่เหมาะสมเพราะเร็วเกินไป ใช้ร่วมกับ PBKDF2 เท่านั้น ในขณะที่ BCrypt มีพื้นฐานมาจากปักเป้า แต่ปักเป้าก็เป็นอัลกอริธึมสำหรับการเข้ารหัสไม่ใช่เพื่อการแฮช
martinstoeckli

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

wmfrancia wrote: "Salting เพิ่มสตริงแบบสุ่มไปยังรหัสผ่านเพื่อให้รหัสผ่านที่คล้ายกันไม่ปรากฏใน DB" สิ่งนี้ไม่สมเหตุสมผลสำหรับฉัน Hashes ในฐานข้อมูลจะปรากฏแตกต่างกันไปเนื่องจากเป็นคุณสมบัติของฟังก์ชันแฮช
H2ONaCl

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

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

12

Google กล่าวว่า SHA256 พร้อมใช้งานกับ PHP

คุณควรใช้เกลืออย่างแน่นอน ฉันขอแนะนำให้ใช้แบบสุ่มไบต์ (และไม่ จำกัด ตัวคุณเป็นตัวอักษรและตัวเลข) โดยทั่วไปยิ่งคุณเลือกได้นานเท่าไหร่คุณก็จะยิ่งปลอดภัยยิ่งช้าลงเท่านั้น 64 bytes ควรจะดีฉันเดา


13
64 บิตน่าจะเพียงพอสำหรับทุกคน?
Konerak

@ Konerak ฉันจะกลับมาที่นี่อีกครั้งหลังจากผ่านไป 20 ปี :) แต่แท้จริงแล้ว SHA256 นั้นพร้อมใช้งานแล้ว หากคุณต้องการทราบว่า SHA256 ปลอดภัยเพียงใดคุณอาจต้องการตรวจสอบสิ่งนี้: security.stackexchange.com/questions/90064/…
Vincent Edward Gedaria Binua

8

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


2
การป้องกันการแฮ็กหลายครั้งยังช่วยป้องกันพจนานุกรมและการโจมตีด้วยสัตว์เดรัจฉาน - เช่นทำให้การคำนวณนานขึ้น
frankodwyer

6
การแฮ็กสองครั้งจะไม่ทำให้คุณได้เปรียบที่สำคัญ แต่การทำซ้ำหลายรอบยังคงเป็นการป้องกันที่เป็นไปได้สำหรับพจนานุกรมและการโจมตีแบบบรูซ แฮชของรหัสผ่านความแข็งแรงทางอุตสาหกรรมใช้มากกว่า 1,000 รอบ PBKDF1 ของ PKCS # 5 แนะนำขั้นต่ำ 1,000 รอบ
Berk D. Demir

8

ฉันพบหัวข้อที่สมบูรณ์แบบในเรื่องนี้ที่นี่: https://crackstation.net/hashing-security.htmฉันต้องการให้คุณได้รับประโยชน์จากมันนี่คือซอร์สโค้ดที่ให้การป้องกันการโจมตีตามเวลาด้วย

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

คุณให้วิธีการแก้ปัญหากับเราโดยไม่ต้องไม่มีการใช้งานเลย
ไมเคิล

6

ฉันมักจะใช้ SHA1 และเกลือกับ ID ผู้ใช้ (หรือบางส่วนของข้อมูลเฉพาะของผู้ใช้) และบางครั้งฉันก็ใช้เกลือคงที่เพิ่มเติม (ดังนั้นฉันจึงมีเกลือ 2 ส่วน)

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


2
เกลือคงที่ไม่ใช่ความคิดที่ดี ... อาจไม่ใช่ข้อบกพร่องที่ร้ายแรง แต่มันทำให้แผนการอ่อนแอลงโดยไม่จำเป็น
frankodwyer

MD5 และ SHA1 นั้นเร็วดังนั้นนี่คือดีนาที่ไม่ดี
CodesInChaos

4

SHA1และเกลือควรจะพอเพียง (ขึ้นอยู่กับว่าคุณกำลังเขียนโปรแกรมบางอย่างสำหรับFort Knoxหรือระบบเข้าสู่ระบบสำหรับรายการช็อปปิ้งของคุณ) สำหรับอนาคตอันใกล้ หาก SHA1 ไม่ดีพอสำหรับคุณใช้SHA256

ความคิดของเกลือคือการโยนผลตอบสนองความสมดุลออกมาเพื่อที่จะพูด มันเป็นที่รู้จักตัวอย่างเช่น MD5-hash ของสตริงว่างคือd41d8cd98f00b204e9800998ecf8427eแฮชของสตริงที่ว่างเปล่าเป็น ดังนั้นหากใครที่มีความจำดีพอหน่วยความจำจะเห็นแฮชนั้นและรู้ว่ามันคือแฮชของสตริงว่าง แต่ถ้าสตริงนั้นถูกใส่เกลือ (พูดกับสตริง " MY_PERSONAL_SALT") แฮชสำหรับ 'สตริงว่าง' (เช่น " MY_PERSONAL_SALT") จะกลายเป็นaeac2612626724592271634fb14d3ea6ดังนั้นจึงไม่ชัดเจนที่จะย้อนรอยถอยหลัง สิ่งที่ฉันพยายามที่จะพูดว่ามันเป็นดีกว่าการใช้ใด ๆเกลือกว่าที่จะไม่ ดังนั้นจึงไม่มากเกินไปของความสำคัญที่จะรู้ซึ่งเกลือเพื่อการใช้งาน

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

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


ไซต์เป้าหมายไม่ควรมีสิ่งใดที่ละเอียดอ่อนเกินไป (ไม่ใช่ธนาคาร) แต่ก็ยังค่อนข้างปลอดภัย
luiscubal

1
การแฮ็ชสองครั้งจะไม่ลดพื้นที่ผลลัพธ์ hashing ซ้ำแล้วซ้ำอีกเป็นการควบคุมทั่วไปสำหรับพจนานุกรมและการโจมตีแบบบังคับเดรัจฉาน
frankodwyer

2
@frankodwyer: ใช่มันไม่ดี sha1(sha1($foo))ลดพื้นที่เอาท์พุตได้อย่างมีประสิทธิภาพเนื่องจากการชนกันของฟังก์ชั่นภายในจะกลายเป็นการชนกันของภายนอกโดยอัตโนมัติ การย่อยสลายเป็นแบบเส้นตรง แต่ก็ยังเป็นปัญหาอยู่ $hash = sha1(sha1($salt . $password) . $salt)วิธีการแปลงแป้นพิมพ์ซ้ำฟีดข้อมูลกลับในแต่ละรอบเช่น แต่นั่นก็ยังไม่ดี ... ติดกับ PBKDF2 หรือ Bcrypt ...
ircmaxell

-7

ตกลงใน Fitsy ที่เราต้องการเกลือเกลือจะต้องไม่ซ้ำกันดังนั้นให้สร้างมันขึ้นมา

   /**
     * Generating string
     * @param $size
     * @return string
     */
    function Uniwur_string($size){
        $text = md5(uniqid(rand(), TRUE));
        RETURN substr($text, 0, $size);
    }

นอกจากนี้เรายังต้องการแฮชที่ฉันใช้ sha512 ดีที่สุดและอยู่ใน php

   /**
     * Hashing string
     * @param $string
     * @return string
     */
    function hash($string){
        return hash('sha512', $string);
    }

ดังนั้นตอนนี้เราสามารถใช้ฟังก์ชั่นนี้เพื่อสร้างรหัสผ่านที่ปลอดภัย

// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations

// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);

ตอนนี้เราต้องบันทึกในฐานข้อมูลค่าตัวแปร $ hash_psw และตัวแปร $ salt ของเรา

และเพื่ออนุญาตเราจะใช้ขั้นตอนเดียวกัน ...

มันเป็นวิธีที่ดีที่สุดในการรักษารหัสผ่านของลูกค้าให้ปลอดภัย ...

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


4
คำถามนี้เกี่ยวกับแฮชสำหรับรหัสผ่าน 1 การดำเนินการของsha512(แม้ว่าเค็ม) ได้รับการพิจารณาอย่างกว้างขวางว่าไม่ดีพอสำหรับการป้องกันรหัสผ่าน (เช่นกันว่า RNG ไม่มีความปลอดภัยในการเข้ารหัสดังนั้นการใช้รหัสผ่านในการสร้างรหัสผ่านจึงมีความเสี่ยง)
luiscubal

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

ตกลง. รหัสของฉันไม่ปลอดภัย ดังนั้นให้ฉันรู้ว่าทำไมคุณถึงใช้ในอัลกอริทึมของคุณด้วย sha256 ??? ฉันรู้ว่า sha512 ดีที่สุดทำไมไม่ใช้มัน ???
shalvasoft

1
@shalvasoft sha512 นั้นค่อนข้างดีสำหรับวัตถุประสงค์ทั่วไปของการแฮช แต่การป้องกันรหัสผ่านต้องใช้แฮชที่มีคุณสมบัติเฉพาะเจาะจงมาก ("กำลังช้า" เป็นสิ่งที่ดีอย่างแปลกประหลาดและ sha512 นั้นค่อนข้างเร็ว) บางคนใช้ sha512 เป็นแบบเอกสารสำเร็จรูปเพื่อสร้างฟังก์ชั่นการแฮ็กรหัสผ่าน แต่ทุกวันนี้วิธีการที่แนะนำคือ "ใช้ bcrypt และจับตาดู scrypt"
luiscubal
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.