引言 2016年中,我所在的項目組將原來系統中的登錄模塊拆出來做成一套集中賬號管理系統,並對外提供單點登錄的服務。後來,公司中需要使用員工賬號進行登錄的系統越來越多,但這些系統都是各有各的實現方式,管理比較混亂。為了推廣我們組的賬號管理系統,統一公司的賬號體系,我寫了一篇“軟文”希望在公司技術月刊上 ...
引言
2016年中,我所在的項目組將原來系統中的登錄模塊拆出來做成一套集中賬號管理系統,並對外提供單點登錄的服務。後來,公司中需要使用員工賬號進行登錄的系統越來越多,但這些系統都是各有各的實現方式,管理比較混亂。為了推廣我們組的賬號管理系統,統一公司的賬號體系,我寫了一篇“軟文”希望在公司技術月刊上發表,便是這篇文章的來歷。
隨著公司業務的不斷發展,各種內部管理系統也越來越多,這些系統雖然功能職責各不相同,但有一個功能模塊是所有這些系統都必備的,那就是登錄模塊。登錄模塊負責生成並存儲識別用戶身份的數據,在有用戶對系統進行操作的時候驗明用戶的真實身份,併進行適當的許可權限制。
如何實現登錄模塊
要實現一個基礎的登錄模塊非常簡單,大概有下麵幾個步驟:
- 實現用戶註冊頁面,用戶填寫包括用戶名密碼的基本信息之後,將用戶信息存儲到資料庫。
- 用戶嘗試對系統進行操作前,判斷用戶是否登錄,如果沒有就跳轉到登錄頁面讓用戶輸入用戶名密碼。
- 用戶輸入正確的用戶名密碼之後,驗明用戶身份並生成 session 和 cookie,以便在用戶做下一次操作時判斷用戶的身份和許可權。
完成上述三個步驟,一個基本的用戶登錄模塊就完成了。但是,凡事總有但是,事情並沒有這麼簡單。在一個真實的場景中,作為系統信息安全的重要保障,登錄模塊往往還需要考慮很多的實現細節。
-
弱口令限制
很多用戶在註冊的時候,喜歡使用非常簡單的密碼,比如 123456 或者 qweasd 之類的。尤其在企業內部系統中,這種用戶密碼更是常見。但是,這類密碼簡直形同虛設,如此簡單的用戶密碼,非常容易被惡意用戶猜解,從而導致信息的泄露,對企業信息安全造成嚴重威脅。為了避免這種情況的發生,我們在新用戶註冊或用戶重設密碼的時候,往往會對用戶密碼複雜度做出一定的限制,比如要求用戶密碼必須同時包含數字、大寫字母、小寫字母、特殊符號四類字元中的至少三類,且密碼位數不能低於8位。
-
註冊驗證
作為一個企業內部系統,我們往往不希望企業外部人員也能夠註冊成為用戶,因為這很可能會導致企業內部信息的泄露。那麼,如何保證外部人員無法註冊呢?常見的手段是使用企業郵箱對註冊人的身份進行驗證。比如,用戶在註冊時,除了要用戶輸入用戶名和密碼以外,還需要用戶輸入其企業郵箱賬號。用戶提交註冊表單後,系統驗證其輸入的郵箱賬號是企業內部的合法郵箱賬號,並向這個郵箱發一封註冊驗證郵件,其內包含一個隨機生成的複雜鏈接,用戶點擊這個鏈接之後,才能完全註冊成功。
-
加密存儲密碼
用戶註冊成功之後,系統需要將用戶名和密碼的相關信息寫入資料庫或類似介質,以便用戶下次登錄系統時查詢驗證。可是為了防備一些非常規的情況,我們往往不能直接明文存儲用戶的密碼,而是用摘要演算法對用戶密碼進行若幹處理,再將摘要信息寫入資料庫中。比如,用戶的原始密碼是 hell0W0rld ,我們先用 MD5 演算法對密碼做摘要,得到摘要密文 17529cb075a386f08409f260bf0dfb8c ,然後再用用戶的註冊時間戳作為 salt 拼接到密文上,得到 17529cb075a386f08409f260bf0dfb8c1484547629852 ,再對這個字元串用 MD5 演算法做摘要,得到密碼摘要信息 6ee203a6a6c05a6f8f958c5be00b1313 ,最後我們將用戶名、密碼摘要信息、用戶註冊時間戳三個信息全部寫入資料庫中,以便將來驗證用戶身份。
這樣的做法雖然看起來比較繁瑣,但其安全性得到了比較高的保障。即使資料庫中的密碼信息被完全盜取,且用戶的原始密碼相對簡單,面對加了隨機salt且做過兩次摘要的密碼信息,想要猜解出原始密碼也是非常困難的
-
驗證碼
暴力猜解是比較常見的用戶信息猜解手段,簡單點說,就是用程式反覆嘗試用不同的密碼登錄某個賬戶,直到成功為止。這種破解用戶密碼的方式,一方面增加了用戶信息泄露的風險,另一方面也由於系統需要不斷的查詢資料庫驗證密碼正確性,而大大增加了系統的資源消耗。為了防止這種情況,一般我們需要通過隨機圖片驗證碼來驗證當前提交登錄請求的是人而不是某種程式。而一般為了平衡用戶體驗和系統安全性兩方面的要求,常見的做法是用戶輸錯密碼3次後再要求用戶輸入驗證碼。
-
失敗次數
雖然我們加了圖片驗證碼提高系統的安全性,但還是有一些比較高級的破解程式,可以正確識別出圖片驗證碼的內容。所以,我們還需要加上嘗試失敗次數的限制,當用戶嘗試登錄失敗超過指定的次數之後,系統就會鎖定該賬號。一段時間內,無論用戶是否輸入正確的用戶密碼,系統都拒絕該賬號的登錄請求,必須找系統管理員手段解鎖,或等待一段時間之後才能再次嘗試。
-
找回密碼
找回密碼也是很常見的需求點。用戶有時候真的會忘記自己的密碼,這時,需要用戶能夠手動重置自己的密碼。常見的做法是用戶提交重置密碼請求,系統向該用戶的註冊郵箱發一封密碼重置郵件,內含一個隨機生成的複雜鏈接,用戶通過這個鏈接地址訪問系統的密碼重置頁面來重置自己的密碼。
-
HTTPS
用戶在發起登錄請求時,輸入的賬號和密碼信息通過網路發往伺服器,這些信息在發往伺服器的過程中會經歷非常多的網路節點,如果信息在傳輸過程中是明文狀態,那麼這些網路節點就都可以獲取到用戶的賬號和密碼信息,這將成為非常大的系統信息安全隱患。因此,對用戶登錄過程中的敏感信息進行加密傳輸是非常必要的。最常見的做法就是對登錄請求用 HTTPS 協議代替 HTTP 協議。
-
跨平臺特性
很多的系統都具有跨平臺特性,比如 OA 系統,我們可以在 PC 上填寫加班申請單,在手機瀏覽器上查看這個申請單的審批狀態,而如果公司員工是在微信中訪問 OA 系統的頁面,OA 系統還會通過關聯的微信賬號讓用戶直接登錄系統,免去了輸入用戶名密碼的步驟,從而大大提高了用戶操作的便利性。
由此我們可以看出,要實現一個功能完備又安全的登錄模塊,並不是一件非常簡單的事情,這其中設計、開發、測試的工作都需要花費大量的時間和人力,那麼我們又怎麼能在兩分鐘內為各應用系統實現這麼多複雜的功能呢?答案就是使用 UserCenter。
如何使用 UserCenter
UserCenter 是 OA 組根據公司實際業務場景設計實現的單點登錄系統,功能完善,可靠性高,使用方便。
使用 UserCenter 只需簡單的兩個步驟:
-
安裝 UserCenter SDK
UserCenter 通過 Composer 包分發其 SDK,只要在項目的 Composer 配置中聲明依賴 UserCenter 就可以了。
-
修改 Controller 基類的 _initialize 方法,調用 UserCenter 的介面
複製上面的代碼到 Controller 基類中,修改第 4 行和第 15 行的代碼即可。
UserCenter 的其他優勢
UserCenter 系統不僅功能完備安全性高,可靠性也值得信賴。目前系統採用主從備份部署方式,武漢和深圳機房各有一套服務處於運行狀態。員工賬號數據能夠實時在主從服務間進行同步,一旦主服務因網路或電力故障無法訪問,系統會將登錄和身份驗證的相關網路請求切換到備用服務上,使得各應用系統的用戶登錄功能不受影響。
同時,UserCenter 還支持各種第三方系統通過 LDAP 介面接入,如公司正在使用 PMS、WIKI 以及 JENKINS 系統等等。
另外,使用 UserCenter 之後,公司各內部系統共用同一套賬號系統,在新員工入職和老員工離職時,賬號的創建和回收工作都將更加便利和安全。同時,由於使用 UserCenter 的各個應用系統不再需要單獨保存用戶的賬號和密碼信息,使得公司員工賬號泄露的風險大大降低。
結語
目前,公司還沒有統一的的身份驗證策略和框架。隨著業務的增長和時間的推移,這將導致大量內部系統都擁有一套自己的身份驗證模塊和用戶賬號數據。每個員工都需要記住多個用戶名和密碼,才能訪問各個不同的系統。這給系統管理人員以及公司的各個員工都帶來很大的負擔。如果沒有統一的策略,開發人員就需要為每個系統重覆實現定製的登錄模塊,這還會導致各種維護上的麻煩問題。UserCenter 為安全性和身份驗證提供了統一的範式,大大減輕了用戶、管理員和開發人員的負擔。