1 คะแนน โดย GN⁺ 3 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ช่องกรอกยืนยันอีเมล 6 หลักของระบบล็อกอินรัฐบาลสวิตเซอร์แลนด์ AGOV ไม่สามารถจัดการการป้อนตัวเลขจากคีย์บอร์ด AZERTY แบบฝรั่งเศสได้ ทำให้การสมัครบัญชีถูกขัดขวางตั้งแต่ต้น
  • JavaScript ของช่องกรอกดักจับการกดแป้นและเก็บรหัสยืนยันไว้ในตัวแปรแยกต่างหาก แต่ ละเลยปุ่ม Shift จึงปิดกั้นเลย์เอาต์ AZERTY ที่ต้องใช้ Shift เพื่อพิมพ์ตัวเลขโดยพฤตินัย
  • ข้อผิดพลาดเดียวกันเกิดขึ้นกับหลายชุดผสมของ Firefox·Chromium·Chrome·Safari และ Linux·macOS แต่คีย์บอร์ด QWERTY ใช้งานได้ปกติ จึงจำกัดสาเหตุได้ว่าเป็น ปัญหาเลย์เอาต์คีย์บอร์ด ไม่ใช่เบราว์เซอร์หรือระบบปฏิบัติการ
  • แม้แต่การขอรับการสนับสนุนอย่างเป็นทางการก็ต้องผ่านการยืนยันอีเมลแบบเดียวกันก่อน และไม่มีช่องทางสำรองอย่างอีเมลหรือโทรศัพท์ ผู้ใช้ที่ล็อกอินไม่ได้จึง ไม่สามารถรายงานบั๊กการล็อกอินได้ด้วยซ้ำ
  • หากใช้ตรรกะจัดการปุ่มที่ซับซ้อนแทนช่องกรอกแบบเนทีฟ และผูกผลิตภัณฑ์กับช่องทางสนับสนุนไว้กับขั้นตอนยืนยันเดียวกัน ทั้งการเข้าถึงและการรับมือเหตุขัดข้องจะพังไปพร้อมกัน จึงจำเป็นต้องมี การป้อนข้อมูลแบบ DOM ที่เรียบง่าย และช่องทางสนับสนุนที่เป็นอิสระ

AGOV ที่กลายเป็นโครงสร้างพื้นฐานตัวตนดิจิทัล

  • ตัวตนดิจิทัลกลายเป็นประเด็นถกเถียงสำคัญของเว็บในช่วงหลัง พร้อมความพึ่งพาอาศัยกันและข้อถกเถียงหลายด้าน
  • ระบบล็อกอินของรัฐบาลสวิตเซอร์แลนด์ AGOV เริ่มดำเนินงานตั้งแต่ปี 2024 และมีจำนวนบัญชีถึง 1.6 ล้านบัญชี
  • กำลังถูกขยายให้เป็นวิธีล็อกอินสำหรับงานภาครัฐหลายอย่าง รวมถึงการใช้ประกันการว่างงานและการยื่นภาษีภาคบังคับ

การสมัครที่หยุดค้างตรงขั้นตอนยืนยันอีเมล

  • ขั้นตอนสมัคร AGOV เริ่มจากการส่งอีเมลแอดเดรส แล้วกรอก รหัสยืนยัน 6 หลัก
  • UI รหัสยืนยันประกอบด้วยช่องกรอกทั้งหมด 6 ช่อง ช่องละหนึ่งตัวเลข
    • เมื่อพิมพ์ตัวเลข โฟกัสไม่ย้ายไปช่องถัดไป
    • ตัวเลขสะสมอยู่ในช่องปัจจุบันต่อไป และเปลี่ยนเป็นสถานะผิดพลาดสีแดง
    • แม้ย้ายช่องเองทีละหลักเพื่อกรอก สุดท้ายก็เกิดข้อผิดพลาด field required
  • พยายามแก้ค่า DOM โดยตรงในเครื่องมือนักพัฒนา แต่ไม่พบค่าฟอร์มที่มองเห็นได้ชัดเจน และไม่มีข้อผิดพลาดถูกบันทึกในเว็บคอนโซล
  • แม้ใช้อีเมลแอดเดรสอื่นหรือแอดเดรสปลอมอย่าง test@example.com ผลลัพธ์ก็เหมือนเดิม
    • example.com เป็นโดเมนที่สงวนไว้ตาม RFC 6761

ตัดความเป็นไปได้เรื่องเบราว์เซอร์และระบบปฏิบัติการ

  • ตอนแรกสงสัยว่าชุดผสม Firefox กับ Linux อาจไม่รองรับ หรือ CAPTCHA ล้มเหลว
  • ข้อผิดพลาดเดียวกันเกิดขึ้นใน 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 ดักจับการกดปุ่มและรวบรวมรหัสยืนยันไว้ใน ตัวแปร JavaScript
    • Enter เรียกใช้คอลแบ็กยืนยัน
    • 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 ความคิดเห็น

 
GN⁺ 3 시간 전
ความคิดเห็นจาก Lobste.rs
  • หนึ่งในแนวปฏิบัติบนอินเทอร์เน็ตที่ไม่ชอบเป็นพิเศษคือเว็บไซต์ที่ ดักจับการกดแป้นพิมพ์แล้วจัดการเองตามใจ แทนที่จะส่งต่อให้เบราว์เซอร์ตามปกติ
    เว็บไซต์ที่ห้ามคัดลอกและวางในช่องรหัสผ่านนั้นพบได้บ่อยกว่ามาก แต่นี่ก็อยู่ในประเภทเดียวกัน และอาจดูร้ายแรงกว่าด้วยซ้ำ

    • ไม่เข้าใจว่าทำไมต้องใช้ JavaScript มาเขียนใหม่ในสิ่งที่เบราว์เซอร์ รองรับเป็นพื้นฐานอยู่แล้วด้วย HTML และ CSS เท่านั้น
      ส่วนใหญ่แล้วมีแต่เพิ่มความซับซ้อนด้วยเหตุผลที่ฝืน ๆ
  • วิธีที่ แยกช่องกรอกหนึ่งช่องต่อหนึ่งตัวอักษร เหมือนโรคระบาด
    พอบริษัทหนึ่งนำมาใช้เพราะดูเท่ ตอนนี้ทุกคนก็พากันทำเวอร์ชันของตัวเอง

    • คงไม่แปลกใจถ้า UI แบบนี้ช่วย เพิ่มอัตราความสำเร็จในการกรอกรหัสใช้ครั้งเดียว ได้จริง
      ผู้ใช้จะรู้ได้ทันทีว่านี่ไม่ใช่ช่องรหัสผ่าน แม้ไม่ต้องอ่านอย่างละเอียด
  • กรณีที่เกี่ยวข้องคือ Medium once had a bug like this which prevented entering the character 'Ś'

  • ลองคิดวิธีใช้งานแบบอื่นแล้ว แต่สุดท้ายก็ยังหาวิธีที่ดีกว่า <input type="text" /> ธรรมดา ไม่ได้
    แม้แต่การตกแต่งด้วย CSS ให้ดูต่างจากช่องกรอกทั่วไปมากเกินไปก็ยังลังเลอยู่ อาจแสดงค่าที่กรอกซ้ำในช่องใหญ่ ๆ ได้ แต่ก็ต้องตอบปัญหาสารพัด เช่น ถ้าผู้ใช้กรอกเกินความยาวที่อนุญาตจะทำอย่างไร และข้อดีก็ไม่ได้มากพอให้คุ้มกับความพยายาม อย่างมากก็คงเปลี่ยนแค่ฟอนต์และขนาดของช่องกรอก

    • ข้อผิดพลาดที่พบบ่อยที่สุดใน OTP คือ พิมพ์ตัวเลขผิดไปหนึ่งหลัก เช่น 1224 แทน 1234
      วิธีแก้ที่เร็วที่สุดคือคลิกเลข 2 ตัวที่สองแล้วกด 3 แต่ทำด้วย HTML+CSS อย่างเดียวไม่ได้
    • ยอมรับว่าเป็นไอเดียที่ตลกมาก แต่ก็สงสัยว่าจะทำให้ <input type="text" pattern="[0-9]+" minlength=6 maxlength=6> หนึ่งช่อง ดูเหมือนเป็นหกช่องด้วยการตั้งระยะห่างตัวอักษรแปลก ๆ ได้ไหม
      วิธีที่ง่ายกว่าคือให้ผู้ใช้กรอกในช่องข้อความเดียว แล้วให้ JavaScript วาดช่องหกช่องไว้ที่ตำแหน่งอื่นใน DOM และอัปเดตด้วยอีเวนต์ input ที่เกิดขึ้นทุกครั้งที่กดแป้น
      ยากจะมั่นใจว่าวิธีไหนดีกว่าด้านการเข้าถึง จากมุมมองของโปรแกรมอ่านหน้าจอ วิธีหลังที่ใช้ <input> ธรรมดาร่วมกับ <canvas alt=""> สำหรับตกแต่งอาจดีกว่าด้วยซ้ำ และการใช้งานคีย์บอร์ดก็ไม่เพี้ยนไปด้วย แต่สำหรับผู้ใช้ที่ใช้เครื่องมือช่วยเหลืออื่นนอกเหนือจากโปรแกรมอ่านหน้าจอ การซ่อน <input> ทางสายตาอาจกลายเป็น หายนะด้านการเข้าถึง ได้ จึงต้องระมัดระวังอย่างมาก
  • จะให้ ทั้งรหัสและลิงก์เปิดใช้งาน ในอีเมลเหมือนบริการจำนวนมากก็ได้

    ป้อนรหัส: XX XX XX
    
    หรือคลิกลิงก์: <ลิงก์เปลี่ยนเส้นทาง + เปิดใช้งานรหัส>  
    

    แบบนี้ก็แก้ปัญหาเดียวกันได้

    • มองว่าการฝึกให้ผู้ใช้คลิกลิงก์ในอีเมลเป็นการ ถอยหลังด้านการป้องกันฟิชชิง
    • ถ้าเปิดเว็บไซต์บนแล็ปท็อปและรับอีเมลบนโทรศัพท์ การคัดลอกและวางก็ไม่ได้สะดวกนัก
      อาจมองว่านี่เป็นสถานการณ์พิเศษก็ได้ แต่การเข้าถึงก็คือการจัดการข้อยกเว้นแบบนั้นให้ถูกต้องนั่นเอง
  • Tridactyl ก็มี ปัญหาเดียวกันเป๊ะ https://github.com/tridactyl/tridactyl/issues/3257
    มีรายงานครั้งแรกในปี 2019 และไม่แน่ว่าเรื่องครั้งนี้อาจทำให้อายจนต้องแก้ในที่สุด

  • นี่แสดงให้เห็นอีกครั้งว่า การทำเว็บไซต์ให้ พังหรือช้า ต้องใช้ความพยายามมากกว่าการทำเว็บไซต์ที่ใช้งานได้ตามปกติเสียอีก