自動填充深色圖案
已發表: 2022-03-10報紙註冊表單有姓名、電子郵件和密碼字段。 所以,我開始在名稱字段上輸入,自動填充建議了我的個人資料。 但是有一些時髦的東西。 自動完成建議包括我的郵寄地址。 不用說,令人費解的是:地址不是表單中的字段。 為什麼它甚至被建議?
當這個問題開始在我腦海中形成時,我的大腦已經發出信號讓我的手指點擊這個建議,並且完成了。 接下來,我被帶到第二個表單頁面,該頁面要求提供更多信息,例如地址、電話、出生日期等。 所有這些字段也已由自動填充功能預先填充。
我鬆了口氣。 這是一個“多步驟”的形式,而不是網站的伎倆。 畢竟,那是一份有聲望的報紙。 我從第二頁刪除了所有可選信息,完成了註冊,然後繼續前進。
這種(麻煩的)交互突出了使用自動完成功能的風險之一。
自動完成和自動填充
它們可能聽起來很相似,但autocomplete
和自動填充不是一回事。 儘管它們密切相關:
- 自動填充是一種瀏覽器功能,允許人們保存信息(在瀏覽器或操作系統上)並在 Web 表單上使用它。
-
autocomplete
是一個 HTML 屬性,它為瀏覽器提供有關如何(或不)自動填充 Web 表單中的字段的指南。
我們可以說自動填充是“什麼”,而自動填充是“如何”,即autofill
存儲數據並嘗試在 Web 表單中匹配它(基於字段的name
、 type
或id
),並且autocomplete
引導瀏覽器關於如何做(每個字段中需要哪些信息)。
自動完成是一個強大的功能,有許多選項允許指定許多不同類型的值:
- 個人:姓名、地址、電話、出生日期;
- 財務:信用卡號、姓名、到期日;
- 人口統計:地點、年齡、性別、語言;
- 專業:公司和職位。
自動填充是一個廣泛使用的功能,無論是有意還是無意:誰不接受讓瀏覽器保存/使用 Web 表單信息,無論是有意還是無意? 這可能是一個問題——尤其是結合了對autocomplete
的不當使用(以及如今增加的網絡釣魚電子郵件和 SMS 消息的數量驚人。)
隱私風險
這兩個功能都給用戶帶來(至少)兩個主要風險,都與他們的個人數據及其隱私有關:
- 填充不可見字段(這與具有隱藏類型的字段不同);
- 即使在用戶提交表單之前,也可以通過 JavaScript 讀取自動完成的信息。
這意味著一旦用戶選擇自動填充信息,所有字段都將可供開發人員閱讀。 同樣,無論用戶是否提交表單,用戶都不知道實際填充了哪些字段。
最後一部分是相對的:知道填充了哪些字段將取決於瀏覽器。 Safari 和 Firefox 在這方面做得很好(我們很快就會在下面看到)。 另一方面,目前最流行的瀏覽器 Chrome 提供了糟糕的體驗,甚至可能欺騙最有知識的用戶分享他們的個人信息。
如果我們還考慮用戶不小心選擇填充字段的時間,這個問題就會變得更加相關。 讓我們通過一個例子更詳細地檢查它。
一個小實驗
我進行了一個小實驗,創建了一個包含許多字段的表單並附加了具有不同值的autocomplete
屬性。 然後,我玩了一下表單的結構:
- 我通過將大部分字段放在屏幕外的容器中來隱藏大部分字段(而不是使用
hidden
或type="hidden"
); - 我從標籤順序中刪除了視覺上隱藏的字段(因此鍵盤用戶會忽略隱藏的字段);
- 我嘗試以不同的順序對字段進行排序(令我驚訝的是,這影響了自動填充!)。
最後,表單的代碼如下所示:
<form method="post" action="javascript:alertData()"> <label for="name">Full name</label><input name="name" autocomplete="name" /><br/> <label for="email">Email</label><input name="email"/><br/> <label for="postal-code">ZIP</label><input name="postal-code" autocomplete="postal-code"/> <div class="hide-this"> <!-- Hidden --> <label for="firstname">First name</label><input tabindex="-1" type="hidden" name="firstname" autocomplete="given-name" /><br/> <label for="lastname">Last name</label><input tabindex="-1" name="lastname" autocomplete="family-name" /><br/> <label for="honorific-prefix">honorific-prefix</label><input tabindex="-1" name="honorific-prefix" autocomplete="honorific-prefix"/><br/> <label for="organization">Organization</label><input tabindex="-1" name="organization" /><br/> <label for="phone">Phone</label><input tabindex="-1" name="phone" autocomplete="tel" /><br/> <label for="address">address</label><input tabindex="-1" name="address" autocomplete="street-address" /><br/> <label for="city">City</label><input tabindex="-1" name="city" autocomplete="address-level2" /><br/> <label for="state">State</label><input tabindex="-1" name="state" autocomplete="address-level1" /><br/> <label for="level3">Level3</label><input tabindex="-1" name="state" autocomplete="address-level3" /><br/> <label for="level4">Level4</label><input tabindex="-1" name="state" autocomplete="address-level4" /><br/> <label for="country">Country</label><input tabindex="-1" name="country" autocomplete="country" /><br/> <label for="birthday">Birthday</label><input tabindex="-1" name="birthday" autocomplete="bday" /><br/> <label for="language">Language</label><input tabindex="-1" name="language" autocomplete="language" /><br/> <label for="sex">Sex</label><input tabindex="-1" name="sex" autocomplete="sex" /><br/> <label for="url">URL</label><input tabindex="-1" name="url" autocomplete="url" /><br/> <label for="photo">Photo</label><input tabindex="-1" name="photo" autocomplete="photo" /><br/> <label for="impp">IMPP</label><input tabindex="-1" name="impp" autocomplete="impp" /><br/> <label for="username">Username</label><input tabindex="-1" name="username" autocomplete="username" /><br/> <label for="password">Password</label><input tabindex="-1" name="password" autocomplete="password" /><br/> <label for="new-password">Password New</label><input tabindex="-1" name="new-password" autocomplete="new-password" /><br/> <label for="current-password">Password Current</label><input tabindex="-1" name="current-password" autocomplete="current-password" /><br/> <label for="cc">CC#</label><input tabindex="-1" name="cc" autocomplete="cc-number" /><br/> <label for="cc-name">CC Name</label><input tabindex="-1" name="cc-name" autocomplete="cc-name" /><br/> <label for="cc-expiration">CC expiration</label><input tabindex="-1" name="cc-expiration" autocomplete="cc-expiration" /><br/> <label for="cc-zipcode">CC Zipcode</label><input tabindex="-1" name="cc-zipcode" autocomplete="cc-postalcode" /><br/> </div> <button>Submit</button> </form>
注意:我不久前創建了這個演示,標準是一個動態文檔。 從那時起,一些自動完成名稱發生了變化。 例如,現在我們可以為地址或信用卡指定new-password
和current-password
或更多以前不可用的詳細信息。
該表單具有三個可見字段( name
、 email
和zipcode
)。 雖然這種形式在保險公司、有線電視和其他服務提供商中很常見,但它可能不會太普遍,所以我用一個電子郵件字段進一步減少了這種形式。 我們到處都可以註冊網站、新聞通訊或更新。 你可以在這裡看到一個正在運行的演示:
如果您使用自動完成來填寫表格,那麼您已經分享了比您想要的更多的信息(別擔心,這些都是本地的,沒有與我分享)。 在 Chrome 中,它甚至可能看起來像一個完全正常的訂閱表單。
如果您沒有/使用自動填充,請不要擔心。 以下是在三種不同瀏覽器上的體驗總結。
注意:所有這些測試都假設使用自動填充並且基於虛假配置文件!
蘋果瀏覽器
當您單擊表單控件時,Safari 將在字段右側顯示一個圖標。 單擊它將顯示一個彈出窗口,其中包含瀏覽器將與表單共享的信息:
一件好事:它顯示了將作為表單的一部分共享的所有數據。 不僅是可見字段的數據,而且是所有字段的數據。 此時,用戶可能會懷疑有些事情不太對勁。 有什麼可疑的。
當我將表單縮小為電子郵件字段時,Safari 做了一些有趣的事情。 自動填充彈出窗口不同:
它聲明它將僅共享電子郵件(並且僅共享該信息)。 但下面的聯繫信息可能比較棘手。 當我們單擊該按鈕時,瀏覽器會顯示配置文件的摘要及其共享數據。 但這在任何地方都沒有明確說明。 它看起來就像一張普通的名片,帶有一些“共享/不共享”選項。 單擊“自動填充”按鈕後,表單將填充所有數據。 不僅是電子郵件:
因此,有一種方法可以讓用戶無意中與表單共享信息。 考慮到它是兩個可能選項中帶有圖標的“突出顯示”,這很棘手,但並不太牽強。
有趣的是,瀏覽器將個人數據與信用卡數據分開,但 Safari 根據個人數據(姓名和 ZIP)填充了部分信用卡信息。
火狐
在 Firefox 中使用自動填充有點複雜。 它不像 Chrome 那樣是自動的,也沒有像 Safari 那樣的圖標。 用戶必須開始輸入或再次單擊才能看到自動填充彈出窗口,其中將包含瀏覽器將填寫的每個類別的註釋,而不僅僅是可見字段:
使用僅限電子郵件的表單進行測試,Firefox 顯示了相同的自動填充彈出窗口,說明它將填充哪些字段類別。 沒有任何區別。
與其他瀏覽器類似,在自動填充運行後,我們可以使用 JavaScript 讀取所有值。
Firefox 是三者中最好的:它清楚地說明了哪些信息將與表單共享,而與字段或其順序無關。 它隱藏了自動填充功能,發生了第二次用戶交互。
鍵盤用戶可以在沒有意識到的情況下選擇自動填充,方法是進入彈出氣泡並按 Tab 鍵。
鉻合金
然後輪到 Chrome 了。 (這裡我使用“Chrome”,但測試的幾個基於 Chromium 的瀏覽器的結果相似。)我點擊了該字段,沒有任何進一步的交互,自動填充彈出窗口顯示。 雖然 Firefox 和 Safari 有很多共同點,但 Chrome 完全不同:它只顯示兩個值,而且都是可見的。
這個顯示是設計使然。 我特意選擇了字段的順序,以獲得可見控件和自動完成建議的特定組合。 然而,看起來 Chrome 為第二個值賦予了一些自動完成屬性更多的“權重”。 這使得彈出窗口根據表單中字段的順序發生變化。
使用表單的第二個版本進行測試也好不到哪裡去:
雖然彈出窗口顯示了一個不可見的字段(名稱),但尚不清楚彈出窗口中名稱的用途。 有經驗的用戶可能知道會發生這種情況,因為名稱是共享的,但普通用戶(甚至是有經驗的用戶)可能會認為電子郵件與具有該名稱的個人資料相關聯。 瀏覽器將與表單共享的數據為零。
一旦用戶點擊自動填充按鈕,開發人員就可以使用 JavaScript 讀取數據:
Chrome 是最嚴重的違規者:它自動共享信息,不清楚涉及哪些數據,並且自動填充建議會根據控件的順序和屬性而變化。
前兩個問題對所有/許多瀏覽器都很常見,以至於它甚至可以被視為一項功能。 然而,第三個問題是 Chromium 瀏覽器獨有的,它促進了粗略的深色模式。
如果不是因為 Chrome 佔據了在線瀏覽器(包括 Chrome 和基於 Chromium 的)相當大的市場份額,這種行為將更像是一個軼事而不是問題。
黑暗模式
您可能知道,深色模式是一種欺騙性的 UX 模式,它會誘使用戶做他們可能並不真正想做的事情。
“當你使用網站和應用程序時,你不會閱讀每一頁上的每一個字——你會略讀並做出假設。 如果一家公司想欺騙你做某事,他們可以利用這一點,讓頁面看起來像是在說一件事,而實際上它在說另一件事。”
— Harry Brignull,darkpatterns.org
前面幾點描述的行為顯然是一種欺騙性的用戶體驗。 沒有經驗的用戶不會意識到他們正在共享他們的個人數據。 甚至更多精通技術的人可能會被它欺騙,因為 Chrome 使所選選項看起來像是屬於個人資料,而不是清楚地說明正在共享的信息。
瀏覽器實現會導致這種行為,但它需要開發人員將其設置到位以利用它。 不幸的是,已經有公司願意利用它,將其作為獲得潛在客戶的功能出售。
只要出現深色圖案,它也可能是非法的。 這是因為它違反了歐洲通用數據保護條例 (GDPR) 第 5 條中規定的與個人數據處理相關的許多原則:
- 合法、公平、透明
這個過程幾乎是透明的。 - 目的限制
數據的處理方式與最初的目的不符。 - 數據最小化
恰恰相反。 數據最大化:獲取盡可能多的信息。
例如,如果您想訂閱時事通訊或索取有關產品的信息,並且您提供了您的電子郵件,則網站沒有合法權利獲取您的姓名、地址、出生日期、電話號碼或其他任何信息同意或知情。 即使您認為用戶在點擊自動填充時給予了許可,但獲取數據的目的與表單的初衷並不相符。
可能的解決方案
為了避免這個問題,所有參與者都需要做出貢獻並幫助解決這個問題:
- 用戶
- 開發人員和設計師
- 瀏覽器
1. 用戶
用戶方面唯一要做的就是確保自動填充彈出窗口中顯示的數據是正確的。
但我們需要記住,用戶是這裡的受害者。 我們可以責怪他們在點擊自動填充時沒有給予足夠的關注,但這是不公平的。 另外,一個人可能會錯誤地單擊按鈕並意外共享其數據的原因有很多。 因此,即使是善意和精明的用戶也可能會愛上它。
2. 開發人員和設計師
說實話。 雖然開發人員不是問題的根本原因,但他們在利用暗模式方面發揮了關鍵作用。 無論是意外還是出於惡意。
讓我們負責任和誠實(這次是字面意義上的),因為這是開發人員和設計人員可以做的事情來建立信任並充分利用自動填充和自動完成功能:
- 僅自動完成您需要的數據。
- 明確說明將收集哪些數據。
- 不要隱藏稍後提交的表單字段。
- 不要誤導或欺騙用戶發送更多數據。
作為一種極端措施,可能會盡量避免自動完成某些字段。 但是,當然,這會帶來其他問題,因為它會降低表單的可用性和可訪問性。 所以找到平衡可能很棘手。
所有這一切都沒有考慮可以利用暗模式的 XSS 漏洞的可能性。 當然,那將是一個完全不同的故事,也是一個更重要的問題。
3. 瀏覽器
大部分工作需要從瀏覽器端完成(尤其是在 Chromium 端)。 但是,讓我首先說明 Web 瀏覽器處理自動填充/自動完成的方式並非都是壞事。 很多東西都是好的。 例如:
- 它們限制了可以共享的數據
瀏覽器有一個用於自動完成的字段列表,其中可能不包括 HTML 標準中描述的所有值。 - 它們封裝和分組數據
瀏覽器將個人信息和財務信息分開,以保護信用卡等關鍵價值。 Safari 對此有一些問題,但問題不大。 - 他們警告將要共享的數據
有時這可能不完整(Chrome)或不清楚(Safari),但它們確實會提醒用戶。
儘管如此,許多或所有網絡瀏覽器都可以改進一些事情。
顯示將自動完成的所有字段
瀏覽器應始終顯示將在自動填充彈出窗口中自動完成的所有字段的列表(而不僅僅是部分列表。)此外,信息應明確標識為要共享的數據,而不是顯示為常規聯繫人卡片可能會產生誤導。
Firefox 在這一點上做得很好,Safari 總體上做得很好,與其他兩個相比,Chrome 表現不佳。
不要在自動填充時觸發onChange
事件
這將是一個有問題的請求,因為此行為是 HTML 標準中自動填充定義的一部分:
“自動完成機制必須由用戶代理實現,就像用戶修改了控件的數據一樣 [...]。”
這意味著瀏覽器應該將自動完成的數據視為用戶輸入的數據,從而觸發所有事件、顯示值等。即使是在不可見的字段上也是如此。
防止在不可見元素上出現這種行為可以解決問題。 但是驗證表單控件是否可見對瀏覽器來說可能代價高昂。 此外,這個解決方案只是部分的,因為即使沒有輸入觸發事件,開發人員仍然可以讀取這些值。
不允許開發人員在提交前閱讀自動完成的字段
這也是有問題的,因為許多開發人員經常依賴於在提交之前讀取字段值來驗證值(例如,當用戶離開輸入時)。但這是有道理的:用戶不想共享信息直到他們提交表單,所以瀏覽器也不應該。
另一種方法是在讀取自動完成值時提供虛假數據。 Web 瀏覽器已經對訪問的鏈接進行了類似的操作,為什麼不對自動完成的表單字段做同樣的事情呢? 提供亂七八糟的名稱、與地方當局匹配的有效地址而不是用戶地址、假電話號碼? 這可以解決開發者驗證需求,同時保護用戶的個人信息。
顯示瀏覽器將清楚地與表單共享的字段/值的完整列表將是向前邁出的一大步。 另外兩個是理想的,但更多的是延伸目標。 儘管如此,它們仍然是可以大大改善隱私的舉措。
自動填充深色模式仍然可以利用嗎? 不幸的是,是的。 但這會復雜得多。 在這一點上,避免這種情況是用戶的責任和開發者的責任。
結論
我們可以爭辯說,自動完成不是一個巨大的安全問題(即使在 Chrome 上也不是),因為它需要用戶交互來選擇信息。 但是,我們也可以爭辯說,潛在的數據丟失證明了適當的行動是合理的。 與保護關鍵個人信息相比,Chrome 對(相對)不太重要的安全/可用性問題(參見alert()
、 prompt()
和confirm()
進行了更多更改。
然後我們有深色圖案的問題。 如果每個人都儘自己的一份力量,這是可以避免的:
- 用戶應該小心他們自動填寫的表格/數據;
- 開發人員應避免利用這些數據;
- 瀏覽器應該在保護人們的數據方面做得更好。
從根本上說,這種黑暗模式是一個瀏覽器問題(主要是 Chrome 問題),而不是一個小問題(隱私應該是在線的關鍵)。 但是有一個選擇。 最後,是否利用暗模式取決於開發人員。 因此,讓我們明智地選擇並做正確的事。
Smashing 雜誌的進一步閱讀
- 更好的表單設計:每頁一件事(案例研究),Adam Silver
- Web 表單中的常見問題和隱私,Vitaly Friedman
- 使用
accent-color
簡化表單樣式 , Michelle Barker - HTML5 輸入類型:它們現在在哪裡?,Drew McLellan
- Ionic React 中的表單和驗證,Jerry Navi
- 移動表單設計的最佳實踐,Nick Babich