อ่าน 12 นาที
โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย
โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย ( SRP ) เป็น โปรโตคอล การแลกเปลี่ยนคีย์ที่ตรวจสอบความถูกต้องด้วยรหัสผ่าน (PAKE) ที่ได้รับการปรับปรุง...
โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย
โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย ( SRP ) เป็น โปรโตคอล การแลกเปลี่ยนคีย์ที่ตรวจสอบความถูกต้องด้วยรหัสผ่าน (PAKE) ที่ได้รับการปรับปรุง ซึ่งออกแบบมาโดยเฉพาะเพื่อแก้ไขปัญหาสิทธิบัตรที่มีอยู่[ 1 ]
เช่นเดียวกับโปรโตคอล PAKE ทั้งหมด ผู้ดักฟังหรือผู้แทรกแซงไม่สามารถได้รับข้อมูลเพียงพอที่จะสามารถ เดา รหัสผ่านแบบ brute-force หรือใช้ การโจมตีแบบพจนานุกรมได้โดยไม่ต้องมีการโต้ตอบเพิ่มเติมกับฝ่ายต่างๆ สำหรับการเดาแต่ละครั้ง ยิ่งไปกว่านั้น เนื่องจากเป็นโปรโตคอล PAKE ที่ได้รับการปรับปรุง เซิร์ฟเวอร์จึงไม่เก็บข้อมูลที่เทียบเท่ากับรหัสผ่าน[ 2 ]ซึ่งหมายความว่าผู้โจมตีที่ขโมยข้อมูลเซิร์ฟเวอร์ไม่สามารถปลอมตัวเป็นไคลเอนต์ได้ เว้นแต่พวกเขาจะทำการค้นหารหัสผ่านแบบ brute-force ก่อน
กล่าวโดยง่าย ในระหว่างการตรวจสอบสิทธิ์แบบ SRP (หรือโปรโตคอล PAKE อื่นๆ) ฝ่ายหนึ่ง ("ไคลเอ็นต์" หรือ "ผู้ใช้") แสดงให้ฝ่ายอื่น ("เซิร์ฟเวอร์") เห็นว่าตนเองรู้รหัสผ่าน โดยไม่ต้องส่งรหัสผ่านหรือข้อมูลอื่นใดที่สามารถนำมาคำนวณหารหัสผ่านได้ รหัสผ่านจะไม่เคยออกจากไคลเอ็นต์และเซิร์ฟเวอร์จะไม่ทราบ
นอกจากนี้ เซิร์ฟเวอร์ยังจำเป็นต้องทราบรหัสผ่าน (แต่ไม่จำเป็นต้องทราบรหัสผ่านโดยตรง) เพื่อเริ่มต้นการเชื่อมต่อที่ปลอดภัย ซึ่งหมายความว่าเซิร์ฟเวอร์จะตรวจสอบความถูกต้องของตัวเองกับไคลเอนต์ด้วย ทำให้ป้องกันการหลอกลวงโดยไม่ต้องพึ่งพาผู้ใช้ในการวิเคราะห์ URL ที่ซับซ้อน
คุณสมบัติความปลอดภัยที่ได้รับการพิสูจน์ทางคณิตศาสตร์เพียงอย่างเดียวของ SRP คือเทียบเท่ากับ Diffie-Hellman เมื่อเผชิญกับผู้โจมตีแบบพาสซีฟ[ 3 ]แม้ว่า SRP จะมีความสมบูรณ์และใช้งานอย่างแพร่หลาย แต่ก็เป็นการออกแบบที่เก่ากว่าและมีบางรูปแบบที่แสดงจุดอ่อนเล็กน้อย คือไม่ปลอดภัยแบบ UCขาดความต้านทานต่อ การโจมตี แบบ precomputation ทั้งหมด มีการพิสูจน์อย่างเป็นทางการที่อ่อนแอกว่า และไม่มีการป้องกันต่อรูปแบบการโจมตีสมัยใหม่บางแบบ ด้วยเหตุผลเหล่านี้ ปัจจุบัน SRP จึงถือว่าล้าสมัยไปแล้ว OPAQUE เป็น PAKE เสริมที่นิยมใช้ ในขณะที่ CPace หรือ SPAKE2 เป็นที่นิยมสำหรับสถานการณ์ PAKE ที่สมดุลซึ่งทั้งสองฝ่ายแบ่งปันรหัสผ่าน[ 4 ] [ 5 ]
ภาพรวม
โปรโตคอล SRP มีคุณสมบัติที่น่าสนใจหลายประการ ได้แก่ อนุญาตให้ผู้ใช้ยืนยันตัวตนกับเซิร์ฟเวอร์ได้ ทนทานต่อการโจมตีแบบพจนานุกรมที่กระทำโดยผู้ดักฟัง และไม่ต้องการบุคคลที่สามที่น่าเชื่อถือ โดยพื้นฐานแล้วมันส่งต่อการพิสูจน์รหัสผ่านแบบไร้ความรู้จากผู้ใช้ไปยังเซิร์ฟเวอร์ ในเวอร์ชัน 6 ของโปรโตคอลนี้ สามารถเดารหัสผ่านได้เพียงครั้งเดียวต่อการพยายามเชื่อมต่อแต่ละครั้ง คุณสมบัติที่น่าสนใจอย่างหนึ่งของโปรโตคอลนี้คือ แม้ว่าหนึ่งหรือสองส่วนของหลักการเข้ารหัสที่ใช้จะถูกโจมตี มันก็ยังคงปลอดภัย โปรโตคอล SRP ได้รับการปรับปรุงแก้ไขหลายครั้ง และปัจจุบันอยู่ในเวอร์ชัน 6a
โปรโตคอล SRP สร้างคีย์ส่วนตัวขนาดใหญ่ที่ใช้ร่วมกันระหว่างสองฝ่ายในลักษณะที่คล้ายกับการแลกเปลี่ยนคีย์ Diffie–Hellmanโดยฝั่งไคลเอ็นต์มีรหัสผ่านของผู้ใช้และฝั่งเซิร์ฟเวอร์มี ตัวตรวจสอบ การเข้ารหัสที่ได้มาจากรหัสผ่าน คีย์สาธารณะที่ใช้ร่วมกันนั้นได้มาจากตัวเลขสุ่มสองตัว ตัวหนึ่งสร้างโดยไคลเอ็นต์และอีกตัวหนึ่งสร้างโดยเซิร์ฟเวอร์ ซึ่งแต่ละตัวจะมีเอกลักษณ์เฉพาะสำหรับการเข้าสู่ระบบแต่ละครั้ง ในกรณีที่ต้องการการสื่อสารที่เข้ารหัสและการตรวจสอบสิทธิ์ โปรโตคอล SRP จะมีความปลอดภัยมากกว่า โปรโตคอล SSHและเร็วกว่าการใช้การแลกเปลี่ยนคีย์ Diffie–Hellmanกับข้อความที่ลงนาม นอกจากนี้ยังเป็นอิสระจากบุคคลที่สาม ซึ่งแตกต่างจาก Kerberos
โปรโตคอล SRP เวอร์ชัน 3 ได้รับการอธิบายไว้ใน RFC 2945 SRP เวอร์ชัน 6a ยังใช้สำหรับการตรวจสอบความถูกต้องของรหัสผ่านที่รัดกุมในSSL/TLS [ 6 ] (ในTLS-SRP ) และมาตรฐานอื่นๆ เช่นEAP [ 7 ]และSAMLและเป็นส่วนหนึ่งของIEEE 1363.2และ ISO/IEC 11770-4
โปรโตคอล
ในคำอธิบายโปรโตคอลเวอร์ชัน 6 นี้ ใช้สัญลักษณ์ดังต่อไปนี้:
- เลือกqและN = 2q + 1 โดยที่ทั้งคู่เป็นจำนวนเฉพาะ (ซึ่งทำให้ qเป็นจำนวนเฉพาะโซฟี แฌร์แม็งและNเป็นจำนวนเฉพาะที่ปลอดภัย ) Nต้องมีขนาดใหญ่พอที่จะทำให้การคำนวณลอการิทึมแบบไม่ต่อเนื่องมอดูลNเป็นไปไม่ได้
- การคำนวณเลขคณิตทั้งหมดจะดำเนินการในวงแหวนของจำนวนเต็มมอดูลN ซึ่งหมายความว่าg x ด้านล่าง ควรอ่านว่าg x mod N
- gเป็นตัวสร้างของกลุ่มการคูณ
- H () คือ ฟังก์ชัน แฮชเช่น SHA-256
- kเป็นพารามิเตอร์ที่ได้มาจากทั้งสองฝ่าย ใน SRP-6 k = 3 ในขณะที่ใน SRP-6a จะได้มาจากNและg : k = H ( N , g ) ใช้เพื่อป้องกันการเดาแบบ 2 ต่อ 1 เมื่อผู้โจมตีที่ใช้งานอยู่ปลอมตัวเป็นเซิร์ฟเวอร์[ 8 ] [ 9 ]
- sคือเกลือชนิด หนึ่ง
- Iคือชื่อผู้ใช้ที่ใช้ระบุตัวตน
- pคือรหัสผ่านของผู้ใช้
- vคือตัวตรวจสอบรหัสผ่านของโฮสต์ โดยv = g xซึ่งอย่างน้อยที่สุดx = H ( s , p ) เนื่องจากxถูกคำนวณเฉพาะบนฝั่งไคลเอ็นต์ จึงสามารถเลือกอัลกอริทึมที่แข็งแกร่งกว่าได้ การใช้งานอาจเลือกใช้x = H ( s | I | p )โดยไม่ส่งผลกระทบต่อขั้นตอนใดๆ ที่โฮสต์ต้องดำเนินการ มาตรฐานRFC2945กำหนดx = H ( s | H ( I | ":" | p ) )การใช้Iภายในxช่วยป้องกันไม่ให้เซิร์ฟเวอร์ที่เป็นอันตรายสามารถเรียนรู้ได้ว่าผู้ใช้สองคนใช้รหัสผ่านเดียวกัน หรือ ไม่
- AและBคือคีย์ชั่วคราวแบบสุ่มที่ใช้ได้ครั้งเดียวของผู้ใช้และโฮสต์ตามลำดับ
- | (เครื่องหมาย |) หมายถึงการเชื่อมต่อ
ตัวแปรอื่นๆ ทั้งหมดถูกกำหนดโดยอ้างอิงจากตัวแปรเหล่านี้
ขั้นแรก เพื่อสร้างรหัสผ่านpกับเซิร์ฟเวอร์ Steve ลูกค้า Carol จะเลือกค่า salt แบบสุ่มsและคำนวณ x = H ( s , p ) , v = gx Steve จะจัดเก็บvและsโดยใช้ดัชนีIเป็นตัวตรวจสอบรหัสผ่านและค่า salt ของ Carol Carol ต้องไม่เปิดเผยxให้กับใคร และต้องลบมันอย่างปลอดภัยในขั้นตอนนี้ เพราะมันเทียบเท่ากับรหัสผ่านp ที่เป็นข้อความธรรมดา ขั้นตอนนี้เสร็จสมบูรณ์ก่อนที่ระบบจะถูกใช้เป็นส่วนหนึ่งของการลงทะเบียนผู้ใช้กับ Steve โปรดทราบว่าค่า salt sจะถูกแบ่งปันและแลกเปลี่ยนเพื่อเจรจาคีย์เซสชันในภายหลัง ดังนั้นค่าอาจถูกเลือกโดยฝ่ายใดฝ่ายหนึ่ง แต่ Carol เป็นผู้เลือกเพื่อให้เธอสามารถลงทะเบียนI , sและvในคำขอลงทะเบียนเดียว การส่งและการตรวจสอบความถูกต้องของคำขอลงทะเบียนไม่ได้กล่าวถึงใน SRP
จากนั้น เพื่อทำการตรวจสอบรหัสผ่านในภายหลัง จะมีการดำเนินการตามโปรโตคอลการแลกเปลี่ยนดังต่อไปนี้:
- แครอล → สตีฟ: สร้างค่าสุ่มa ; ส่งIและA = g a
- Steve → Carol: สร้างค่าสุ่มb ; ส่งsและB = kv + g b
- ทั้งสอง: u = H ( A , B )
- แคโรล: S แคโรล = ( B − kg x ) ( a + ux ) = ( kv + g b − kg x ) ( a + ux ) = ( kg x − kg x + g b ) (a + ux) = ( g b ) ( a + ux )
- แครอล: K แครอล = H ( S แครอล )
- Steve: S Steve = ( Av u ) b = ( g a v u ) b = [ g a ( g x ) u ] b = ( g a + ux ) b = ( g b ) (a + ux)
- สตีฟ: K สตีฟ = H ( S สตีฟ ) = K แครอล
ขณะนี้ทั้งสองฝ่ายมีคีย์เซสชันที่แข็งแกร่งร่วมกันแล้ว คือ Kในการตรวจสอบสิทธิ์ให้เสร็จสมบูรณ์ พวกเขาจำเป็นต้องพิสูจน์ให้กันและกันเห็นว่าคีย์ของพวกเขานั้นตรงกัน วิธีหนึ่งที่เป็นไปได้มีดังนี้:
- Carol → Steve: M 1 = H [ H ( N ) XOR H ( g ) | H ( I ) | s | A | B | K Carol ] Steve ตรวจสอบM 1แล้ว
- Steve → Carol: M 2 = H ( A | M 1 | K Steve ) . Carol ตรวจสอบM 2แล้ว
วิธีการนี้จำเป็นต้องเดาข้อมูลสถานะที่ใช้ร่วมกันมากกว่าแค่กุญแจสำคัญเพื่อให้การปลอมแปลงตัวตนสำเร็จ ในขณะที่ข้อมูลสถานะเพิ่มเติมส่วนใหญ่เป็นข้อมูลสาธารณะ ข้อมูลส่วนตัว เช่น กุญแจส่วนตัวของเซิร์ฟเวอร์ สามารถเพิ่มเข้าไปในอินพุตของฟังก์ชันแฮชได้อย่างปลอดภัย
อีกทางเลือกหนึ่ง ในการพิสูจน์โดยใช้รหัสผ่านเพียงอย่างเดียว สามารถข้ามการคำนวณK ไปได้ และพิสูจน์ S ร่วมกันได้ ด้วย:
- Carol → Steve: M 1 = H ( A | B | S Carol ) . Steve ตรวจสอบM 1แล้ว
- Steve → Carol: M 2 = H ( A | M 1 | S Steve ) . Carol ตรวจสอบM 2แล้ว
เมื่อใช้ SRP ในการเจรจาเพื่อสร้างคีย์ร่วมKซึ่งจะถูกนำไปใช้ทันทีหลังจากการเจรจาเสร็จสิ้น อาจดูเหมือนง่ายที่จะข้ามขั้นตอนการตรวจสอบM1และM2 เซิร์ฟเวอร์จะปฏิเสธคำขอแรกจากไคลเอ็นต์ที่ไม่สามารถถอดรหัสได้ อย่างไรก็ตาม การทำเช่นนี้อาจเป็นอันตรายได้ ดังที่แสดงไว้ในส่วน " ข้อผิดพลาดในการใช้งาน "ด้านล่าง
ทั้งสองฝ่ายยังได้ใช้มาตรการป้องกันดังต่อไปนี้:
- แครอลจะทำแท้งหากเธอได้รับB = 0 (mod N ) หรือu = 0
- สตีฟจะยกเลิกหากเขาได้รับA (mod N ) = 0
- แครอลต้องแสดงหลักฐานการพิสูจน์K (หรือS ) ของเธอก่อน หากสตีฟตรวจพบว่าหลักฐานการพิสูจน์ของแครอลไม่ถูกต้อง เขาต้องยกเลิกโดยไม่แสดงหลักฐานการพิสูจน์ K (หรือS ) ของตนเอง
ตัวอย่างโค้ดในภาษา Python
""" ตัวอย่างการตรวจสอบสิทธิ์ SRPคำเตือน: ห้ามใช้เพื่อวัตถุประสงค์ทางด้านการเข้ารหัสลับจริงนอกเหนือจากการทดสอบคำเตือน: โค้ดด้านล่างนี้ขาดมาตรการป้องกันที่สำคัญ มันไม่ได้ตรวจสอบว่า A, B และ U ไม่เป็นศูนย์อ้างอิงจาก http://srp.stanford.edu/design.html """ import hashlib import random# หมายเหตุ: str แปลงตามเดิม str([1,2,3,4]) จะแปลงเป็น "[1,2,3,4]" def H ( * args ) -> int : """ฟังก์ชันแฮชแบบทางเดียว""" a = ":" . join ( str ( a ) for a in args ) return int ( hashlib . sha256 ( a . encode ( "utf-8" )) . hexdigest (), 16 )def cryptrand ( n : int = 1024 ): return random . SystemRandom () . getrandbits ( n ) % N# จำนวนเฉพาะขนาดใหญ่ที่ปลอดภัย (N = 2q+1 โดยที่ q เป็นจำนวนเฉพาะ) # การคำนวณทั้งหมดทำโดยใช้โมดูลัส N # (สร้างโดยใช้ "openssl dhparam -text 1024") N = """00:c0:37:c3:75:88:b4:32:98:87:e6:1c: 2d:a3:32: 4b:1b:a4:b8:1a:63:f9:74:8f:ed:2d:8a:41:0c:2f: c2:1b:12:32:f0:d3:bf:a0:24:27:6c:fd:88:44:81: 97:aa:e4:86:a6:3b:fc:a7:b8:bf:77:54:df:b3:27: c7:20:1f:6f:d1:7f:d7:fd:74:15:8b:d3:1c:e7:72: c9:f5:f8:ab:58:45:48:a9:9a:75:9b:5a:2c:05:32: 16:2b:7b:62:18:e8:f1:42:bc:e2:c3:0d:77:84:68: 9a:48:3e:09:5e:70:16:18:43:79:13:a8:c3:9c:3d: d0:d4:ca:3c:50:0b:88:5f:e3"""N = int ( "" . join ( N . split ()) . replace ( ":" , "" ), 16 ) g = 2 # ตัวสร้างโมดูลัส Nk = H ( N , g ) # พารามิเตอร์ตัวคูณ (k=3 ใน SRP-6 แบบดั้งเดิม)F = '#0x' # ตัวระบุรูปแบบprint ( "#. H, N, g และ k เป็นที่ทราบล่วงหน้าทั้งฝั่งไคลเอ็นต์และเซิร์ฟเวอร์:" ) print ( f ' { H = } \n { N = :{ F }} \n { g = :{ F }} \n { k = :{ F }} ' )พิมพ์( " 0. เซิร์ฟเวอร์จัดเก็บ (I, s, v) ในฐานข้อมูลรหัสผ่าน" )# เซิร์ฟเวอร์ต้องสร้างตัวตรวจสอบรหัสผ่านก่อนI = "person" # ชื่อผู้ใช้p = "password1234" # รหัสผ่านs = cryptrand ( 64 ) # เกลือสำหรับผู้ใช้x = H ( s , I , p ) # คีย์ส่วนตัวv = pow ( g , x , N ) # ตัวตรวจสอบรหัสผ่านprint ( f ' { I = } \n { p = } \n { s = :{ F }} \n { x = :{ F }} \n { v = :{ F }} ' )# 0. เซิร์ฟเวอร์จัดเก็บ (I, s, v) ในฐานข้อมูลรหัสผ่าน# I = 'person' # p = 'password1234' # s = 0x67bc8932cfd26a49 # x = 0x98a4bce8dde877762a90222f1a1161eba9248590a47eb83aa9e5bd7ecda5368d # v = 0xa7e2038e675d577ac0f318999cab67bba7ec2daf45d2d09f7911b1b78d2fc7f963cd0ac8f17851e0516f059e453672c3b70fcecf5f6843180b271a bdd01f552ccda7b24fe4719336409cbc1352f8517be651b8935cc0b74ff2819fa07a3f031537d4cfd9f8df7b788a5f2f88e1cd4106b35c38b3d7205a# <สาธิต> --- หยุด ---print ( " 1. ไคลเอนต์ส่งชื่อผู้ใช้ I และค่าชั่วคราวสาธารณะ A ไปยังเซิร์ฟเวอร์" ) a = cryptrand () A = pow ( g , a , N ) print ( f " { I = } \n { A = :{ F }} " ) # ไคลเอนต์->เซิร์ฟเวอร์ (I, A)# 1. ไคลเอนต์ส่งชื่อผู้ใช้ I และค่าชั่วคราวสาธารณะ A ไปยังเซิร์ฟเวอร์# I = 'บุคคล' # A = 0x678556a7e76581e051af656e8cee57ae46df43f1fce790f7750a3ec5308a85da4ec4051e5cb74d3e463685ee975a2747cf49035be67c931b56e793 f23ea3524af8909dcfbc8675d872361025bf884778587ac49454a57c53a011ac2be2839bfb51bf7847a49a483aba870dc7a8b467a81cec91b8ae7813# <สาธิต> --- หยุด ---print ( " 2. เซิร์ฟเวอร์ส่งค่า salt s ของผู้ใช้และค่าชั่วคราวสาธารณะ B ไปยังไคลเอ็นต์" ) b = cryptrand () B = ( k * v + pow ( g , b , N )) % N print ( f " { s = :{ F }} \n { B = :{ F }} " ) # server->client (s, B)# 2. เซิร์ฟเวอร์ส่งค่า salt s ของผู้ใช้และค่าชั่วคราวสาธารณะ B ไปยังไคลเอ็นต์# s = 0x67bc8932cfd26a49 # B = 0xb615a0a5ea6abf138077bbd869f6a8da37dfc0b7e06a9f5fac5c1e4109c6302cb3e94dcc2cc76da7b3d87d7e9b68a1db998ab239cfde609f3f7a1e ce4a491ce3d9a665c20cf4e4f06730daaa8f52ed61e45bbb67cdc337bf648027ffa7f0f215d5ebe43f9f51832518f1142266aae0dfa960e0082b5154# <สาธิต> --- หยุด ---print ( " 3. ไคลเอนต์และเซิร์ฟเวอร์คำนวณพารามิเตอร์การสุ่ม" ) u = H ( A , B ) # พารามิเตอร์การสุ่มprint ( f " { u = :{ F }} " )# 3. ไคลเอนต์และเซิร์ฟเวอร์คำนวณพารามิเตอร์การสุ่มสลับ# u = 0x796b07e354c04f672af8b76a46560655086355a9bbce11361f01b45d991c0c52# <สาธิต> --- หยุด ---print ( " 4. ไคลเอนต์คำนวณคีย์เซสชัน" ) x = H ( s , I , p ) S_c = pow ( B - k * pow ( g , x , N ), a + u * x , N ) K_c = H ( S_c ) print ( f " { S_c = :{ F }} \n { K_c = :{ F }} " )# 4. ไคลเอนต์คำนวณคีย์เซสชัน# S_c = 0x699170aff6e9f08ed09a1dff432bf0605b8bcba05aadcaeea665757d06dbda4348e211d16c10ef4678585bcb2809a83c62b6c19d97901274ddafd4075f90604c06baf036af587af8540342b47867eaa22b9ca5e35ac14c8e85a0c4e623bd855828dffd513cea4d829c407137a0dd81ab4cde8a904c45cc # K_c = 0x43f8df6e1d2ba762948c8316db5bf03a7af49391742f5f51029630711c1671e# <สาธิต> --- หยุด ---print ( " 5. เซิร์ฟเวอร์คำนวณคีย์เซสชัน" ) S_s = pow ( A * pow ( v , u , N ), b , N ) K_s = H ( S_s ) print ( f " { S_s = :{ F }} \n { K_s = :{ F }} " )# 5. เซิร์ฟเวอร์คำนวณคีย์เซสชัน# S_s = 0x699170aff6e9f08ed09a1dff432bf0605b8bcba05aadcaeea665757d06dbda4348e211d16c10ef4678585bcb2809a83c62b6c19d97901274ddafd4075f90604c06baf036af587af8540342b47867eaa22b9ca5e35ac14c8e85a0c4e623bd855828dffd513cea4d829c407137a0dd81ab4cde8a904c45cc # K_s = 0x43f8df6e1d2ba762948c8316db5bf03a7af49391742f5f51029630711c1671e# <สาธิต> --- หยุด ---print ( " 6. ไคลเอ็นต์ส่งหลักฐานของคีย์เซสชันไปยังเซิร์ฟเวอร์" ) M_c = H ( H ( N ) ^ H ( g ), H ( I ), s , A , B , K_c ) print ( f " { M_c = :{ F }} " ) # ไคลเอ็นต์->เซิร์ฟเวอร์ (M_c) ; เซิร์ฟเวอร์ตรวจสอบ M_c# 6. ไคลเอ็นต์ส่งหลักฐานของคีย์เซสชันไปยังเซิร์ฟเวอร์# M_c = 0x75500df4ea36e06406ac1f8a8241429b8e90a8cba3adda3405c07f19ea3101e8# <สาธิต> --- หยุด ---print ( " 7. เซิร์ฟเวอร์ส่งหลักฐานของคีย์เซสชันไปยังไคลเอ็นต์" ) M_s = H ( A , M_c , K_s ) print ( f " { M_s = :{ F }} " ) # เซิร์ฟเวอร์->ไคลเอ็นต์ (M_s) ; ไคลเอ็นต์ตรวจสอบ M_s# 7. เซิร์ฟเวอร์ส่งหลักฐานของคีย์เซสชันไปยังไคลเอ็นต์# M_s = 0x182ed24d1ad2fb55d2268c46b42435d1ef02e0fc49f647c03dab8b2a48b0bd3dข้อผิดพลาดในการนำไปปฏิบัติ
การโจมตีแบบ Brute Force ออฟไลน์ด้วยการส่งข้อความแบบ Server-first โดยไม่มีการตรวจสอบคีย์
หากเซิร์ฟเวอร์ส่งข้อความที่เข้ารหัสโดยไม่รอการตรวจสอบจากไคลเอนต์ ผู้โจมตีจะสามารถทำการโจมตีแบบ Brute Force ออฟไลน์ได้คล้ายกับการถอดรหัสแฮช ซึ่งอาจเกิดขึ้นได้หากเซิร์ฟเวอร์ส่งข้อความที่เข้ารหัสในแพ็กเก็ตที่สองพร้อมกับค่า Salt และBหรือหากข้ามขั้นตอนการตรวจสอบคีย์และเซิร์ฟเวอร์ (แทนที่จะเป็นไคลเอนต์) ส่งข้อความที่เข้ารหัสแรก ซึ่งเป็นสิ่งที่ดึงดูดใจเพราะหลังจากแพ็กเก็ตแรก เซิร์ฟเวอร์จะมีข้อมูลทั้งหมดเพื่อคำนวณคีย์ร่วมKแล้ว
ขั้นตอนการโจมตีมีดังนี้:
- แครอล → สตีฟ: สร้างค่าสุ่มa ; ส่งIและA = g a
- สตีฟ: u = H ( A , B ); S = Av u ; K = H ( S )
- Steve: สร้างข้อความmและเข้ารหัสเพื่อสร้างc =ENC( K , m )
- Steve → Carol: สร้างค่าสุ่มb ; ส่งs , B = kv + g bและc
แครอลไม่รู้จัก ค่า xหรือvแต่ถ้าให้รหัสผ่านp ใดๆ เธอก็สามารถคำนวณได้ดังนี้:
- x p = H (เกลือ, p )
- S p = ( B - กก. x พี ) ( a + ux p )
- K p = H ( S p )
Kpคือกุญแจที่สตีฟจะใช้หากpคือรหัสผ่านที่คาดไว้ ค่าทั้งหมดที่จำเป็นในการคำนวณKp นั้นถูกควบคุมโดยแครอลหรือทราบจากแพ็กเก็ตแรกจากสตีฟ แครอลสามารถลองเดารหัสผ่าน สร้างกุญแจที่เกี่ยวข้อง และพยายามถอดรหัสข้อความที่เข้ารหัสc ของสตีฟ เพื่อตรวจสอบกุญแจได้ เนื่องจากข้อความโปรโตคอลมักมีโครงสร้าง จึงสันนิษฐานได้ว่าการระบุว่าcถูกถอดรหัสอย่างถูกต้องนั้นทำได้ง่าย ซึ่งช่วยให้สามารถกู้คืนรหัสผ่านแบบออฟไลน์ได้
การโจมตีนี้จะไม่สามารถเกิดขึ้นได้หากสตีฟรอให้แครอลพิสูจน์ได้ว่าเธอสามารถคำนวณคีย์ที่ถูกต้องได้ก่อนที่จะส่งข้อความที่เข้ารหัส การใช้งาน SRP ที่ถูกต้องจะไม่ได้รับผลกระทบจากการโจมตีนี้ เนื่องจากผู้โจมตีจะไม่สามารถผ่านขั้นตอนการตรวจสอบคีย์ได้
การโจมตีแบบ Brute Force ออฟไลน์โดยอาศัยการจับเวลา
ในปี 2021 Daniel De Almeida Braga, Pierre-Alain Fouque และ Mohamed Sabt ได้ตีพิมพ์ PARASITE [ 10 ]ซึ่งเป็นเอกสารที่พวกเขาสาธิตการใช้ประโยชน์จากการโจมตีแบบจับเวลาบนเครือข่ายในทางปฏิบัติ โดยใช้ประโยชน์จากการใช้งานที่ไม่คงที่ของการยกกำลังแบบโมดูลาร์ของตัวเลขขนาดใหญ่ และส่งผลกระทบต่อ OpenSSL โดยเฉพาะ
การนำไปใช้
- ตัวแปร SRP-6:ไลบรารี Java ของฟังก์ชันพื้นฐานทางด้านการเข้ารหัสลับที่จำเป็นสำหรับการใช้งานโปรโตคอล SRP-6
- OpenSSLเวอร์ชัน 1.0.1 หรือใหม่กว่า
- Botan (ไลบรารีการเข้ารหัสลับที่เขียนด้วยภาษา C++) มีการใช้งาน SRP-6a อยู่ภายใน
- TLS-SRPคือชุดรหัสลับสำหรับความปลอดภัยระดับชั้นการขนส่งที่ใช้ SRP
- srp-clientคือการใช้งาน SRP-6a ในJavaScript (เข้ากันได้กับ RFC 5054) เป็นโอเพนซอร์ส ภายใต้ใบ อนุญาต Mozilla Public License (MPL)
- ไลบรารีJavaScript Crypto Libraryประกอบด้วยการใช้งานโปรโตคอล SRP ในภาษา JavaScript ซึ่งเป็นโอเพนซอร์สและ ได้รับอนุญาตภายใต้ใบ อนุญาตBSD
- Gnu Cryptoเป็น ไลบรารีที่เขียนด้วย ภาษา Javaซึ่งได้รับอนุญาตภายใต้GNU General Public Licenseโดยมี "ข้อยกเว้นสำหรับไลบรารี" ซึ่งอนุญาตให้ใช้งานเป็นไลบรารีร่วมกับซอฟต์แวร์ที่ไม่ใช่โอเพนซอร์สได้
- Legion of the Bouncy Castle ให้บริการซอฟต์แวร์ที่ เขียนด้วยภาษา Java และC#ภายใต้สัญญาอนุญาต MIT
- Nimbus SRPเป็นไลบรารี Java ที่ให้บริการตัวสร้างตัวตรวจสอบความถูกต้อง เซสชันฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์ รวมถึงอินเทอร์เฟซสำหรับคีย์รหัสผ่านแบบกำหนดเอง รูทีนข้อความหลักฐานฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์ ไม่มีการพึ่งพาภายนอกใดๆ เผยแพร่ภายใต้ ใบอนุญาต Apache 2.0
- srplibcppเป็นไลบรารี C++ ที่พัฒนาต่อยอดจากMIRACL
- DragonSRPเป็นการใช้งานแบบโมดูลาร์ที่เขียนด้วยภาษา C++ ซึ่งปัจจุบันใช้งานได้กับOpenSSL
- Json2Ldapให้บริการการตรวจสอบสิทธิ์แบบ SRP-6a สำหรับเซิร์ฟเวอร์ไดเร็กทอรีLDAP
- การใช้งาน csrp SRP-6a ในภาษา C
- การใช้งาน Crypt-SRP SRP-6a ในภาษาPerl
- การใช้งาน pysrp SRP-6a ในภาษา Python (ใช้งานร่วมกับcsrp ได้ )
- การใช้งาน py3srp SRP-6a ด้วยPython3บริสุทธิ์
- srptoolsเครื่องมือสำหรับใช้งานการตรวจสอบสิทธิ์ด้วยรหัสผ่านระยะไกลที่ปลอดภัย (SRP) ในPython ตรวจสอบ แล้วว่าใช้ไลบรารีเดียวกัน
- ระบบบัญชีผู้ใช้ของ Meteor Web Framework ใช้ SRP สำหรับการตรวจสอบสิทธิ์ด้วยรหัสผ่าน
- srp-rbการใช้งาน SRP-6a ในภาษา Ruby
- falkmueller demo การใช้งานโปรโตคอลStanford SRP-6aในJavaScriptและPHPภายใต้ใบอนุญาต MIT
- srp-6a-demoการใช้งาน SRP-6a ในPHPและJavaScript
- thinbus-srp-js คือ การใช้งาน SRP-6a ในJavaScriptมาพร้อมกับ คลาส Java ที่เข้ากันได้ ซึ่งใช้Nimbus SRP (เก็บถาวรเมื่อ 2014-02-22 บนWayback Machine)แอปพลิเคชันสาธิตที่ใช้Spring Securityนอกจากนี้ยังมีแอปพลิเคชันสาธิตการตรวจสอบสิทธิ์ไปยัง เซิร์ฟเวอร์ PHPเผยแพร่ภายใต้Apache License
- Stanford JavaScript Crypto Library (SJCL)ใช้หลักการ SRP สำหรับการแลกเปลี่ยนคีย์
- node-srpเป็นการนำหลักการ SRP มาใช้ในรูปแบบไคลเอ็นต์และเซิร์ฟเวอร์ด้วย JavaScript (node.js)
- SRP6 สำหรับการใช้งานในภาษา C# และ Java
- ALOSRPAuthเป็นการใช้งาน SRP-6a ที่เขียนด้วยภาษา Objective-C
- go-srpคือการนำหลักการ SRP-6a มาใช้ในภาษา Go
- tssrp6aคือการนำ SRP-6a มาใช้ในรูปแบบ TypeScript
- ไลบรารี IceNet Cryptography Java สำหรับพัฒนาแอปพลิเคชัน Spring Boot ที่ใช้การเข้ารหัสลับ รองรับมาตรฐาน SRP-6a อยู่ภายใต้ลิขสิทธิ์ Apache License
- การนำSRP-6a ไปใช้ใน .NET
- Apple Homekit ใช้ SRP เมื่อจับคู่กับอุปกรณ์และเครื่องใช้ไฟฟ้าในบ้านอัจฉริยะ
- การตรวจสอบสิทธิ์ Proton Mailสำหรับการเข้ารหัสอีเมล
- SRPเป็นการนำ SRP มาเขียนด้วยภาษา Go ซึ่งใช้ในการตรวจสอบสิทธิ์ผู้ใช้บนPosterity
ประวัติศาสตร์
โครงการ SRP เริ่มต้นในปี 1997 [ 11 ]แนวทางที่แตกต่างกันสองวิธีในการแก้ไขช่องโหว่ด้านความปลอดภัยใน SRP-1 ส่งผลให้เกิด SRP-2 และ SRP-3 [ 12 ] SRP-3 ได้รับการเผยแพร่ครั้งแรกในปี 1998 ในการประชุม[ 13 ] RFC 2945 ซึ่งอธิบาย SRP-3 ด้วย SHA1 ได้รับการเผยแพร่ในปี 2000 [ 14 ] SRP-6 ซึ่งแก้ไขการโจมตีแบบเดา "สองต่อหนึ่ง" และการโจมตีแบบเรียงลำดับข้อความ ได้รับการเผยแพร่ในปี 2002 [ 8 ] SRP-6a ปรากฏใน "libsrp" อย่างเป็นทางการในเวอร์ชัน 2.1.0 ลงวันที่ 2005 [ 15 ] SRP-6a พบได้ในมาตรฐานดังนี้:
- ISO/IEC 11770-4:2006 "กลไกข้อตกลงหลัก 2" (เรียกวิธีการนี้ว่า "SRP-6" แต่มี การคำนวณ kเป็น 6a)
- RFC 5054 TLS-SRP ปี 2007 (เรียกอีกครั้งว่า "SRP-6" แต่แก้ไขใน erratum [ 16 ] )
- IEEE Std 1363.2-2008 "DLAPKAS-SRP6" (เรียกอีกครั้งว่า "SRP-6") [ 17 ]
IEEE 1363.2 ยังรวมถึงคำอธิบายของ "SRP5" ซึ่งเป็นรูปแบบที่แทนที่ลอการิทึมแบบไม่ต่อเนื่องด้วยเส้นโค้งวงรีที่ Yongge Wang นำเสนอในปี 2001 [ 18 ]นอกจากนี้ยังอธิบาย SRP-3 ดังที่พบใน RFC 2945
ดูเพิ่มเติม
- การตรวจสอบสิทธิ์แบบท้าทาย-ตอบสนอง
- การตกลงรหัสลับที่ตรวจสอบด้วยรหัสผ่าน
- กลไกการตรวจสอบความถูกต้องด้วยการตอบโต้แบบมีเกลือ (SCRAM)
- การแลกเปลี่ยนคีย์แบบเลขชี้กำลังรหัสผ่านอย่างง่าย
- การพิสูจน์รหัสผ่านแบบ Zero-knowledge
ลิงก์ภายนอก
- เว็บไซต์อย่างเป็นทางการ
- ใบอนุญาต SRP —โอเพนซอร์สแบบ BSD
- US6539479 - สิทธิบัตร SRP (หมดอายุเมื่อวันที่ 12 พฤษภาคม 2558 เนื่องจากไม่ชำระค่าบำรุงรักษา (ตามข้อมูลจาก Google Patents) เดิมกำหนดหมดอายุในเดือนกรกฎาคม 2561)
หน้าคู่มือ
- pppd(8) : เดมอนโปรโตคอลแบบจุดต่อจุด
- srptool(1) : เครื่องมือรหัสผ่าน SRP แบบง่าย
อาร์เอฟซี
- RFC 2944 - การตรวจสอบสิทธิ์ Telnet: SRP
- RFC 2945 - ระบบการตรวจสอบสิทธิ์และการแลกเปลี่ยนคีย์ SRP (เวอร์ชัน 3)
- RFC 3720 - อินเทอร์เฟซระบบคอมพิวเตอร์ขนาดเล็กทางอินเทอร์เน็ต (iSCSI)
- RFC 3723 - การรักษาความปลอดภัยของโปรโตคอลการจัดเก็บข้อมูลแบบบล็อกผ่าน IP
- RFC 3669 - แนวทางสำหรับคณะทำงานด้านประเด็นทรัพย์สินทางปัญญา
- RFC 5054 - การใช้โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย (SRP) สำหรับการตรวจสอบสิทธิ์ TLS
ลิงก์อื่นๆ
- อีอีอีอี 1363
- สไลด์เกี่ยวกับทรัพย์สินทางปัญญาของ SRP (ธันวาคม 2544 - อาจล้าสมัยแล้ว)สิทธิบัตรของ EKE ที่กล่าวถึงหมดอายุในปี 2554 และ 2556
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย
โปรโตคอลรหัสผ่านระยะไกลที่ปลอดภัย ( SRP ) เป็น โปรโตคอล การแลกเปลี่ยนคีย์ที่ตรวจสอบความถูกต้องด้วยรหัสผ่าน (PAKE) ที่ได้รับการปรับปรุง...
ภาพรวม
โปรโตคอล SRP มีคุณสมบัติที่น่าสนใจหลายประการ ได้แก่ อนุญาตให้ผู้ใช้ยืนยันตัวตนกับเซิร์ฟเวอร์ได้ ทนทานต่อ การโจมตีแบบพจนานุกรม ที่กระทำโดยผู้ดักฟัง และไม่ต้องการ บุคคลที่สามที่น่าเชื่อถือ โดย พื้นฐานแล้วมันส่งต่อ การพิสูจน์รหัสผ่านแบบไร้ความรู้...
โปรโตคอล
ในคำอธิบายโปรโตคอลเวอร์ชัน 6 นี้ ใช้สัญลักษณ์ดังต่อไปนี้:
ตัวอย่างโค้ดในภาษา Python
""" ตัวอย่างการตรวจสอบสิทธิ์ SRP คำเตือน: ห้ามใช้เพื่อวัตถุประสงค์ทางด้านการเข้ารหัสลับจริงนอกเหนือจากการทดสอบ คำเตือน: โค้ดด้านล่างนี้ขาดมาตรการป้องกันที่สำคัญ มันไม่ได้ตรวจสอบว่า A, B และ U ไม่เป็นศูนย์ อ้างอิงจาก http://srp.stanford.edu/design.