﻿# 使用 SPA 單一頁面應用程式設計網頁表單應考量密碼管理器需求

由於我公司有使用[玉山商業銀行](https://www.esunbank.com.tw/)來處理帳務，我經常需要登入[玉山全球智匯網](https://gib.esunbank.com/)以審核放行一些廠商款項，我一直以來都有使用[密碼管理器](https://zh.wikipedia.org/wiki/%E5%AF%86%E7%A2%BC%E7%AE%A1%E7%90%86%E5%93%A1)的習慣，確保我的每個網站所使用的密碼都是不一樣的，強化資訊安全。不過，該網站在我用了數幾年之後，從不久之前開始，該網站完全無法自動登入了，深入研究後才發現，原來他們把網頁上的表單欄位的 `id` 屬性移除了！這篇文章我來說說我解決此問題的過程，也說說前端工程師應注意的事項！

### 問題分析

由於很少有網站無法使用「密碼管理器」來管理密碼，[玉山全球智匯網](https://gib.esunbank.com/)應該是我第一個遇到完全無法自動輸入密碼的網站，所以我就分析了一下這個網站的前端結構，以下是我的探索發現：

1.  我很驚訝的發現，該網站的首頁竟然用了一個我從 `2000` 年開始就沒在用的標籤 `FRAMESET` 標籤！😅
    
    我不太清楚這個設計的用意為何？故意讓網站上的網址不會動嗎？好多銀行都有類似設計，我聽過大多數的原因，都是不希望客戶按下 F5 重新整理網頁，只要按了 F5 重新整理網頁就要登出！但我必須老實說，你其實有更好的選擇，可以不用透過 `FRAMESET` 來降低網頁的可及性(Accessibility)！
    
    ![FRAMESET](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/30bdabae4b72a378b4c9-219687769-e91f9b58-1551-4328-94fd-d308e8de3b85.png)
    
2.  我拿掉了 FRAMESET 的包袱，直接進入 FRAMESET 中的[主要頁面](https://gib.esunbank.com/index2.html)，網頁依然可以正常瀏覽！
    
    他們用了 Angular `4.4.6` 版本來建置這個網站，可以理解從建站之初到現在，從來沒有升級過版本，老實說我會擔心使用太舊版本的前端框架或函式庫，會帶來一些資訊安全上的風險。
    
    ![Angular 4.4.6](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/c5594dac7abf582e698f-219688954-37700905-5b5e-4275-8d90-29ebc40b9019.png)
    
    > 題外話，網頁上載入的 JavaScript 刻意加上 `defer` 與 `async` 在這裡是完全無意義的，這個位置已經在頁尾了阿！😅
    
3.  我的密碼管理器自動填入了「使用者名稱」與「密碼」欄位，但是「顧客ID/代號」這個欄位就沒有自動填入了！
    
    因為這個網站我已經用了很多年，這個欄位一直是可以填入的，但前幾個月似乎就開始無法自動填入了。
    
    ![密碼管理器自動填入了「使用者名稱」與「密碼」欄位，但是「顧客ID/代號」這個欄位就沒有自動填入](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/3dd5dc0b8c064490ed0e-219690471-94603397-8e51-4acc-8d9f-bf988aa999c6.png)
    
4.  原來「顧客ID/代號」這個欄位缺乏 `id` 屬性，導致密碼管理器無法定位到該欄位！
    
    我想這就是主因了，一定是在某次更版的過程中，開發人員將 `id` 屬性移除了。老實說，在 SPA 架構下，表單欄位的 `id` 與 `name` 屬性其實一點都不重要，沒有這兩個屬性一樣可以開發表單互動，所以經常被開發人員忽略。
    
    在網頁中的標籤使用 `id` 屬性，除了可以讓傳統 JavaScript 更好的透過 DOM API 定位到該元素(Element)之外，還可以讓 E2E 自動化測試更好的定位到該欄位。很自然的，此舉也可以讓「密碼管理器」更容易找到重要的表單欄位，加以記憶與管理！
    
    ![欄位缺乏 id 屬性](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/616b0b9d67d4526ec290-219691822-448d145a-7160-490d-8bf6-37de8f7e7ec5.png)
    

### 解決方案

解決這個問題其實也不難，透過 [Tampermonkey](https://www.tampermonkey.net/) 擴充套件，外加我寫的一段 Userscript 就可以在網頁載入時自動加入該欄位的 `id` 屬性，如此一來「密碼管理器」就可以識別這個欄位了！👍

以下是完整的 Userscript 實作：

```javascript
// ==UserScript==
// @name         玉山銀行: 添加遺失的表單欄位 id 屬性
// @version      1.0.0
// @description  修復玉山銀行玉山全球智匯網登入頁面無法使用密碼管理器的問題
// @license      MIT
// @homepage     https://blog.miniasp.com/
// @homepageURL  https://blog.miniasp.com/
// @website      https://www.facebook.com/will.fans
// @source       https://github.com/doggy8088/TampermonkeyUserscripts/raw/main/src/ESUN_Add_Field_ID.user.js
// @namespace    https://github.com/doggy8088/TampermonkeyUserscripts/raw/main/src/ESUN_Add_Field_ID.user.js
// @match        https://gib.esunbank.com/*
// @author       Will Huang
// @run-at       document-start
// @icon         https://www.google.com/s2/favicons?sz=64&domain=https://gib.esunbank.com
// ==/UserScript==

(async function () {
    "use strict";
    let it = setInterval(() => {
        let elm = document.querySelector('input[placeholder="顧客ID/代號"],input[placeholder="顾客ID/代号"],input[placeholder="Customer ID/No"]');
        if (elm) {
            elm.id = 'inputCustomerId';
            clearInterval(it);
        }
    }, 60);
})();
```

### 後記

其實我可以理解銀行的資安需求永遠站在最高標準看待，我覺得他們應該是站在保護顧客的立場，不希望客戶透過「任何工具」代客戶輸入密碼。不過我老實說，如果真的有這種想法，這個資安觀念真的是有點過時了，就跟要求客戶每半年要改一次密碼，而且不能用過去 5 次用過的密碼一樣過時！

現在上網風險之高，已經跟 20 年前不太一樣了，[撞庫攻擊](https://zh.wikipedia.org/wiki/%E6%92%9E%E5%BA%93)是常年下來一直都非常有效的攻擊手段，因此在不同網站之間共用相同密碼，早就被證明是一種相當危險的密碼管理政策，應該盡可能的避免。若網站要求使用者經常變更密碼，又不允許他們使用工具輸入密碼，這無疑是要人把密碼貼在鍵盤底下，不然就是設定「一二兩排」這種 IT 人常見的「高強度密碼」！😆

這篇文章希望可以讓使用任何 JS 前端框架的開發者知道，適時的加上 `id` 屬性到欄位上，其實可以減少用戶的麻煩，提高用戶滿意度，更能提升資安強度！👍

喔喔，還有，拜託 [`<frameset>`](https://developer.mozilla.org/zh-TW/docs/Web/HTML/Element/frameset) 不要再用了！事實上在 HTML5 規格中，根本沒有這個標籤，這是一個 W3C 完全棄用的歷史產物，瀏覽器為了讓老舊網頁還可以瀏覽，所以才留著的。網站做這麼棒，花了那麼多力氣在 UI/UX 上面，我覺得用現代化的角度去製作網站(Modern Web)，應該是全體 Web 開發者的共識啦，不鼓勵再去使用任何已廢棄的 HTML 標籤或 Web API！🔥

### 相關連結

-   [玉山全球智匯網](https://gib.esunbank.com/)
-   [<frameset> - HTML：超文本標記語言 | MDN](https://developer.mozilla.org/zh-TW/docs/Web/HTML/Element/frameset)
-   [撞庫 - 維基百科，自由的百科全書](https://zh.wikipedia.org/wiki/%E6%92%9E%E5%BA%93)
-   [HTML element: frameset - HTML element: frameset | Can I use... Support tables for HTML5, CSS3, etc](https://caniuse.com/mdn-html_elements_frameset)
