1 điểm bởi GN⁺ 3 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • Ô nhập mã xác thực email 6 chữ số của hệ thống đăng nhập chính phủ Thụy Sĩ AGOV không xử lý được việc nhập số trên bàn phím AZERTY kiểu Pháp, khiến bản thân việc đăng ký tài khoản cũng bị chặn
  • JavaScript của ô nhập đã chặn thao tác gõ phím và lưu mã xác thực vào một biến riêng, đồng thời bỏ qua phím Shift, nên trên thực tế đã chặn bố cục AZERTY nơi cần Shift để nhập số
  • Cùng một lỗi xuất hiện trên nhiều tổ hợp Firefox·Chromium·Chrome·Safari và Linux·macOS, nhưng hoạt động bình thường trên bàn phím QWERTY, qua đó thu hẹp nguyên nhân không phải trình duyệt hay hệ điều hành mà là bố cục bàn phím
  • Hỗ trợ chính thức cũng chỉ dùng được sau khi vượt qua cùng bước xác thực email đó, và không có phương án thay thế như email hay điện thoại, nên người dùng không đăng nhập được thậm chí cũng không thể báo lỗi đăng nhập
  • Khi dùng logic xử lý phím phức tạp thay vì trường nhập native, đồng thời buộc sản phẩm và kênh hỗ trợ dùng chung một quy trình xác thực, thì cả khả năng truy cập lẫn ứng phó sự cố đều sụp đổ; vì vậy cần ô nhập đơn giản dựa trên DOM và các kênh hỗ trợ độc lập

AGOV đã trở thành hạ tầng nhận dạng số

  • Nhận dạng số gần đây đã nổi lên như một chủ đề tranh cãi lớn trên web, kéo theo nhiều phụ thuộc lẫn tranh cãi
  • Hệ thống đăng nhập chính phủ Thụy Sĩ AGOV đã đi vào hoạt động từ năm 2024, và số tài khoản đã đạt 1,6 triệu
  • Nó đang được mở rộng làm phương thức đăng nhập cho nhiều nghiệp vụ chính phủ, gồm cả bảo hiểm thất nghiệp và khai thuế bắt buộc

Đăng ký dừng lại ở bước xác thực email

  • Quy trình đăng ký AGOV bắt đầu bằng việc gửi địa chỉ email rồi nhập mã xác thực 6 chữ số
  • Giao diện mã xác thực gồm tổng cộng 6 ô nhập, mỗi ô cho một chữ số
    • Dù nhập số thì con trỏ cũng không chuyển sang ô tiếp theo
    • Số tiếp tục dồn vào ô hiện tại và chuyển sang trạng thái lỗi màu đỏ
    • Ngay cả khi tự chuyển từng ô để nhập, cuối cùng vẫn hiện lỗi field required
  • Khi thử sửa trực tiếp giá trị DOM bằng công cụ cho nhà phát triển thì không thấy giá trị form nào rõ ràng, và console web cũng không ghi lỗi
  • Kết quả vẫn như vậy dù dùng địa chỉ email khác hay địa chỉ giả như test@example.com
    • example.com là tên miền được dành riêng theo RFC 6761

Loại trừ khả năng do trình duyệt và hệ điều hành

  • Ban đầu người viết nghi ngờ tổ hợp Firefox và Linux không được hỗ trợ hoặc CAPTCHA bị lỗi
  • Cùng một lỗi xuất hiện trên cả 6 tổ hợp môi trường sau
    • Firefox, Chromium, Chrome trên Linux
    • Firefox, Safari, Chrome trên macOS
  • Trên laptop công việc, sau khi nhập thì con trỏ tự chuyển sang ô kế tiếp, và lỗi Code entered is incorrect cho mã sai nhưng không rỗng cũng hiển thị bình thường
  • Trên máy macOS của một người bạn, cả ba trình duyệt đều chấp nhận mã xác thực
  • Không thể phụ thuộc vào máy tính do công ty cấp để tương tác lâu dài với dịch vụ chính phủ; ngay cả nếu đăng ký được trên máy công việc, vẫn còn khả năng không thể đăng nhập trên laptop cá nhân

Cấu trúc hỗ trợ còn chặn cả việc báo lỗi

  • Hỗ trợ chính thức chỉ được cung cấp qua form web, và form này cũng yêu cầu nhập mã xác thực email trước
  • FAQ nêu rõ hỗ trợ từ các cơ quan tham gia chỉ được cung cấp trong giờ làm việc thông qua việc tạo ticket trực tuyến
  • Ngoài địa chỉ bưu điện của Swiss Federal Chancellery thì không có email hay số điện thoại nào
  • Tính năng phản hồi để gửi lời khen, phê bình hay yêu cầu cho AGOV cũng đòi hỏi đăng nhập bằng AGOV hoặc tài khoản tương đương
  • Người dùng thất bại ở bước xác thực email rơi vào một vòng phụ thuộc lặp kín: không thể báo lỗi cũng vì cùng quy trình xác thực đó
  • AGOV Access và các thiết bị được hỗ trợ

    • Ứng dụng AGOV Access Android có điểm đánh giá 1,4, nhưng trong review trên Google Play không thấy cùng vấn đề mã xác thực này
    • Các review có nhiều yêu cầu hỗ trợ GrapheneOS, một biến thể Android tập trung vào bảo mật và quyền riêng tư
    • Theo FAQ chính thức, ứng dụng không hoạt động vì framework tăng cường chống sửa đổi trái phép không tương thích với GrapheneOS
    • Federal Chancellery đã chỉ đạo nhà cung cấp đảm bảo khả năng tương thích
    • Hiện tại, phương thức xác thực hai yếu tố cho đăng ký và đăng nhập là smartphone iOS·Android tiêu chuẩn được chấp nhận hoặc khóa bảo mật, và dù là cách nào thì cũng phải vượt qua bước xác thực email trước

Nguyên nhân được tìm thấy trong JavaScript

  • Tài nguyên mà trang tải về không nhiều, nhưng file JavaScript chính ở dạng minify nhưng không bị làm rối có kích thước 2,4MB, và nếu bung ra thì vượt quá 100.000 dòng
  • Tìm chuỗi field required đã lần ra logic đặt trạng thái mã xác thực
    • Nếu không có biến mã xác thực thì trạng thái được đặt là REQUIRED
    • Nếu độ dài khác với độ dài mã yêu cầu thì bị xử lý là WRONG
    • Nếu độ dài khớp thì dùng VALID hoặc trạng thái lỗi theo kết quả xác thực email từ máy chủ
  • Hàm verificationCodeEntered chặn thao tác gõ phím và thu thập mã xác thực vào một biến JavaScript
    • Enter chạy callback xác thực
    • Backspace xóa giá trị hiện tại
    • Phím mũi tên và Tab di chuyển giữa các ô nhập
    • Các phím thông thường được đổi thành số bằng Number(S.key) rồi lưu vào mã
    • Các phím như Control, Meta, Shift, v, r bị bỏ qua và hàm trả về
  • Vì khi gửi form nó không đọc giá trị DOM, nên dù sửa ô nhập bằng công cụ cho nhà phát triển hay tiện ích mở rộng trình duyệt, trạng thái do JavaScript quản lý riêng cũng không được cập nhật

Vì sao số chỉ bị chặn trên AZERTY

  • Bố cục AZERTY tiêu chuẩn của Pháp cần phím Shift để nhập số
  • Vì code bỏ qua thao tác nhấn Shift nên trên AZERTY bản thân chữ số không thể được lưu vào mã xác thực
  • Máy công việc dùng bố cục QWERTY tiếng Anh, và trong những người hỗ trợ xác minh vấn đề thì không có ai là người Pháp
    • Kết quả là trong các thiết bị đã thử, chỉ hai laptop cá nhân trông như bị lỗi
  • Khi đổi bố cục bàn phím trong hệ điều hành sang bố cục khác thì việc nhập trên laptop cá nhân hoạt động lại bình thường
    • Ngược lại, khi chuyển một thiết bị vốn hoạt động bình thường sang bố cục kiểu Pháp, cùng lỗi lại được tái hiện
  • Bàn phím tiếng Pháp tiêu chuẩn ở Thụy Sĩ thuộc họ QWERTZ, phổ biến ở Trung Âu
    • Nó cho phép nhập tiếng Pháp và tiếng Đức hiệu quả, và không cần Shift để nhập số nên không gặp cùng lỗi này
  • Theo Swiss Federal Statistical Office, có khoảng 171.000 cư dân mang quốc tịch Pháp tại Thụy Sĩ; con số này còn chưa tính người lao động qua biên giới phải tương tác với chính phủ Thụy Sĩ

Hạn chế điều tra trước khi mã nguồn được công khai

  • Theo FAQ của AGOV, mã nguồn AGOV dự kiến sẽ được công khai vào tháng 12/2026 để đáp ứng yêu cầu pháp lý
  • Điều 9 EMBAG yêu cầu các cơ quan liên bang công khai mã nguồn phần mềm do họ trực tiếp phát triển hoặc đặt phát triển để thực hiện nhiệm vụ
    • Ngoại lệ được áp dụng nếu quyền của bên thứ ba hoặc lý do an ninh cản trở hay hạn chế việc công khai
  • Đối tượng công khai là phiên bản AGOV đã đạt mục tiêu dự án, bao gồm AGOV e-ID Verifier; các phiên bản về sau sẽ được công khai kèm release note chuẩn bị sau khi phát hành
  • Dù một số dịch vụ đã bắt buộc dùng AGOV để đăng nhập, mã nguồn vẫn chưa được công khai, khiến người dùng khó báo lỗi trực tiếp cho nhà phát triển hoặc chia sẻ cách lách tạm thời

Phạm vi xác minh danh tính được kiểm tra sau khi đăng ký

  • Sau khi đổi bố cục bàn phím, người viết đã xác thực địa chỉ email và hoàn tất đăng ký bằng khóa bảo mật
  • Trong quá trình đăng ký có nhập tên, số điện thoại và ngày sinh, nhưng các thông tin này không được xác minh
  • Ở bước đăng ký cơ bản chỉ có hai điều được xác nhận
    • Địa chỉ email thực sự tồn tại
    • Phương thức xác thực hai yếu tố là khóa bảo mật thuộc mẫu được chấp nhận, hoặc ứng dụng AGOV Access chạy trên thiết bị Android·iOS được chấp nhận
  • AGOV có khả năng chống chiếm đoạt tài khoản do phishing từ xa tốt, nhưng ở bước đăng ký cơ bản không ngăn được việc người khác tạo tài khoản bằng tên và thông tin danh tính của người khác
  • Kiểm tra thêm cho thấy, khi truy cập các dịch vụ được phân loại là nhạy cảm thì cần xác minh danh tính
    • Ngay sau khi đăng ký, người viết vẫn chưa truy cập loại dịch vụ đó
  • Đã báo lỗi qua form hỗ trợ nhưng không nhận được phản hồi

Bài học rút ra từ thiết kế

  • Thiết kế nhập liệu và hỗ trợ thiếu độ bền vững

    • Cách làm UI cầu kỳ bằng 6 ô nhập và logic JavaScript phức tạp là không bền vững
    • Tốt hơn là dùng một trường nhập native của trình duyệt rồi chỉ trang trí hình thức bằng CSS
    • Khi tách hoàn toàn logic form khỏi DOM thì lúc submit không thể đọc giá trị DOM, và người dùng nâng cao hay tiện ích mở rộng trình duyệt cũng không thể sửa giá trị nhập
    • Nếu chỉ có một kênh hỗ trợ, khi chính kênh đó hỏng thì sẽ không còn cách liên hệ; vì vậy cần kênh thứ hai như email hoặc điện thoại
    • Nếu áp dụng cùng một logic đăng nhập cho cả sản phẩm lẫn kênh hỗ trợ thì sẽ bỏ lỡ báo lỗi từ những người không thể đăng nhập
    • Đây cũng là lý do nhiều dịch vụ Internet đặt trang trạng thái ở một tên miền riêng
    • Đặt yêu cầu hỗ trợ sau bước xác thực email có thể giảm spam, nhưng cũng làm giảm cả báo cáo sự cố từ người dùng thật
    • Nếu chỉ công khai mã nguồn sau khi một số hệ thống đã bắt buộc sử dụng thì khả năng tự giải quyết vấn đề, chia sẻ bug và cách lách của người dùng sẽ bị hạn chế
    • Việc công khai mã nguồn theo luật không chỉ là một hạng mục tuân thủ mà còn hữu ích cho điều tra sự cố thực tế
  • Web mở đã giúp việc điều tra

    • Vì logic JavaScript liên quan không bị làm rối, chỉ cần vài lần tìm chuỗi là đã tìm ra nguyên nhân
    • Không cần decompiler cao cấp hay LLM đắt tiền
    • Nếu mã bị làm rối hoặc được biên dịch thành WebAssembly thì sẽ mất nhiều thời gian hơn rất nhiều để xác định nguyên nhân
    • Mã không chỉ được phân phối trên các hệ điều hành đóng đã được phê duyệt mà được cung cấp qua web mở, nên vẫn có thể tải về để điều tra dù chỉ ở dạng minify
  • Những điều kiện giúp xác định nguyên nhân

    • Có thể so sánh nhiều laptop dùng các bố cục bàn phím khác nhau, qua đó sớm giảm khả năng lỗi theo trình duyệt hoặc lỗi mạng
    • Tuy vậy, để xác nhận đây không phải lỗi thao tác của người dùng, tác giả đã phải chụp màn hình một cách có hệ thống ở từng tổ hợp trình duyệt trong giai đoạn thu thập bằng chứng ban đầu, nên vẫn tốn thời gian

1 bình luận

 
Ý kiến trên Lobste.rs
  • Một trong những thói quen tôi đặc biệt ghét trên Internet là các website chặn thao tác gõ phím rồi tự xử lý theo ý mình, thay vì chuyển nguyên vẹn cho trình duyệt Các trang cấm sao chép/dán vào trường mật khẩu phổ biến hơn nhiều, nhưng việc này cũng cùng một kiểu và có lẽ còn có vẻ nghiêm trọng hơn

    • Tôi không hiểu vì sao phải dùng JavaScript để triển khai lại một chức năng mà trình duyệt đã hỗ trợ sẵn chỉ bằng HTML và CSS Thường thì nó chỉ làm tăng độ phức tạp vì những lý do gượng ép
  • Cách làm mỗi ký tự một ô nhập giống như một dịch bệnh Một công ty nào đó thấy trông hay ho nên áp dụng, và giờ ai cũng tự triển khai phiên bản riêng của mình

    • Tôi sẽ không ngạc nhiên nếu UI kiểu này thực sự làm tăng tỷ lệ nhập mã dùng một lần thành công Người dùng có thể nhận ra ngay đây không phải là ô nhập mật khẩu mà không cần đọc kỹ
  • Một ví dụ liên quan là Medium once had a bug like this which prevented entering the character 'Ś'

  • Tôi đã nghĩ thử các cách triển khai khác, nhưng cuối cùng vẫn không tìm được cách nào tốt hơn `` bình thường Ngay cả việc trang trí bằng CSS để nó trông quá khác ô nhập thông thường cũng khiến tôi do dự. Có thể sao chép giá trị nhập để hiển thị trong các ô lớn, nhưng khi người dùng nhập nhiều hơn độ dài cho phép thì xử lý ra sao, cùng đủ loại vấn đề khác cần trả lời; lợi ích không đủ lớn để đáng công. Nhiều nhất tôi chỉ đổi phông chữ và kích thước của ô nhập

    • Lỗi phổ biến nhất với OTP là nhập sai một chữ số, chẳng hạn 1224 thay vì 1234 Cách sửa nhanh nhất là nhấp vào số 2 thứ hai rồi nhấn 3, nhưng chỉ với HTML+CSS thì không thể triển khai được
    • Tôi thừa nhận đây là một ý tưởng khá buồn cười, nhưng tôi tò mò liệu có thể áp dụng khoảng cách chữ đặc biệt cho một **** để về mặt thị giác trông như sáu ô hay không Cách dễ hơn là để người dùng nhập vào một ô văn bản duy nhất, rồi JavaScript vẽ sáu ô ở vị trí khác trong DOM và cập nhật bằng sự kiện `input` phát sinh mỗi khi nhấn phím Khó chắc cách nào tốt hơn về khả năng tiếp cận. Từ góc nhìn trình đọc màn hình, phương án sau — một bình thường kèm chỉ để trang trí — có thể còn tốt hơn, và thao tác bàn phím cũng không trở nên kỳ quặc. Nhưng với người dùng sử dụng công cụ hỗ trợ ngoài trình đọc màn hình, việc ẩn về mặt thị giác có thể trở thành thảm họa về khả năng tiếp cận, nên phải cực kỳ thận trọng
  • Cũng có thể, như nhiều dịch vụ khác, cung cấp cả mã lẫn liên kết kích hoạt trong email

    Nhập mã: XX XX XX
    
    Hoặc nhấp liên kết:
    
  • Cách này cũng có thể giải quyết cùng vấn đề
    - Tôi cho rằng việc tập cho người dùng nhấp vào liên kết trong email là **một bước lùi trong phòng chống phishing**
    - Nếu bạn mở website trên laptop nhưng nhận email trên điện thoại, việc sao chép/dán không tiện lắm
      Có thể coi đó là trường hợp ngoại lệ, nhưng khả năng tiếp cận chính là xử lý tốt những ngoại lệ như vậy
    
    
  • Tridactyl cũng có đúng vấn đề y hệt https://github.com/tridactyl/tridactyl/issues/3257 Vấn đề này được báo cáo lần đầu vào năm 2019; không biết liệu sự việc lần này có khiến họ xấu hổ mà sửa nó không

  • Điều này một lần nữa cho thấy việc tạo ra một website hỏng hoặc chậm tốn nhiều công sức hơn hẳn so với một website cứ thế hoạt động bình thường