FIDO U2F應用與開發(三)-開發支援U2F的站點
1. 設計中的約束
U2F協議只能在支援HTTPS的網站上才可被支援,對於商業站點這不是問題,但對於區域網內或內部開發環境,我們使用自簽名證書來實現HTTPS。
U2F裝置在網頁上進行簽名和註冊時,會對請求中的“appId”進行檢查,“appId”在web應用中為此web應用的一個facet,應符合“Web Origin”定義(RFC6454):在實現時應為域名或機器名,不可為IP地址,且與請求訪問裝置頁面的“Web Origin”一致,否則會出現錯誤。對於“appId”,有Single-facet和Multi-facet兩種應用模式,有興趣的讀者看參看U2F的技術規範。
2. 一個支援U2F的站點DEMO
2.1. 如何獲取程式碼
https://github.com/solarkai/FIDO_U2F_KEDACOM 提供了一個支援U2F的站點專案。雖然只是一個站點DEMO,但提供了對使用者和U2F裝置管理的完整功能。
2.2. 如何構建執行
U2F該專案客戶端使用jquery和jquery-ui編寫,服務端使用spring-boot框架編寫。可使用maven進行構建,使用如下命令:
./mvnw clean package
U2F對於生成的jar包,可使用如下命令(建議JDK1.8)直接執行(需要注意當前工作目錄下要有tomcat.keystore檔案,不然會報spring的注入錯誤):
java -jar Kedacom-U2F-DEMO-0.0.1-SNAPSHOT.jar
U2F上面的程式執行後,啟動了一個tomcat伺服器,支援http和https兩種模式。使用者可在瀏覽器中使用“ http://localhost:8080 ” 和 “ https://localhost:8443 ” 兩種模式訪問,在http模式下不支援U2F裝置。
2.3 如何支援HTTPS
U2F為使用HTTPS,需要使用自簽名證書,我們使用JDK自帶的keytool生成自簽名證書tomcat.keystore,專案執行時放在當前工作目錄下。生成命令如下:
keytool -genkeypair -keystore tomcat.keystore-alias tomcat -keyalg RSA -keysize 2048 -validity 5000 -dname "CN=localhost, OU=kedacom, O=kedacom, L=shanghai, ST=shanghai, C=cn" -ext "SAN=DNS:localhost,IP:172.16.64.59" -ext "BC=ca:true"
U2F為使得瀏覽器對自簽名證書不產生告警,需要從tomcat.keystore中匯出公鑰證書(cer檔案)以匯入瀏覽器的“受信任的根證書頒發機構”,匯出公鑰證書的命令如下:
keytool -keystore tomcat.keystore -export -alias tomcat -file tomcat.cer
U2F在專案的application.properties檔案中,定義了相關HTTPS引數,這些引數在專案啟動時,被spring注入到變數中,application.properties定義如下:
#https https.port=8443 https.ssl.key-store=tomcat.keystore https.ssl.key-store-password=tomcat https.ssl.keyAlias=tomcat #u2f u2f.appId=https://localhost:8443
U2F如果讀者使用該專案的程式碼構建自己的站點時,一定要注意保證application.properties檔案中“u2f.appId”,tomcat.keystore中CN,SAN對域名(機器名)的一致性。
2.4. 如何實現使用者資料的持久化
U2F該專案中未實現使用者資料的磁碟持久化,這意味著伺服器一重啟,之前儲存的使用者資料都將丟失。但要實現持久化對於有興趣的讀者而言也是非常簡單的事情,專案中對於使用者資料的操作是使用com.kedacom.u2f.users.IUserStore實現的,系統啟動時注入該介面的實現物件,目前專案程式碼中使用的是com.kedacom.u2f.users.UsersStoreInmemory物件注入的。讀者只需將實現IUserStore的自定義持久化物件替代UsersStoreInmemory注入即可。
2.5. 站點功能
U2F該專案站點DEMO提供完整的使用者和U2F裝置管理功能,提供使用者的增加刪除修改,U2F裝置的註冊繫結和鑑權等功能。
2.5.1 使用者管理功能
U2F站點啟動時已經預設生成了admin使用者,可使用“admin/admin”的初始使用者名稱和密碼登入。圖1展示了使用者的增加、刪除和修改密碼功能。

圖1
2.5.2. 繫結、解綁U2F裝置
U2F該站點中一個使用者可繫結(註冊)多個U2F裝置,對同一個U2F裝置不可繫結兩次。而同一個U2F裝置可被多個使用者繫結。
圖2顯示了一個使用者的裝置繫結過程,站點在繫結時會提示使用者觸控裝置。

圖2
圖3顯示了裝置繫結後的資料。

圖3
圖4顯示了一個使用者繫結多個裝置的註冊資料,每個裝置的繫結資料以keyHandle作為標識。

圖4
可選擇其中的一個keyHandle解除繫結,該keyHandle對應的U2F裝置在登入鑑權時將不再起作用,如圖5所示。

圖5
2.5.3. 使用者登入鑑權
U2F對於綁定了U2F裝置的使用者,在登入時不僅要校驗使用者名稱和密碼,還需要驗證U2F裝置,如圖6所示。

圖6
2.6. 使用的第三方庫
U2F該專案在客戶端使用的U2F簽名和註冊介面指令碼均來自 https://demo.yubico.com/js/u2f-api.js , 服務端使用了yubico提供的u2flib-server-core和u2flib-server-attestation這兩個庫,可在pom檔案中增加如下依賴:
<dependency> <groupId>com.yubico</groupId> <artifactId>u2flib-server-core</artifactId> <version>0.19.0</version> </dependency> <dependency> <groupId>com.yubico</groupId> <artifactId>u2flib-server-attestation</artifactId> <version>0.19.0</version> </dependency>
U2F這兩個庫完成U2F設備註冊資訊中證書的驗證、公鑰的提取、簽名的驗證等功能,其核心類為com.yubico.u2f.U2F類,引用了java.security相關的包和類,程式碼值得一讀。