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