ทำความสะอาดรหัสผ่านของผู้ใช้


98

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

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


1
คุณสามารถเข้ารหัสผู้ใช้ base64
MSS

ไม่มี @MSS คุณไม่ควรเพราะ base64 ถูกเข้ารหัสไม่เข้ารหัสหรือคร่ำเครียด รหัสผ่านควรจะถกกัน
Jay Blanchard

1
ฉันหมายถึงก่อนแฮช;)
MSS

คุณไม่ควรและไม่จำเป็นต้องทำก่อนการแฮช จะทำให้คุณต้องเขียนโค้ดเพิ่มเติมโดยไม่จำเป็น @MSS
Jay Blanchard

คำตอบ:


99

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

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

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

หากคุณปฏิบัติตามมนต์ในการอนุญาตให้ผู้ใช้ใช้รหัสผ่าน / วลีที่พวกเขาต้องการและคุณไม่ จำกัด รหัสผ่านการอนุญาตให้มีความยาวช่องว่างจำนวนเท่าใดก็ได้และการแฮชอักขระพิเศษใด ๆ จะทำให้รหัสผ่าน / ข้อความรหัสผ่านปลอดภัยไม่ว่าจะมีอะไรอยู่ภายในก็ตาม รหัสผ่าน. ณ ตอนนี้แฮชที่พบบ่อยที่สุด (ค่าเริ่มต้น) PASSWORD_BCRYPTเปลี่ยนรหัสผ่านเป็นสตริงกว้าง 60 อักขระที่มีเกลือแบบสุ่มพร้อมกับข้อมูลรหัสผ่านที่แฮชและค่าใช้จ่าย (ต้นทุนอัลกอริทึมในการสร้างแฮช):

PASSWORD_BCRYPT ใช้เพื่อสร้างแฮชรหัสผ่านใหม่โดยใช้อัลกอริทึม CRYPT_BLOWFISH สิ่งนี้จะส่งผลให้แฮชใช้รูปแบบการเข้ารหัส "$ 2y $" ซึ่งกว้าง 60 อักขระเสมอ

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

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

SELECT * FROM `users`;

สามารถแฮชได้ $2y$10$1tOKcWUWBW5gBka04tGMO.BH7gs/qjAHZsC5wyG0zmI2C.KgaqU5G

มาดูกันว่าวิธีการฆ่าเชื้อที่แตกต่างกันมีผลต่อรหัสผ่านอย่างไร -

รหัสผ่านคือI'm a "dessert topping" & a <floor wax>!(มี 5 ช่องว่างที่ส่วนท้ายของรหัสผ่านซึ่งไม่แสดงที่นี่)

เมื่อเราใช้วิธีการตัดแต่งต่อไปนี้เราจะได้ผลลัพธ์ที่แตกต่างกันออกไป:

var_dump(trim($_POST['upassword']));
var_dump(htmlentities($_POST['upassword']));
var_dump(htmlspecialchars($_POST['upassword']));
var_dump(addslashes($_POST['upassword']));
var_dump(strip_tags($_POST['upassword']));

ผล:

string(40) "I'm a "dessert topping" & a <floor wax>!" // spaces at the end are missing
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // double quotes, ampersand and braces have been changed
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // same here
string(48) "I\'m a \"dessert topping\" & a <floor wax>!     " // escape characters have been added
string(34) "I'm a "dessert topping" & a !     " // looks like we have something missing

เกิดอะไรขึ้นเมื่อเราส่งเหล่านี้เพื่อpassword_hash()? พวกเขาทั้งหมดได้รับการแฮชเช่นเดียวกับข้อความค้นหาข้างต้น ปัญหาเกิดขึ้นเมื่อคุณพยายามยืนยันรหัสผ่าน ถ้าเราจ้างหนึ่งหรือมากกว่าของวิธีการเหล่านี้เราต้อง password_verify()re-จ้างพวกเขาก่อนที่จะเปรียบเทียบกับ สิ่งต่อไปนี้จะล้มเหลว:

password_verify($_POST['upassword'], $hashed_password); // where $hashed_password comes from a database query

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


ใช้ PHP เวอร์ชันน้อยกว่า 5.5? คุณสามารถใช้แพคความเข้ากันpassword_hash()

คุณไม่ควรใช้แฮชรหัสผ่าน MD5จริงๆ


13
ไม่ถ้าเขาสร้างรหัสผ่านโดยมีช่องว่างต่อท้ายซึ่งได้รับอนุญาตเขาจะต้องใช้รหัสนั้นในการเข้าสู่ระบบ @DanBracuk
Jay Blanchard

12
@DanBracuk ยังไง? หากเราอนุญาตให้ผู้ใช้ตั้งรหัสผ่านที่ต้องการรวมถึงช่องว่างนำหน้า / ต่อท้ายด้วย?
Jay Blanchard

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

4
@MargaretBloom กฎง่ายๆก็แค่ฮิวริสติก บางครั้งเรายังต้องคิดสิ่งต่างๆเช่นรหัสผ่าน คุณพูดว่า "ไม่มีใครรู้ว่าสิ่งต่างๆจะเปลี่ยนไปอย่างไรในอนาคต" แต่ดูเหมือนว่าถ้ามีอะไรเปลี่ยนแปลงไปนี่เป็นวิธีที่เราหลบหนีข้อมูลก่อนที่เราจะใส่ลงในฐานข้อมูลซึ่งในกรณีนี้ผู้ใช้จะพบว่าตัวเองถูกล็อกเอาไว้เมื่อรหัสผ่านไม่มี ตรงกับสิ่งที่เราเก็บไว้นานขึ้น อะไรคืออันตรายในการไม่หลบหนีแฮชรหัสผ่านเทียบกับอันตรายจากการหลบหนี
DavidS

3
ตรง: แน่นอนคุณจะ "หลีกเลี่ยงแฮช" ในแง่ที่ จำกัด ของการส่งต่อไปยังแบบสอบถาม SQL ที่กำหนดพารามิเตอร์อย่างถูกต้องโดยที่โค้ดบางตัวในตัวเชื่อมต่อ SQL ของคุณอาจทำหรือไม่ทำอะไรกับมันที่สอดคล้องกับ "การหลบหนี" คุณก็ไม่ได้ ไม่รู้และไม่สนใจ คุณไม่จำเป็นต้องเขียนโค้ดใด ๆ เพื่อให้บรรลุเป้าหมายนั้นเนื่องจากเป็นกิจวัตรที่สมบูรณ์สำหรับการสืบค้น SQL ทั้งหมดของคุณเว้นแต่คุณจะเคยตัดสินใจในชีวิตที่ไม่ดี
Steve Jessop

36

ก่อน hashing รหัสผ่านที่คุณควรปกติมันตามที่อธิบายไว้ในมาตรา 4 ของ RFC 7613 โดยเฉพาะอย่างยิ่ง:

  1. กฎการแม็ปเพิ่มเติม: อินสแตนซ์ใด ๆ ของพื้นที่ที่ไม่ใช่ ASCII จะต้องแมปกับพื้นที่ ASCII (U + 0020) ช่องว่างที่ไม่ใช่ ASCII คือจุดรหัส Unicode ที่มีหมวดหมู่ทั่วไปของ Unicode เป็น "Zs" (ยกเว้น U + 0020)

และ:

  1. กฎ Normalization: ต้องใช้ Unicode Normalization Form C (NFC) กับอักขระทั้งหมด

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


3
@DavidS, Mac Book ในอเมริกาเหนือสุดแวววาว (ที่โจใช้ก่อนออกเดินทาง) และคอมพิวเตอร์อินเทอร์เน็ตคาเฟ่ของไต้หวันที่มีคุณภาพต่ำ (ที่โจพยายามใช้เพื่อดาวน์โหลดคือบัตรขึ้นเครื่องกลับ)
Margaret Bloom

2
ฟังดูตลก :-) ขอบคุณ
DavidS

3
อืม. หากคุณทำเช่นนี้คุณควรตรวจสอบรหัสผ่านเพื่อปฏิเสธสิ่งที่มีอักขระที่ยังไม่ได้กำหนด มันจะแย่มากถ้าผู้ใช้ใช้ NEWFANGLED SPACE ซึ่งแอปของคุณไม่รู้จักจึงแฮชตามที่เป็นอยู่จากนั้นคุณอัปเกรดฐานข้อมูลอักขระ Unicode ของคุณและทันใดนั้น NEWFANGLED SPACE จะถูกแมปกับ SPACE ก่อนที่จะแฮช ไม่สามารถป้อนรหัสผ่านที่แอปของคุณจะแฮชเก่าได้อีกต่อไป
ruakh

4
@JayBlanchard เนื่องจากเมื่อคุณกด Space Bar บนเครื่องหนึ่งและเมื่อคุณกดบนเครื่องอื่นคุณอาจได้รับรหัส Unicode สองจุดที่แตกต่างกันและจะมีการเข้ารหัส UTF-8 ที่แตกต่างกันสองรายการโดยที่ผู้ใช้ไม่ทราบอะไรเลย อาจเป็นที่ถกเถียงกันอยู่ว่านี่เป็นปัญหาที่คุณต้องการละเว้น แต่ RFC 7613 เกิดจากปัญหาในชีวิตจริงเช่นนี้ไม่ใช่คำแนะนำในการทำงาน
Unslander Monica

1
@ruakh เมื่อคุณตัดสินใจว่าจะจัดการรหัสผ่านด้วยวิธีใดวิธีหนึ่งรหัสเหล่านั้นจะต้องได้รับการจัดการด้วยวิธีนั้นไม่เช่นนั้นสิ่งอื่นจะเสียหายสำหรับกรณีการใช้งานที่มีอยู่ หากคุณตั้งใจที่จะเปลี่ยนวิธีการประมวลผลล่วงหน้าในอนาคตคุณควรจัดเก็บไว้พร้อมกับการแสดงรหัสผ่านที่ผ่านการประมวลผลล่วงหน้าและแฮช ด้วยวิธีนี้เมื่อคุณได้รับอินพุตคุณจะเลือกวิธีการก่อนการประมวลผล / การแฮชตามสิ่งที่คุณกำลังเปรียบเทียบ
Unslander Monica
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.