ควรใช้วิธีปฏิบัติที่ดีที่สุดในสคริปต์การเข้าสู่ระบบ PHP อย่างไร


27

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

ฉันจะใช้ PHP และฐานข้อมูล MySQL

ฉันเคยใช้ md5 แต่ฉันเห็นว่า sha256 หรือ sha512 น่าจะดีกว่า (พร้อมแฮชและเกลือที่ปลอดภัย)

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

ฉันยังใช้แนวปฏิบัติที่ดีที่สุดเล็กน้อยในการใช้งานเซสชันใน PHP 5 (ครั้งล่าสุดที่ฉันอ่านคือ PHP 4) ดังนั้นแนวปฏิบัติที่ดีที่สุดบางข้ออาจเป็นประโยชน์

ขอบคุณ


1
โยนสคริปต์ของคุณใน codereview.SE!
คริส

@Chris CodeReview ช่วยด้วยความชัดเจนของรหัสและสิ่งที่ชอบ คุณไม่ควรไปหาพวกเขาเพื่อความปลอดภัย หากมีสิ่งใดพวกเขามักจะเตือนคุณไม่ให้ "ม้วนตัวคุณเอง" ซึ่งเป็นคำตอบเดียวกับที่เขาจะได้รับในชุมชนการเขียนโปรแกรมใด ๆ ใน SE
Alternatex

คำตอบ:


21

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

ถ้าด้วยเหตุผลบางอย่างคุณไม่สามารถใช้เฟรมเวิร์กต่อไปนี้เป็นคำแนะนำ:

คำแนะนำที่เกี่ยวข้องกับความปลอดภัย

  • ใช้ PBKDF2 หรือ bcrypt ถ้าคุณสามารถ มันทำเพื่อสิ่งนั้น

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

  • ถ้าคุณทำไม่ได้อย่างน้อยอย่าใช้ MD5 / SHA1 ไม่เคย ลืมมันไปเถอะ ตัวอย่างเช่นใช้ SHA512 แทน ใช้เกลือด้วย

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

  • ใน PHP 5.5.0 และภายหลังการใช้งานและpassword_hashpassword_verify

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

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

    การป้องกันอื่นจะเป็นการตั้งค่าขีดจำกัดความล้มเหลวต่อชั่วโมง หากผู้ใช้ส่งรหัสผ่านไม่ถูกต้อง 3600 ชั่วโมงใน 1 ชั่วโมงรหัสผ่าน 1 ต่อวินาทีก็ยากที่จะเชื่อว่านี่เป็นผู้ใช้ที่ถูกกฎหมาย

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

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

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

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

  • อย่าจดจำข้อมูลรับรองผู้ใช้ในคุกกี้เว้นแต่ผู้ใช้ขอให้ทำ (ช่องทำเครื่องหมาย "จดจำฉัน" จะต้องไม่ถูกตรวจสอบโดยค่าเริ่มต้นเพื่อหลีกเลี่ยงข้อผิดพลาดของมนุษย์)

คำแนะนำในการใช้งานง่าย

  • ปล่อยให้ผู้ใช้จำรหัสผ่านหากต้องการแม้ว่าเบราว์เซอร์ส่วนใหญ่จะมีคุณสมบัตินี้อยู่แล้ว
  • อย่าใช้วิธีการที่ Google เมื่อแทนที่จะถามชื่อผู้ใช้และรหัสผ่านของผู้ใช้จะถามบางครั้งสำหรับรหัสผ่านเพียง<span/>ชื่อผู้ใช้ที่มีการแสดงอยู่แล้วใน เบราว์เซอร์ไม่สามารถกรอกฟิลด์รหัสผ่านในกรณีนี้ (อย่างน้อย Firefox ไม่สามารถทำได้) ดังนั้นจึงบังคับให้ออกจากระบบจากนั้นเข้าสู่ระบบด้วยรูปแบบปกติที่เต็มไปด้วยเบราว์เซอร์
  • อย่าใช้ป๊อปอัปที่เปิดใช้งาน JavaScriptสำหรับการเข้าสู่ระบบ มันทำลายคุณสมบัติจำรหัสผ่านของเบราว์เซอร์ (และดูดในทุกกรณี)
  • ให้ผู้ใช้ใส่ทั้งชื่อผู้ใช้ของเธอหรือที่อยู่อีเมลของเธอ เมื่อฉันลงทะเบียนบางครั้งชื่อผู้ใช้ที่ฉันต้องการป้อนนั้นถูกใช้ไปแล้วดังนั้นฉันจึงต้องประดิษฐ์ชื่อใหม่ ฉันมีโอกาสทั้งหมดที่จะลืมชื่อนี้ในอีกสองชั่วโมง
  • ให้ลิงก์ไปยังคุณสมบัติ "ลืมรหัสผ่านของฉัน" เสมอใกล้กับแบบฟอร์มการเข้าสู่ระบบ อย่าแสดงเฉพาะเมื่อผู้ใช้ไม่สามารถเข้าสู่ระบบได้: ผู้ใช้ที่จำรหัสผ่านของเธอไม่ทราบว่าจะต้องส่งรหัสผิดเพื่อดูลิงก์ "ลืมรหัสผ่านของฉัน"
  • อย่าใช้การรักษาความปลอดภัยโดยการโพสต์มัน
  • อย่าคิดค้นกฎโง่เกี่ยวข้องกับรหัสผ่านในการที่จะทำให้มันอ่อนแอ ตัวอย่าง: "รหัสผ่านของคุณจะต้องเริ่มต้นด้วยตัวอักษรตัวเล็ก"; "รหัสผ่านของคุณต้องไม่มีช่องว่าง"

ไม่เจอ bcrypt คุณมีเหตุผลอะไรในการแนะนำสิ่งนั้น ทำไมไม่ md5 / sha1 ขอบคุณสำหรับคำแนะนำที่เหลือ!
baritoneuk

เหตุผลง่าย ๆbcryptคือทำโดยคนที่มีคุณสมบัติสูง มันผ่านการทดสอบตรวจสอบและอื่น ๆ ดังนั้นจึงไม่มีเหตุผลที่จะใช้สิ่งเดียวกันกับตัวเอง มันเหมือนกับการสร้างอัลกอริทึมการเข้ารหัสของคุณเองสำหรับเว็บไซต์ของคุณ * "ทำไมไม่ md5 / sha1?": ดูตัวอย่างen.wikipedia.org/wiki/MD5#Security
Arseni Mourzenko

5
bcrypt นั้นช้าและได้รับการกล่าวถึงโดยมืออาชีพ md5 เป็นอัลกอริทึมการแปลงแป้นพิมพ์ไม่ใช่การเข้ารหัสซึ่งไม่เหมือนกัน การแฮชไฟล์อย่างรวดเร็วนั้นดี md5 จะถูกใช้ที่นี่ ... การแฮชรหัสผ่านไม่จำเป็นต้องเร็วนัก bcrypt สามารถช่วยได้ที่นี่ เหตุผลที่ฉันพูดแบบนี้คือแรงเดรัจฉานกลายเป็นเรื่องยากเมื่ออัลกอริทึม crypt "ช้า"
Chris

2
@baritoneuk: ขั้นต่ำสุดยอด แต่ฉันไม่สามารถนับจำนวนไซต์ที่ฉันเคยไปที่มีข้อ จำกัด เช่นความยาวสูงสุดไม่มีตัวอักษรที่ไม่ใช่ตัวอักษรและตัวเลข ฯลฯ น่าประหลาดใจถ้าคุณกำลังจะแฮรหัสผ่านต่อไป - ซึ่งทำให้ฉันกังวลว่าพวกเขาจะไม่ พวกเขากำลังเก็บมันไว้ในฐานข้อมูลอย่างชัดเจน
Carson63000

1
@Brian Ortiz: ไม่เสมอไป บางครั้งเป็นความคิดที่ดีที่จะกำหนดวงเงิน หากคุณไม่ทำเช่นนั้นคุณจะทดสอบว่าใบสมัครของคุณใช้ได้นานหรือไม่? อย่างไร? หากคุณไม่ได้ทดสอบคุณจะแน่ใจได้อย่างไรว่ามันใช้งานได้ แต่เมื่อตั้งค่าขีด จำกัด เป็นค่าที่เหมาะสมเช่น 100 คุณสามารถทดสอบรหัสผ่านได้ 100 ตัว
Arseni Mourzenko

6
  1. เว็บไซต์ของคุณควรใช้ HTTPS คุณไม่ควรแสดงหน้าเข้าสู่ระบบหรือยอมรับการเข้าสู่ระบบจากการเชื่อมต่อที่ไม่ได้เข้ารหัส
  2. คุกกี้ของคุณควรถูก จำกัด ที่ HTTP เท่านั้นและถูก จำกัด ให้เชื่อมต่ออย่างปลอดภัยหากคุณใช้ HTTPS
  3. กระบวนการเข้าสู่ระบบควรใช้เวลาไม่น้อยกว่า 2 วินาที (1 ถ้าคุณคิดว่า 2 วินาทีนั้นยาวเกินไป) ใช้แฮชที่ปลอดภัยเมื่อจัดเก็บและตรวจสอบรหัสผ่านและใช้เกลือที่คาดเดายาก ใช้bcryptถ้าเป็นไปได้ มิฉะนั้นให้ใช้แฮชชนิดซ้ำชนิดอื่น
  4. ไม่เคยmysql_real_escape_stringเขียนสืบค้นฐานข้อมูลของคุณในทางที่ต้องใช้ฟังก์ชั่นเช่นใด อย่าใช้การต่อสตริงเพื่อสร้างคำถามของคุณ ใช้แบบสอบถามที่เตรียมไว้เป็นพารามิเตอร์ ส่วนใหญ่ถ้าไม่ได้ทั้งหมดไดรเวอร์ DB สำหรับ PHP สนับสนุน หากคุณไม่ทราบวิธีการที่จะทำมันใช้เวลาเรียนรู้บางวิธีการprepare, bindและexecuteการใช้สิ่งที่ DB คุณกำลังใช้ มันเป็นเพียงวิธีการตรวจสอบเพื่อป้องกันตัวเองจากการฉีด SQL PDO รองรับสิ่งนี้
  5. ส่งเสริมให้ผู้ใช้ของคุณไม่ใช้รหัสผ่านเดียวกันกับที่ใช้กับอีเมลของพวกเขา เตือนพวกเขาว่าหากไซต์ของคุณถูกบุกรุกและหากพวกเขาใช้รหัสผ่านเดียวกันทั้งสองแห่งใครบางคนสามารถขโมยอีเมลได้

+1 สำหรับ HTTPS เนื่องจากมีการรับส่งข้อมูลมากขึ้นผ่านเครือข่าย WiFi สาธารณะ แต่ฉันไม่เห็นด้วยกับจุด 3: 2 วินาทีนานเกินไปจากมุมมองของผู้ใช้ 0.5 วิ ไม่เป็นไรโดยเฉพาะถ้าใช้เทคนิคต่อต้านกำลังดุร้ายอื่น ๆ
Arseni Mourzenko

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

@chrisw: ใช่ข้อมูลผู้ใช้ทั้งหมดควรได้รับการจัดการราวกับว่ามันเป็นอันตราย แต่เมื่อคุณใช้คำสั่ง parametrized มันเป็นบาร์ไม่มีวิธีที่ดีที่สุดที่จะหยุดฉีด SQL หากคุณไม่ได้ใช้แบบสอบถามที่เตรียมไว้และเป็นพารามิเตอร์คุณมีความเสี่ยงต่อการฉีด SQL mysql_real_escape_stringเป็นการรักษาความปลอดภัยที่ผิดพลาด - ไม่ใช่การรับประกัน Parametrized แบบสอบถามคือ
greyfade

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

1
คุณสามารถใช้ PDO
เฟลิกซ์ G

1

ใช้แฮชทางเดียวแบบเค็ม (ควรใช้ SHA512 โดยใช้http://au2.php.net/manual/en/function.hash.php ) ... ด้วยวิธีนี้ถ้ามีคนแฮกฐานข้อมูลของคุณแม้ว่าพวกเขาจะรู้ว่าเกลือ พวกเขาไม่สามารถแยกรหัสผ่าน (โดยไม่มีตารางสายรุ้งซึ่งจะเป็น looong สำหรับ SHA512)

ใช้ HTTPS

อย่าส่งการยืนยันชื่อผู้ใช้ / รหัสผ่านทางอีเมลกลับไปยังผู้ใช้เมื่อลงทะเบียน

หากคุณอนุญาตให้ใช้คุกกี้สำหรับ 'จดจำฉัน' - เพิ่มการเข้าสู่ระบบเพิ่มเติมเพื่อเข้าถึงการจัดการและฟังก์ชั่นการแก้ไขโปรไฟล์

หากผู้ใช้รหัสผ่านไม่ถูกต้องอย่าบอกว่าพวกเขาได้รับรหัสผ่านที่ไม่ถูกต้อง (กล่าวว่าพวกเขามี 'ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง' ตลอดเวลา) - วิธีนี้ให้เบาะแสว่าชื่อผู้ใช้ที่ถูกต้องคืออะไร

ลองและใช้ชื่อหน้าจอกับการเข้าสู่ระบบ - ด้วยวิธีนี้ผู้ใช้น้อยกว่าจะแสดงชื่อการเข้าสู่ระบบในรายชื่อผู้ใช้


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

1
  • ห้ามใช้อัลกอริทึมการแปลงแป้นพิมพ์ MD5 หรือ SHA1 ติดใหม่กว่าเช่น SHA512 เสมอ
  • ใช้เกลือที่สร้างแบบสุ่มที่แข็งแกร่งเสมอ
  • อย่าส่งอีเมลรหัสผ่านให้กับผู้ใช้แม้ในกรณีที่ "ลืมรหัสผ่าน"
  • ห้ามใช้ฟังก์ชัน mysql_ * พวกเขาคิดค่าเสื่อมราคานาน ติดกับ PDO
  • อย่าเก็บรหัสผ่านในเซสชันหรือคุกกี้

0

นี่คือคำแนะนำเล็กน้อย: ตรวจสอบให้แน่ใจว่าคุกกี้ของคุณไม่สามารถเข้าถึงด้วย JS เพื่อป้องกันการโจรกรรมได้โปรดดูการปกป้องคุกกี้ของคุณ:บทความHttpOnlyโดย Jeff Atwood

... ด้วยการสร้างที่ชาญฉลาด URL ที่มีรูปแบบไม่ถูกต้องจะจัดการกับสารที่ผ่านการฆ่าเชื้อ รหัสที่แสดงผลสุดท้ายเมื่อดูในเบราว์เซอร์จะโหลดและเรียกใช้สคริปต์จากเซิร์ฟเวอร์ระยะไกลนั้น

... ใครก็ตามที่โหลดหน้าโปรไฟล์ผู้ใช้สคริปต์นี้ได้ส่งคุกกี้เบราว์เซอร์ของพวกเขาไปยังเซิร์ฟเวอร์ระยะไกลที่ชั่วร้ายโดยไม่รู้ตัว!

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

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