FIDO U2F應用開發(fā)(二)-編程接口

1. U2F JS API

??FIDO U2F定義了JavaScript API供開發(fā)者開發(fā)支持U2F設備的在線服務網(wǎng)站耻瑟。U2F JS API分為兩類:底層基于消息端口的API和上層應用API趁曼。在FIDO的規(guī)格文檔中介紹底層API用于與U2F設備進行消息通訊(使用MessagePort Object),發(fā)送和接收消息。本文重點關注屏蔽了通訊細節(jié)的上層API接口宠页。

2. 接口定義

2.1. u2f接口

??使用WebIDL定義的u2f接口定義如下:

interface u2f {
    void register (DOMString appId, sequence<RegisterRequest> registerRequests, sequence<RegisteredKey> registeredKeys, function(RegisterResponse or Error) callback, optional unsigned long? opt_timeoutSeconds);
    void sign (DOMString appId, DOMString challenge, sequence<RegisteredKey> registeredKeys, function(SignResponse or Error) callback, optional unsigned long? opt_timeoutSeconds);
};

2.2. register方法

2.2.1. 請求參數(shù)

??register方法中各參數(shù)描述如下:

參數(shù)名稱 類型 可否為空 是否可選 描述
appId DOMString ? ? 請求中的應用ID
registerRequests sequence<RegisterRequest> ? ? 注冊請求序列
registeredKeys sequence<RegisteredKey> ? ? 已經注冊到U2F設備的信息
callback function(RegisterResponse or Error) ? ? 注冊請求回調函數(shù)
opt_timeoutSeconds unsigned long ? ? 客戶端等待請求處理的超時時間

2.2.2. 返回值

??register方法成功返回的數(shù)據(jù)(callback的參數(shù))使用RegisterResponse結構。

dictionary RegisterResponse {
    DOMString version;
    DOMString registrationData;
    DOMString clientData;
};

??其中各屬性含義如下:

  • version:U2F協(xié)議版本,如“U2F_V2”
  • registrationData:使用websafe-base64編碼后的注冊數(shù)據(jù)省骂,數(shù)據(jù)格式參看《FIDO U2F設備應用與開發(fā)(一)-原理與協(xié)議》3.2節(jié)。
  • clientData:使用websafe-base64編碼后的clientData最住,數(shù)據(jù)格式參看《FIDO U2F設備應用與開發(fā)(一)-原理與協(xié)議》3.5節(jié)钞澳。

2.3. sign方法

2.3.1. 請求參數(shù)

??sign方法中各參數(shù)描述如下:

參數(shù)名稱 類型 可否為空 是否可選 描述
appId DOMString ? ? 請求中的應用ID
challenge DOMString ? ? 使用WEBSAFE-BASE64編碼的挑戰(zhàn)值
registeredKeys sequence<RegisteredKey> ? ? 待簽名用戶的注冊信息
callback function(SignResponse or Error) ? ? 簽名請求回調函數(shù)
opt_timeoutSeconds unsigned long ? ? 客戶端等待請求處理的超時時間

2.3.2. 返回值

??sign方法成功返回的數(shù)據(jù)(callback的參數(shù))使用SignResponse結構。

dictionary SignResponse {
    DOMString keyHandle;
    DOMString signatureData;
    DOMString clientData;
};

??其中各屬性含義如下:

2.4. 錯誤碼

??register和sign方法失敗時返回的錯誤碼定義如下:

interface ErrorCode {
    const short OK = 0;
    const short OTHER_ERROR = 1;
    const short BAD_REQUEST = 2;
    const short CONFIGURATION_UNSUPPORTED = 3;
    const short DEVICE_INELIGIBLE = 4;
    const short TIMEOUT = 5;
};

2.5. 接口中的數(shù)據(jù)結構

2.5.1. RegisterRequest

??使用WebIDL定義的RegisterRequest結構如下:

dictionary RegisterRequest {
    DOMString version;
    DOMString challenge;
};

屬性含義如下:

  • version:U2F協(xié)議版本兰吟,如“U2F_V2”
  • challenge:使用websafe-base64編碼的挑戰(zhàn)值

2.5.2. RegisteredKey

??使用WebIDL定義的RegisteredKey結構如下:

dictionary RegisteredKey {
    DOMString   version;
    DOMString   keyHandle;
    Transports? transports;
    DOMString?  appId;
};

各屬性含義如下:

  • version:U2F協(xié)議版本,如“U2F_V2”
  • keyHandle:用于簽名用戶的key handle
  • transports:傳輸方式茂翔,可選參數(shù)
  • appId:在線服務網(wǎng)站應用Id

3. 編程接口實例探究

3.1. 注冊過程

??讓我們來到y(tǒng)ubico的U2F設備測試網(wǎng)站(https://demo.yubico.com/u2f)混蔼, 使用yubico的安全key,看看register方法和sign方法如何使用珊燎。
??兩個U2F Key,如圖1所示惭嚣,其中一個帶藍牙功能遵湖。

圖1

??首先測試注冊過程,如圖2所示料按。
圖2

??通過跟蹤網(wǎng)站客戶端與服務端的交互消息奄侠,我們發(fā)現(xiàn)開始注冊過程后,客戶端向服務端的提交了兩次請求载矿,對應《FIDO U2F設備應用與開發(fā)(一)-原理與協(xié)議》第3節(jié)描述的3個階段中的第1和第3階段垄潮。
??客戶端第一次向服務端提交請求后,參數(shù)包含用戶名和口令闷盔,如圖3所示弯洗。
圖3

??在客戶端JS腳本對服務端返回的注冊請求進行register函數(shù)調用后,將register的注冊數(shù)據(jù)提交給服務端逢勾,提交的表單數(shù)據(jù)如圖4所示牡整。


圖4

??由圖4提交的數(shù)據(jù)可以看到register返回成功,提交的表單數(shù)據(jù)為:

名稱
mode bind
username zhangkai
password zhangkai
enroll-data {"challenge": "OlyOzHxaxx6LUXX5chXsxj4GfspKTskBANNOtQ_UwcA", "version": "U2F_V2", "appId": "https://demo.yubico.com"}
data(u2f設備接口調用返回數(shù)據(jù)) {"registrationData":"BQSns2lmNJhJPSFbiDioTABT5xd2OZQpmpZFREJpbiaQC8zssXg0jLaxz8_gMioQQILSE5lsbH5BqpJwWR4rJoI1QMxn5LhVlLKhs_W-F7x4ppkw9K57h7dsTCDsikFv9BnpfSvj8XYhEHV-KEoBg8sNXq_I6-PRQ5_Z6yDkAFzrlBQwggJKMIIBMqADAgECAgQSSnL-MA0GCSqGSIb3DQEBCwUAMC4xLDAqBgNVBAMTI1l1YmljbyBVMkYgUm9vdCBDQSBTZXJpYWwgNDU3MjAwNjMxMCAXDTE0MDgwMTAwMDAwMFoYDzIwNTAwOTA0MDAwMDAwWjAsMSowKAYDVQQDDCFZdWJpY28gVTJGIEVFIFNlcmlhbCAyNDk0MTQ5NzIxNTgwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ9ixu9L8v2CG4QdHFgFGhIQVPBxtO0topehV5uQHV-4ivNiYi_O-_XzfIcsL9dehUNhEr-mBA8bGYH2fquKHwCozswOTAiBgkrBgEEAYLECgIEFTEuMy42LjEuNC4xLjQxNDgyLjEuMTATBgsrBgEEAYLlHAIBAQQEAwIFIDANBgkqhkiG9w0BAQsFAAOCAQEAoU8e6gB29rhHahCivnLmDQJxu0ZbLfv8fBvRLTUZiZFwMmMdeV0Jf6MKJqMlY06FchvC0BqGMD9rwHXlmXMZ4SIUiwSW7sjR9PlM9BEN5ibCiUQ9Hw9buyOcoT6B0dWqnfWvjjYSZHW_wjrwYoMVclJ2L_aIebzw71eNVdZ_lRtPMrY8iupbD5nGfX2BSn_1pvUt-D6JSjpdnIuC5_i8ja9MgBdf-Jcv2nkzPsRl2AbqzJSPG6siBFqVVYpIwgIm2sAD1B-8ngXqKKa7XhCkneBgoKT2omdqNNaMSr6MYYdDVbkCfoKMqeBksALWLo2M8HRJIXU9NePIfF1XeUU-dzBFAiAtXTkSxA8NFX8RU-qNtKdzBkuVSk-rIFjhkCJRALTIBwIhAKjY3XT8vJgjgyOyGhEyxGF8zQonpWvdOwFoTe77cOv-","version":"U2F_V2","challenge":"OlyOzHxaxx6LUXX5chXsxj4GfspKTskBANNOtQ_UwcA","attestation":"direct","clientData":"eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZmluaXNoRW5yb2xsbWVudCIsImNoYWxsZW5nZSI6Ik9seU96SHhheHg2TFVYWDVjaFhzeGo0R2ZzcEtUc2tCQU5OT3RRX1V3Y0EiLCJvcmlnaW4iOiJodHRwczovL2RlbW8ueXViaWNvLmNvbSIsImNpZF9wdWJrZXkiOiJ1bnVzZWQifQ"}

3.2. 鑒權過程

??注冊成功后溺拱,可執(zhí)行鑒權(login)過程逃贝,如圖5所示。


圖5

??通過跟蹤網(wǎng)站客戶端與服務端的交互消息迫摔,第一次客戶端請求時攜帶了用戶名和密碼沐扳,如圖6所示。


圖6

??在客戶端JS腳本對服務端返回的簽名請求進行sign函數(shù)調用后句占, U2F設備產生簽名后沪摄,客戶端將簽名數(shù)據(jù)提交到服務端,如圖7所示纱烘。
圖7

??提交的表單數(shù)據(jù)為:

名稱
mode verify
rup
username zhangkai
password zhangkai
sign-data {"challenge": "UGZj34u9u3KVWe3jFrcInm7ZcrPWaX_j9tohZ-34FT0", "version": "U2F_V2", "keyHandle": "3sHb84XcS8HfFaQJ_nhf4aRlWe_wYRKcg5wKelF51hOiP4iNJtGPbsfe5InJmGfoxUSjtqT46HBwG7jkFtc01Q", "appId": "https://demo.yubico.com"}
data(u2f設備接口返回數(shù)據(jù)) {"keyHandle":"3sHb84XcS8HfFaQJ_nhf4aRlWe_wYRKcg5wKelF51hOiP4iNJtGPbsfe5InJmGfoxUSjtqT46HBwG7jkFtc01Q","clientData":"eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwiY2hhbGxlbmdlIjoiVUdaajM0dTl1M0tWV2UzakZyY0lubTdaY3JQV2FYX2o5dG9oWi0zNEZUMCIsIm9yaWdpbiI6Imh0dHBzOi8vZGVtby55dWJpY28uY29tIiwiY2lkX3B1YmtleSI6InVudXNlZCJ9","signatureData":"AQAAAAEwRQIhAMCCFSBV7V8kr07XDY2bT3aPI9siDiOFdFBIm8FVTRq1AiBVaYi06GWIHw6uHE_3MFkjrbSY13k5ukPU9_xnNAo_xQ"}

??服務端 驗證簽名后杨拐,返回驗證成功信息。

3.3. 異常處理

??實驗過程中擂啥,如果在交互時不按U2F設備的按鈕和不插入設備哄陶,register和sign函數(shù)都會返回錯誤碼。錯誤碼的定義可參看2.4節(jié)哺壶。

3.4. u2f-api.js

??u2f-api.js是yubico提供的U2F js api奕筐,封裝了第2節(jié)接口規(guī)范中描述的接口”渎猓可從地址: https://demo.yubico.com/js/u2f-api.js 處獲取。u2f-api.js中的主要定義如下:

var u2f = u2f || {};
u2f.register = function(appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds)
u2f.sign = function(appId, challenge, registeredKeys, callback, opt_timeoutSeconds)

??請注意在這個腳本中將register和sign操作的超時時間定義為30秒:

u2f.EXTENSION_TIMEOUT_SEC = 30;

??在執(zhí)行3.1節(jié)的注冊過程時芭逝,通過跟蹤瀏覽器消息塌碌,可以看到第一次向服務器請求后返回的頁面中包含如下JS代碼:

setTimeout(function() {
  var request = {"challenge": "OlyOzHxaxx6LUXX5chXsxj4GfspKTskBANNOtQ_UwcA", "version": "U2F_V2", "appId": "https://demo.yubico.com"};
  console.log("Register: ", request);
  var appId = request.appId;
  var registerRequests = [{version: request.version, challenge: request.challenge, attestation: 'direct'}];
  $('#promptModal').modal('show');
  console.log(appId, registerRequests);
  u2f.register(appId, registerRequests, [], function(data) {
    console.log("Register callback", data);
    $('#promptModal').modal('hide');
    $('#bind-data').val(JSON.stringify(data));
    $('#bind-form').submit();
  });
}, 1000);

??這段代碼中,使用U2F的上層函數(shù)register進行了注冊旬盯,讀者可以與2.2節(jié)的函數(shù)參數(shù)做一下比對台妆,在這段代碼中registeredKeys參數(shù)使用是空數(shù)組“[]”翎猛。
??仔細閱讀u2f-api.js,會發(fā)現(xiàn)腳本使用了EXTENSION_ID為“kmendfapggjehodndflmmgagdbamhnfd”的chrome內置擴展完成與U2F設備的通訊接剩。
??在執(zhí)行3.2節(jié)的鑒權過程時切厘,通過跟蹤瀏覽器消息,可以看到第一次向服務器請求后返回的頁面中包含如下JS代碼:

setTimeout(function() {
  var request = {"challenge": "UGZj34u9u3KVWe3jFrcInm7ZcrPWaX_j9tohZ-34FT0", "version": "U2F_V2", "keyHandle": "3sHb84XcS8HfFaQJ_nhf4aRlWe_wYRKcg5wKelF51hOiP4iNJtGPbsfe5InJmGfoxUSjtqT46HBwG7jkFtc01Q", "appId": "https://demo.yubico.com"};
  console.log("sign: ", request);
  var appId = request.appId;
  var challenge = request.challenge;
  var registeredKeys = [{version: request.version, keyHandle: request.keyHandle}];
  $('#promptModal').modal('show');
  u2f.sign(appId, challenge, registeredKeys, function(data) {
    $('#promptModal').modal('hide');
    $('#verify-data').val(JSON.stringify(data));
    $('#verify-form').submit();
  });
}, 1000);

??這段代碼中懊缺,使用U2F的上層函數(shù)sign進行了注冊疫稿。

4. 瀏覽器兼容測試

??使用購買的U2F設備在PC上對chrome、firefox鹃两、IE瀏覽器進行了測試遗座。其中chrome版本為69,firefox版本為firefox quantum 62, 這兩種瀏覽器目前都支持U2F設備俊扳。
??在firefox中使用U2F需要打開一個開關(默認沒有打開)途蒋,如圖8所示。

圖8

??這里有個有趣的問題馋记,測試時使用的網(wǎng)站仍然是https://demo.yubico.com/u2f 号坡,JS腳本仍然使用的是u2f-api.js,前面提到這個腳本是針對chrome內置擴展應用與USB口通信的梯醒,在firefox中怎么也能正常使用呢宽堆?
??原因就是firefox實現(xiàn)了自己的u2f對象,而且這個u2f對象的所有屬性都是只讀的冤馏,u2f-api.js沒有改寫這個對象日麸,從控制臺如下輸出可以看到:

TypeError: setting getter-only property "u2f"

IE瀏覽器使用的版本為11,不支持U2F設備逮光。
??在安卓手機上安裝了chrome app,使用U2F設備的BLE模式(藍牙功能)測試了U2F的支持代箭,沒有成功,在chrome調用register函數(shù)時涕刚,U2F設備沒有閃爍嗡综。

5 應用demo

??參看FIDO U2F應用開發(fā)(三)-開發(fā)支持U2F的站點

6. 參考文獻

  1. https://fidoalliance.org/how-fido-works/
  2. https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/FIDO-U2F-COMPLETE-v1.2-ps-20
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末杜漠,一起剝皮案震驚了整個濱河市极景,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驾茴,老刑警劉巖盼樟,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锈至,居然都是意外死亡晨缴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門峡捡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來击碗,“玉大人筑悴,你說我怎么就攤上這事∩酝荆” “怎么了阁吝?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長械拍。 經常有香客問我突勇,道長,這世上最難降的妖魔是什么殊者? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任与境,我火速辦了婚禮,結果婚禮上猖吴,老公的妹妹穿的比我還像新娘摔刁。我一直安慰自己,他們只是感情好海蔽,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布共屈。 她就那樣靜靜地躺著,像睡著了一般党窜。 火紅的嫁衣襯著肌膚如雪拗引。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天幌衣,我揣著相機與錄音矾削,去河邊找鬼。 笑死豁护,一個胖子當著我的面吹牛哼凯,可吹牛的內容都是我干的。 我是一名探鬼主播楚里,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼断部,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了班缎?” 一聲冷哼從身側響起蝴光,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎达址,沒想到半個月后蔑祟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡沉唠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年做瞪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡装蓬,死狀恐怖,靈堂內的尸體忽然破棺而出纱扭,到底是詐尸還是另有隱情牍帚,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布乳蛾,位于F島的核電站暗赶,受9級特大地震影響,放射性物質發(fā)生泄漏肃叶。R本人自食惡果不足惜蹂随,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望因惭。 院中可真熱鬧岳锁,春花似錦、人聲如沸蹦魔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽勿决。三九已至乒躺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間低缩,已是汗流浹背嘉冒。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留咆繁,地道東北人讳推。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像么介,于是被迫代替她去往敵國和親娜遵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內容