所謂「安全的密碼」?
若從資訊安全的角度,會建議取的密碼「愈複雜愈好」:
- 除了常見的長度(至少8字元,甚至允許的話拉得更長更安全)、包含英數大小寫,甚至特殊符號(!@#$之類的,但部分平台因避免惡意程式碼注入等考量不允許)
- 比起嚴格要求大小寫與符號的亂數組合,拉長字數且有語意的密碼,會比短的亂數符號組合好記憶,但也不至於容易被猜出
- 但愈長愈複雜的密碼,理論上還是愈難破解而相對安全(圖表示意)
- 若以記憶性來看,密碼主體可以考慮用特殊意義的英文句子
- 且最好不包含帳號文字與個人資訊(姓名、身分證字號、生日等容易取得用來猜測組合的字詞),也盡量避免明顯常用語句(如”I love xxx”之類的)等規則可循
- 甚至每組帳號對應的密碼皆不同(避免其中一組外洩後,被輕易在其他網站服務上也盜用)
- 此外,如果擔心密碼記不住,或是必須與他人(內部團隊)共用,而需要以明碼紀錄的話,也需注意避免被外人竊取,常見記錄方式:
- 紙本實體:便條、紙張甚至筆記本(多組的話)
- 妥善收好別亂放的話,幾乎不會被盜取
- 數位軟體:獨立的密碼管理器,或瀏覽器內建的密碼記錄功能
- 現代更常見與便利的方案,甚至能自動產生與填入
- 只要確保密碼管理紀錄的軟體本身安全即可
- 紙本實體:便條、紙張甚至筆記本(多組的話)
- 若要更進一步加強安全性,甚至還得定期更改密碼,可讓外泄的密碼因時效性降低風險(高機敏的帳密較常被要求)
- 一些看似有考慮安全,但做得不夠其實NG的範例
- 細節可參考台灣教育部的資安文宣建議
- 或是更進階的密碼設定與保存建議
- 其他:搭配額外手段(如二階段/兩步驟驗證2FA或動態密碼OTP),甚至改採生物識別/辨識(Biometric)(如指紋或臉部)或實體金鑰(如U2F),能避免或繞過只用密碼而被盜的風險
使用者的角度:安全與便利的平衡點?
密碼使用的惰性難以抵抗…
- 使用大量的安全措施,其實違反人性與人類記憶能力…
- 誤用安全規則或理解不夠的話,反而可能搞出人類難以記憶卻容易被電腦破解的「偽安全」密碼
- 理想上每組密碼應該要不一樣,但實際上除非註冊使用的服務很少,不然不可能全部直接記住…
- 因密碼難以記憶而用外部的管理器或紙本等工具,反而又會受制於工具,等於你自己也不知道密碼,甚至工具因漏洞或保存不當外洩時,無法在第一時間得知與處理…
- 至於定期更改密碼,既使因要求而執行,實際上卻可能怕麻煩而沒有徹底更改(如只變動一小部分),更別提可以不用改還懶得改的情況,效果因而大打折扣…
- 另外,若加上2FA、生物識別、U2F等額外手段搭配驗證,不僅開發與維持服務的成本上升,用戶也需要更多的硬體搭配…
- 題外話,如果網站服務有忘記密碼重設功能,對總是忘記(或不想記)密碼的人來說,算是變相的OTP…?
可能的折衷思路:公、私鑰的區分與結合
- 受非對稱式加密啟發
- 比起固定的密碼,自訂固定的密碼規則更重要
- 試圖兼具人性與安全,在二者之間求平衡,且保留取捨的調整性質
- 將個人取密碼的策略調整成二個字串的組合,
- 類似非對稱式加密區分公私鑰的方式,
- 公鑰:對應註冊服務的名稱
- 簡易的作法,直接取服務名稱的英文版,或網頁的網域名稱
- 進階的話則用英文服務明再進一步變化(搭特定規則改寫)
- 因為看到服務名稱可直接聯想到,甚至是直接挪用,因此算是「公鑰」
- 私鑰:以安全規則設的密碼
- 遵守本文第一段「安全的密碼」所設置
- 沒信心的話,可以到這個網站測試得花幾年破解
- 因為這組密碼理論上只有你(或少數人)知道,因此算是「私鑰」
- 公鑰:對應註冊服務的名稱
- 實際密碼的產生組合:將密碼的公鑰與私鑰部分,用特定規則放在一起
- 因為在個別服務註冊的每組密碼,都有根據服務名稱變化的公鑰,可以達成最基本的帳號密碼不重複要求
- 基本版:除公私鑰的先後放置順序,也可以在二者之間加上特殊符號區隔(較為直觀好用)
- 舉例:如在Facebook使用”!4f6#6JL5@facebook”、Google使用”!4f6#6JL5@google”
- 上述為私鑰(!4f6#6JL5)+特殊符號(@)+公鑰(facebook/google)的組合
- 進階版:將公鑰或私鑰的部分穿插在另一部分,甚至實際使用的是公私鑰組合後再加密或雜湊的結果(更能保障安全但也繁瑣,願意隨時準備產生密碼需要的工具的話)
- 限制:仍不改密碼的本質
- 儘管這招較容易產生好記可變化且算安全的密碼,也不是絕不可能外洩或被猜出(儘管機會很低)
- 仍需要妥善保管密碼,且真有高機敏必要的話仍需再加上定期更改、配合額外驗證方式或生物辨識/實體金鑰等常規方式加強安全
應用服務的角度:應如何處理使用者密碼?
前端(Client):格式的提示與檢查
- 以表單(form)下
type=password
的<input>
標籤輸入送出 - 關於設置密碼的規則與建議
- 如果強調安全性,可以將上述常見的密碼規則敘述加到註冊頁面的提示
- 甚至實作密碼強度驗證,避免使用者設置明顯不安全的密碼
- 如最短長度、是否兼具數字與大小寫,甚至必用特殊符號
- 建議在前端以JS實作(可用正規表達式檢查格式),而非發給後端處理再等回傳結果,可節省網路流量與等待時間
- 但除非有特殊需求或限制,否則某些額外的密碼字元與長度硬性限制,反而讓使用者無法依照個人習慣設密碼
- 像是長度上限(資料大小限制?)、不能使用特殊符號(防止惡意程式碼注入?)、只能用大/小寫或數字(PIN碼)…
- 可能讓使用者無法使用習慣的安全密碼規則,得額外記憶或只能交給密碼管理器
- 註冊的部分,通常會加上重複輸入密碼的驗證,強調密碼的重要性和協助確認、記憶(尤其沒提供其他登入方式甚至重設功能是),也是在前端以JS實作效能體驗較佳
- 送出密碼時,切忌以明碼的方式傳輸,且需要一定的加密,否則很容易洩露機密資料!!!
- 以web的概念HTTP method(請求方法)來說,得使用POST而非GET
- POST可將資料藏在body,GET傳輸的資訊會直接顯示在URL
- 加密的部分,只要發送時使用HTTPS即有一定的安全性,可不用特別處理
- 有特殊需求的話,再另外使用其他加/解密方案(但不能用不可逆的雜湊)
- 以web的概念HTTP method(請求方法)來說,得使用POST而非GET
後端(Server):雜湊化儲存與驗證
- 既有帳號驗證 VS 暴力破解
- 由於註冊必須告知帳號名稱是否被使用,可能讓駭客透過洩露的帳號名稱在其他網站服務猜出攻擊目標
- 登入功能最好加上錯誤次數限制,避免被用電腦窮舉所有字串組合暴力破解
- 以不可直接還原的雜湊(hash)儲存使用者密碼
- 除非你想在背後做壞事(X),否則資料庫直接被駭客侵入的話密碼會直接洩露
- 正常的網站服務其實不知道確切的使用者密碼,而是透過雜湊值與輸入的密碼比對來驗證身分
- 因此網站不能主動從資料庫得知使用者密碼明文(能告知密碼的網站反而危險要小心!!!)
- 至於重設密碼的功能,則是透過註冊時綁定的通訊方式(如電子郵件或手機號碼),確認身分後暫時給予登入狀態來修改密碼(另類OTP的概念?)
- 即註冊時使用程式自動產生的複雜密碼(可不用記住),每次登入時都選忘記密碼來重設,等於每次都靠email或手機號碼取得登入權限,然後再隨機產生新的密碼
補充
補充1:OTP與2FA
- OTP(一次性驗證登入)
- 簡單來說就是透過綁定身分的通訊方式給予一次性授權的密碼,使用後即失效
- 除非產生後即被攔截,否則更難暴力破解
- 概念細節可參考維基百科的簡介
- 2FA(雙重/兩步驟認證)算是MFA(多重要素驗證)較常見的例子
- 常見方式如以帳號密碼/第三方平台登入後,仍需要OTP再度驗證
- 可避免帳號被破解後馬上被更改篡奪,相當於多一道鎖
- 概念細節可參考維基百科的簡介
補充2:社群平台等第三方帳號登入
- 串接常見的社群帳號(如Facebook、Google),其登入狀態可用於直接註冊新帳號,之後登入也可不用輸入帳密
- 若應用程式的開發為前後端分離,前端與後端的開發人員須溝通好串接的服務與方式
- 前端部分點擊後前往第三方平台的登入頁面,首次使用還會有授權確認,授權後即自動註冊帳號並登入
- 後端實作可使用基於OAuth 2.0的套件,如Laravel的Socialite和Express.js的Passport
- 第三方登入建立的帳號若無特別設計,其實沒有帳戶對應的密碼(或使用者不知道),無法也使用傳統帳密登入
- 若考慮讓同一組帳號能使用不同方式登入,則需要讓第三方登入註冊的使用者能另訂密碼,甚至還能綁定其他的第三方帳號
補充3:重點摘要與問題討論
- 本文首次於2022.02.17的Monosparta Tech Day發表
- 當日參與者有另外整理摘要筆記,以及分享會後的討論紀錄