ขอให้พิมพ์ตัวเลขได้เฉย ๆ ก็พอ
(gendignoux.com/blog)- ช่องกรอกยืนยันอีเมล 6 หลักของระบบล็อกอินรัฐบาลสวิตเซอร์แลนด์ AGOV ไม่สามารถจัดการการป้อนตัวเลขจากคีย์บอร์ด AZERTY แบบฝรั่งเศสได้ ทำให้การสมัครบัญชีถูกขัดขวางตั้งแต่ต้น
- JavaScript ของช่องกรอกดักจับการกดแป้นและเก็บรหัสยืนยันไว้ในตัวแปรแยกต่างหาก แต่ ละเลยปุ่ม Shift จึงปิดกั้นเลย์เอาต์ AZERTY ที่ต้องใช้ Shift เพื่อพิมพ์ตัวเลขโดยพฤตินัย
- ข้อผิดพลาดเดียวกันเกิดขึ้นกับหลายชุดผสมของ Firefox·Chromium·Chrome·Safari และ Linux·macOS แต่คีย์บอร์ด QWERTY ใช้งานได้ปกติ จึงจำกัดสาเหตุได้ว่าเป็น ปัญหาเลย์เอาต์คีย์บอร์ด ไม่ใช่เบราว์เซอร์หรือระบบปฏิบัติการ
- แม้แต่การขอรับการสนับสนุนอย่างเป็นทางการก็ต้องผ่านการยืนยันอีเมลแบบเดียวกันก่อน และไม่มีช่องทางสำรองอย่างอีเมลหรือโทรศัพท์ ผู้ใช้ที่ล็อกอินไม่ได้จึง ไม่สามารถรายงานบั๊กการล็อกอินได้ด้วยซ้ำ
- หากใช้ตรรกะจัดการปุ่มที่ซับซ้อนแทนช่องกรอกแบบเนทีฟ และผูกผลิตภัณฑ์กับช่องทางสนับสนุนไว้กับขั้นตอนยืนยันเดียวกัน ทั้งการเข้าถึงและการรับมือเหตุขัดข้องจะพังไปพร้อมกัน จึงจำเป็นต้องมี การป้อนข้อมูลแบบ DOM ที่เรียบง่าย และช่องทางสนับสนุนที่เป็นอิสระ
AGOV ที่กลายเป็นโครงสร้างพื้นฐานตัวตนดิจิทัล
- ตัวตนดิจิทัลกลายเป็นประเด็นถกเถียงสำคัญของเว็บในช่วงหลัง พร้อมความพึ่งพาอาศัยกันและข้อถกเถียงหลายด้าน
- ผลกระทบของกฎหมายยืนยันอายุต่อ ความไม่เปิดเผยตัวตนออนไลน์
- ความเป็นไปได้ที่ Wikipedia ในสหราชอาณาจักรจะต้อง ยืนยันตัวตนผู้ใช้
- ปัญหาการ พึ่งพา iOS และ Android ทางการในฐานะแพลตฟอร์มจำเป็นสำหรับกระเป๋าตัวตนดิจิทัล
- กรณีที่ บัญชีดิจิทัล ในสหรัฐฯ ถูกยกเลิกเพียงเพราะเป็นผู้พิพากษาศาลอาญาระหว่างประเทศ
- ระบบล็อกอินของรัฐบาลสวิตเซอร์แลนด์ AGOV เริ่มดำเนินงานตั้งแต่ปี 2024 และมีจำนวนบัญชีถึง 1.6 ล้านบัญชี
- กำลังถูกขยายให้เป็นวิธีล็อกอินสำหรับงานภาครัฐหลายอย่าง รวมถึงการใช้ประกันการว่างงานและการยื่นภาษีภาคบังคับ
- ในรัฐซูริก เป็นวิธีล็อกอินเพียงอย่างเดียวสำหรับการเข้าถึง การยื่นขอสัญชาติ
การสมัครที่หยุดค้างตรงขั้นตอนยืนยันอีเมล
- ขั้นตอนสมัคร AGOV เริ่มจากการส่งอีเมลแอดเดรส แล้วกรอก รหัสยืนยัน 6 หลัก
- UI รหัสยืนยันประกอบด้วยช่องกรอกทั้งหมด 6 ช่อง ช่องละหนึ่งตัวเลข
- เมื่อพิมพ์ตัวเลข โฟกัสไม่ย้ายไปช่องถัดไป
- ตัวเลขสะสมอยู่ในช่องปัจจุบันต่อไป และเปลี่ยนเป็นสถานะผิดพลาดสีแดง
- แม้ย้ายช่องเองทีละหลักเพื่อกรอก สุดท้ายก็เกิดข้อผิดพลาด
field required
- พยายามแก้ค่า DOM โดยตรงในเครื่องมือนักพัฒนา แต่ไม่พบค่าฟอร์มที่มองเห็นได้ชัดเจน และไม่มีข้อผิดพลาดถูกบันทึกในเว็บคอนโซล
- แม้ใช้อีเมลแอดเดรสอื่นหรือแอดเดรสปลอมอย่าง
test@example.comผลลัพธ์ก็เหมือนเดิมexample.comเป็นโดเมนที่สงวนไว้ตาม RFC 6761
ตัดความเป็นไปได้เรื่องเบราว์เซอร์และระบบปฏิบัติการ
- ตอนแรกสงสัยว่าชุดผสม Firefox กับ Linux อาจไม่รองรับ หรือ CAPTCHA ล้มเหลว
- ก่อนฟอร์มรหัสยืนยันจะปรากฏ มีการเชื่อมต่อไปยัง
eu-api.friendlycaptcha.eu - เอกสารข้อกำหนดทางการ ระบุระบบปฏิบัติการที่รองรับไว้เฉพาะ Windows และ macOS
- แต่ คำแนะนำเรื่อง security key ระบุว่ารองรับ Linux และ Firefox ด้วย
- ก่อนฟอร์มรหัสยืนยันจะปรากฏ มีการเชื่อมต่อไปยัง
- ข้อผิดพลาดเดียวกันเกิดขึ้นใน 6 ชุดสภาพแวดล้อม ต่อไปนี้ทั้งหมด
- Firefox, Chromium, Chrome บน Linux
- Firefox, Safari, Chrome บน macOS
- บนแล็ปท็อปสำหรับงาน หลังพิมพ์แล้วระบบย้ายไปช่องถัดไปอัตโนมัติ และข้อผิดพลาด
Code entered is incorrectที่บอกว่าเป็นรหัสผิด ไม่ใช่รหัสว่าง ก็แสดงตามปกติ - บนคอมพิวเตอร์ macOS ของเพื่อน เบราว์เซอร์ทั้งสามตัวก็รับรหัสยืนยันได้เช่นกัน
- ไม่อาจพึ่งพาคอมพิวเตอร์ที่นายจ้างจัดให้เพื่อโต้ตอบกับบริการรัฐในระยะยาวได้ และแม้สมัครบนคอมพิวเตอร์ที่ทำงาน ก็ยังมีความเป็นไปได้ว่าจะล็อกอินจากแล็ปท็อปส่วนตัวไม่ได้
โครงสร้างการสนับสนุนที่ปิดกั้นแม้แต่การรายงานปัญหา
- การสนับสนุนอย่างเป็นทางการ มีให้ผ่านเว็บฟอร์มเท่านั้น และฟอร์มนี้ก็ต้องกรอกรหัสยืนยันอีเมลก่อนเช่นกัน
- FAQ ระบุว่าการสนับสนุนจากหน่วยงานที่เข้าร่วมมีให้เฉพาะ การสร้างทิกเก็ตออนไลน์ ในเวลาทำการเท่านั้น
- นอกจากที่อยู่ไปรษณีย์ของ Swiss Federal Chancellery แล้ว ไม่มีอีเมลหรือเบอร์โทรศัพท์
- ฟีเจอร์ฟีดแบ็ก สำหรับส่งคำชม คำวิจารณ์ หรือคำขอถึง AGOV ก็ต้องล็อกอินด้วย AGOV หรือบัญชีเทียบเท่าก่อน
- ผู้ใช้ที่ยืนยันอีเมลไม่สำเร็จติดอยู่ใน การพึ่งพาแบบวนลูป เพราะไม่สามารถรายงานปัญหาได้เนื่องจากขั้นตอนยืนยันเดียวกัน
-
AGOV Access และอุปกรณ์ที่รองรับ
- แอป AGOV Access บน Android มีคะแนน 1.4 แต่ไม่พบปัญหารหัสยืนยันแบบเดียวกันในรีวิว Google Play
- ในรีวิวมีคำขอจำนวนมากให้รองรับ GrapheneOS ระบบปฏิบัติการอนุพันธ์ของ Android ที่เน้นความปลอดภัยและความเป็นส่วนตัว
- ตาม FAQ ทางการ แอปไม่ทำงานเพราะเฟรมเวิร์กเสริมความแข็งแรงสำหรับป้องกันการดัดแปลงโดยไม่ได้รับอนุญาตไม่เข้ากันกับ GrapheneOS
- Federal Chancellery สั่งให้ซัพพลายเออร์ทำให้เข้ากันได้
- ปัจจุบันวิธีพิสูจน์ตัวตนชั้นที่สองสำหรับการสมัครและล็อกอินคือสมาร์ตโฟน iOS·Android พื้นฐานที่ได้รับอนุญาต หรือ security key และไม่ว่าจะใช้ทางใดก็ต้องผ่านการยืนยันอีเมลก่อน
สาเหตุที่พบใน JavaScript
- ทรัพยากรที่หน้าเว็บโหลดมีไม่มาก แต่ไฟล์ JavaScript หลักที่ถูก minify โดยไม่ obfuscate มีขนาด 2.4MB และเมื่อคลี่ออกมีมากกว่า 100,000 บรรทัด
- ค้นหาสตริง
field requiredแล้วพบตรรกะที่ตั้งค่าสถานะของรหัสยืนยัน- หากไม่มีตัวแปรรหัสยืนยัน จะตั้งสถานะเป็น
REQUIRED - หากความยาวไม่ตรงกับความยาวรหัสที่ต้องการ จะถือเป็น
WRONG - หากความยาวตรง จะใช้
VALIDหรือสถานะข้อผิดพลาดตามผลการยืนยันอีเมลจากเซิร์ฟเวอร์
- หากไม่มีตัวแปรรหัสยืนยัน จะตั้งสถานะเป็น
- ฟังก์ชัน
verificationCodeEnteredดักจับการกดปุ่มและรวบรวมรหัสยืนยันไว้ใน ตัวแปร JavaScriptEnterเรียกใช้คอลแบ็กยืนยันBackspaceล้างค่าปัจจุบัน- ปุ่มลูกศรและ
Tabย้ายระหว่างช่องกรอก - ปุ่มทั่วไปถูกแปลงเป็นตัวเลขด้วย
Number(S.key)แล้วบันทึกลงในรหัส - ปุ่มอย่าง
Control,Meta,Shift,v,rถูกคืนค่าออกไปโดยไม่ประมวลผล
- เนื่องจากตอนส่งฟอร์มไม่ได้อ่านค่า DOM แม้แก้ช่องกรอกด้วยเครื่องมือนักพัฒนาหรือส่วนขยายเบราว์เซอร์ ก็ไม่สะท้อนเข้าไปในสถานะที่ JavaScript จัดการแยกไว้
เหตุผลที่ตัวเลขถูกบล็อกเฉพาะบน AZERTY
- เลย์เอาต์ AZERTY มาตรฐานฝรั่งเศสต้องใช้ ปุ่ม Shift เพื่อพิมพ์ตัวเลข
- เพราะโค้ดละเลยอินพุต Shift บน AZERTY จึงไม่สามารถบันทึกตัวเลขเองเป็นรหัสยืนยันได้
- คอมพิวเตอร์ที่ทำงานใช้เลย์เอาต์ QWERTY ภาษาอังกฤษ และในบรรดาคนที่ช่วยตรวจสอบปัญหาไม่มีคนฝรั่งเศส
- ผลคือในบรรดาเครื่องที่ทดสอบ มีเพียงแล็ปท็อปส่วนตัวสองเครื่องที่ดูเหมือนเสีย
- เมื่อเปลี่ยนเลย์เอาต์คีย์บอร์ดในระบบปฏิบัติการเป็นเลย์เอาต์อื่น แล็ปท็อปส่วนตัวก็กรอกได้ตามปกติ
- กลับกัน เมื่อเปลี่ยนเครื่องที่เคยทำงานปกติเป็นเลย์เอาต์ฝรั่งเศส ข้อผิดพลาดเดียวกันก็เกิดซ้ำได้
- คีย์บอร์ดภาษาฝรั่งเศสมาตรฐานของสวิตเซอร์แลนด์เป็นตระกูล QWERTZ ที่พบได้ทั่วไปในยุโรปกลาง
- พิมพ์ภาษาฝรั่งเศสและเยอรมันได้อย่างมีประสิทธิภาพ และไม่ต้องใช้ Shift เพื่อพิมพ์ตัวเลข จึงไม่เกิดข้อผิดพลาดเดียวกัน
- ตาม Swiss Federal Statistical Office มีผู้พำนักสัญชาติฝรั่งเศสในสวิตเซอร์แลนด์ประมาณ 171,000 คน และตัวเลขนี้ยังไม่รวมแรงงานข้ามพรมแดนที่ต้องโต้ตอบกับรัฐบาลสวิตเซอร์แลนด์
ข้อจำกัดในการตรวจสอบก่อนเปิดซอร์ส
- ตาม AGOV FAQ ซอร์สโค้ดของ AGOV มีกำหนดเปิดเผยใน ธันวาคม 2026 เพื่อให้เป็นไปตามข้อกำหนดทางกฎหมาย
- EMBAG มาตรา 9 กำหนดให้หน่วยงานรัฐบาลกลางเผยแพร่ซอร์สโค้ดของซอฟต์แวร์ที่พัฒนาเองหรือว่าจ้างให้พัฒนาเพื่อใช้ปฏิบัติภารกิจ
- มีข้อยกเว้นเมื่อสิทธิของบุคคลที่สามหรือเหตุผลด้านความปลอดภัยขัดขวางหรือจำกัดการเผยแพร่
- สิ่งที่จะเปิดเผยคือเวอร์ชัน AGOV ที่บรรลุเป้าหมายโครงการ รวมถึง AGOV e-ID Verifier และเวอร์ชันหลังจากนั้นจะเผยแพร่ผ่าน release note ที่จัดเตรียมหลังปล่อยเวอร์ชัน
- แม้บางบริการใช้ AGOV เป็นล็อกอินบังคับแล้ว แต่ซอร์สยังไม่ถูกเปิดเผย ทำให้ผู้ใช้แจ้งบั๊กต่อนักพัฒนาโดยตรงหรือแชร์วิธีเลี่ยงปัญหาได้ยาก
ขอบเขตการยืนยันตัวตนที่ตรวจสอบหลังสมัคร
- หลังเปลี่ยนเลย์เอาต์คีย์บอร์ด จึงยืนยันอีเมลแอดเดรสและสมัครเสร็จด้วย security key
- ระหว่างสมัครมีการกรอกชื่อ เบอร์โทรศัพท์ และวันเกิด แต่ข้อมูลเหล่านี้ไม่ได้ถูกตรวจสอบ
- ในขั้นตอนสมัครพื้นฐาน สิ่งที่ตรวจสอบมีเพียงสองอย่าง
- อีเมลแอดเดรสมีอยู่จริง
- วิธีพิสูจน์ตัวตนชั้นที่สองเป็น security key รุ่นที่อนุญาต หรือเป็นแอป AGOV Access ที่ทำงานบนอุปกรณ์ Android·iOS ที่อนุญาต
- AGOV แข็งแรงต่อการยึดบัญชีด้วยฟิชชิงระยะไกล แต่ในขั้นตอนสมัครพื้นฐานไม่ได้ป้องกันการที่คนอื่นสร้างบัญชีโดยใช้ชื่อและข้อมูลตัวตนของผู้อื่น
- ผลการตรวจสอบเพิ่มเติม ระบุว่าเมื่อเข้าถึงบริการที่จัดเป็นบริการอ่อนไหว จะต้องมี การยืนยันตัวตน
- ทันทีหลังสมัคร ยังไม่ได้เข้าถึงบริการลักษณะนั้น
- รายงานบั๊กผ่านฟอร์มสนับสนุนแล้ว แต่ไม่ได้รับคำตอบ
บทเรียนจากการออกแบบ
-
การออกแบบอินพุตและการสนับสนุนที่ไม่ทนทาน
- วิธีสร้าง UI หรูหราด้วยช่องกรอก 6 ช่องและตรรกะ JavaScript ซับซ้อนไม่ทนทาน
- ใช้ช่องกรอกเนทีฟของเบราว์เซอร์ช่องเดียว แล้วตกแต่งรูปลักษณ์ด้วย CSS จะดีกว่า
- หากแยกตรรกะฟอร์มออกจาก DOM อย่างสมบูรณ์ จะอ่านค่า DOM ตอนส่งฟอร์มไม่ได้ และผู้ใช้ขั้นสูงหรือส่วนขยายเบราว์เซอร์ก็แก้ค่าอินพุตไม่ได้
- หากมีช่องทางสนับสนุนเพียงช่องทางเดียว เมื่อช่องทางนั้นเสียเองก็จะไม่มีวิธีติดต่อ จึงต้องมี ช่องทางที่สอง อย่างอีเมลหรือโทรศัพท์
- หากใช้ตรรกะล็อกอินเดียวกันกับทั้งผลิตภัณฑ์หลักและช่องทางสนับสนุน จะพลาดรายงานบั๊กจากผู้ใช้ที่ล็อกอินไม่ได้
- การที่บริการอินเทอร์เน็ตหลายแห่งวางหน้าสถานะไว้บนโดเมนแยกก็ด้วยเหตุผลเดียวกัน
- การวางคำขอสนับสนุนไว้หลังการยืนยันอีเมลช่วยลดสแปมได้ แต่ก็ลดรายงานเหตุขัดข้องจากผู้ใช้จริงไปพร้อมกัน
- หากเปิดซอร์สโค้ดก็ต่อเมื่อบังคับใช้ระบบกับบางบริการไปแล้ว การแก้ปัญหาของผู้ใช้และการแชร์บั๊กหรือวิธีเลี่ยงจะถูกจำกัด
- การเปิดซอร์สตามกฎหมายไม่ใช่แค่รายการให้ปฏิบัติตาม แต่ยังมีประโยชน์ต่อการสืบสวนเหตุขัดข้องจริงด้วย
-
เว็บเปิดที่ช่วยในการตรวจสอบ
- ตรรกะ JavaScript ที่เกี่ยวข้องไม่ถูก obfuscate จึงค้นหาสาเหตุได้ด้วยการค้นหาสตริงไม่กี่ครั้ง
- ไม่จำเป็นต้องใช้ decompiler ขั้นสูงหรือ LLM ราคาแพง
- หากโค้ดถูก obfuscate หรือคอมไพล์เป็น WebAssembly การระบุสาเหตุคงใช้เวลามากกว่านี้มาก
- เพราะโค้ดไม่ได้ถูกแจกจ่ายเฉพาะบนระบบปฏิบัติการปิดที่ได้รับอนุมัติ แต่ให้บริการบน เว็บเปิด จึงดาวน์โหลดรูปแบบที่ถูก minify มาตรวจสอบได้
-
เงื่อนไขที่ทำให้ระบุสาเหตุได้
- การเปรียบเทียบแล็ปท็อปหลายเครื่องที่ใช้เลย์เอาต์คีย์บอร์ดต่างกัน ช่วยลดความเป็นไปได้ของปัญหารายเบราว์เซอร์หรือปัญหาเครือข่ายได้ตั้งแต่ต้น
- อย่างไรก็ตาม เพื่อยืนยันว่าไม่ใช่ความผิดพลาดของผู้ใช้ ต้องใช้เวลาเก็บหลักฐานช่วงแรกไปกับการจับภาพหน้าจอของแต่ละชุดเบราว์เซอร์อย่างเป็นระบบ
1 ความคิดเห็น
ความคิดเห็นจาก Lobste.rs
หนึ่งในแนวปฏิบัติบนอินเทอร์เน็ตที่ไม่ชอบเป็นพิเศษคือเว็บไซต์ที่ ดักจับการกดแป้นพิมพ์แล้วจัดการเองตามใจ แทนที่จะส่งต่อให้เบราว์เซอร์ตามปกติ
เว็บไซต์ที่ห้ามคัดลอกและวางในช่องรหัสผ่านนั้นพบได้บ่อยกว่ามาก แต่นี่ก็อยู่ในประเภทเดียวกัน และอาจดูร้ายแรงกว่าด้วยซ้ำ
ส่วนใหญ่แล้วมีแต่เพิ่มความซับซ้อนด้วยเหตุผลที่ฝืน ๆ
วิธีที่ แยกช่องกรอกหนึ่งช่องต่อหนึ่งตัวอักษร เหมือนโรคระบาด
พอบริษัทหนึ่งนำมาใช้เพราะดูเท่ ตอนนี้ทุกคนก็พากันทำเวอร์ชันของตัวเอง
ผู้ใช้จะรู้ได้ทันทีว่านี่ไม่ใช่ช่องรหัสผ่าน แม้ไม่ต้องอ่านอย่างละเอียด
กรณีที่เกี่ยวข้องคือ Medium once had a bug like this which prevented entering the character 'Ś'
ลองคิดวิธีใช้งานแบบอื่นแล้ว แต่สุดท้ายก็ยังหาวิธีที่ดีกว่า
<input type="text" />ธรรมดา ไม่ได้แม้แต่การตกแต่งด้วย CSS ให้ดูต่างจากช่องกรอกทั่วไปมากเกินไปก็ยังลังเลอยู่ อาจแสดงค่าที่กรอกซ้ำในช่องใหญ่ ๆ ได้ แต่ก็ต้องตอบปัญหาสารพัด เช่น ถ้าผู้ใช้กรอกเกินความยาวที่อนุญาตจะทำอย่างไร และข้อดีก็ไม่ได้มากพอให้คุ้มกับความพยายาม อย่างมากก็คงเปลี่ยนแค่ฟอนต์และขนาดของช่องกรอก
1224แทน1234วิธีแก้ที่เร็วที่สุดคือคลิกเลข
2ตัวที่สองแล้วกด3แต่ทำด้วย HTML+CSS อย่างเดียวไม่ได้<input type="text" pattern="[0-9]+" minlength=6 maxlength=6>หนึ่งช่อง ดูเหมือนเป็นหกช่องด้วยการตั้งระยะห่างตัวอักษรแปลก ๆ ได้ไหมวิธีที่ง่ายกว่าคือให้ผู้ใช้กรอกในช่องข้อความเดียว แล้วให้ JavaScript วาดช่องหกช่องไว้ที่ตำแหน่งอื่นใน DOM และอัปเดตด้วยอีเวนต์
inputที่เกิดขึ้นทุกครั้งที่กดแป้นยากจะมั่นใจว่าวิธีไหนดีกว่าด้านการเข้าถึง จากมุมมองของโปรแกรมอ่านหน้าจอ วิธีหลังที่ใช้
<input>ธรรมดาร่วมกับ<canvas alt="">สำหรับตกแต่งอาจดีกว่าด้วยซ้ำ และการใช้งานคีย์บอร์ดก็ไม่เพี้ยนไปด้วย แต่สำหรับผู้ใช้ที่ใช้เครื่องมือช่วยเหลืออื่นนอกเหนือจากโปรแกรมอ่านหน้าจอ การซ่อน<input>ทางสายตาอาจกลายเป็น หายนะด้านการเข้าถึง ได้ จึงต้องระมัดระวังอย่างมากจะให้ ทั้งรหัสและลิงก์เปิดใช้งาน ในอีเมลเหมือนบริการจำนวนมากก็ได้
แบบนี้ก็แก้ปัญหาเดียวกันได้
อาจมองว่านี่เป็นสถานการณ์พิเศษก็ได้ แต่การเข้าถึงก็คือการจัดการข้อยกเว้นแบบนั้นให้ถูกต้องนั่นเอง
Tridactyl ก็มี ปัญหาเดียวกันเป๊ะ https://github.com/tridactyl/tridactyl/issues/3257
มีรายงานครั้งแรกในปี 2019 และไม่แน่ว่าเรื่องครั้งนี้อาจทำให้อายจนต้องแก้ในที่สุด
นี่แสดงให้เห็นอีกครั้งว่า การทำเว็บไซต์ให้ พังหรือช้า ต้องใช้ความพยายามมากกว่าการทำเว็บไซต์ที่ใช้งานได้ตามปกติเสียอีก