java 单机接口限流处理方案
409
2022-10-09
FIDO U2F应用开发(二)-编程接口(fidodido)
1. U2F JS API
FIDO U2F定义了JavaScript API供开发者开发支持U2F设备的在线服务网站。U2F JS API分为两类:底层基于消息端口的API和上层应用API。在FIDO的规格文档中介绍底层API用于与U2F设备进行消息通讯(使用MessagePort Object),发送和接收消息。本文重点关注屏蔽了通讯细节的上层API接口。
2. 接口定义
2.1. u2f接口
使用WebIDL定义的u2f接口定义如下:
interface u2f {
void register (DOMString appId, sequence
2.2. register方法
2.2.1. 请求参数
register方法中各参数描述如下:
参数名称 | 类型 | 可否为空 | 是否可选 | 描述 |
---|---|---|---|---|
appId | DOMString | ✘ | ✘ | 请求中的应用ID |
registerRequests | sequence<RegisterRequest> | ✘ | ✘ | 注册请求序列 |
registeredKeys | sequence<RegisteredKey> | ✘ | ✘ | 已经注册到U2F设备的信息 |
callback | function(RegisterResponse or Error) | ✘ | ✘ | 注册请求回调函数 |
opt_timeoutSeconds | unsigned long | ✔ | ✔ | 客户端等待请求处理的超时时间 |
2.2.2. 返回值
register方法成功返回的数据(callback的参数)使用RegisterResponse结构。
dictionary RegisterResponse { DOMString version; DOMString registrationData; DOMString clientData; };
其中各属性含义如下:
version:U2F协议版本,如“U2F_V2” registrationData:使用websafe-base64编码后的注册数据,数据格式参看《FIDO U2F设备应用与开发(一)-原理与协议》3.2节。 clientData:使用websafe-base64编码后的clientData,数据格式参看《FIDO U2F设备应用与开发(一)-原理与协议》3.5节。 2.3. sign方法 2.3.1. 请求参数 sign方法中各参数描述如下:
参数名称 | 类型 | 可否为空 | 是否可选 | 描述 |
---|---|---|---|---|
appId | DOMString | ✘ | ✘ | 请求中的应用ID |
challenge | DOMString | ✘ | ✘ | 使用WEBSAFE-BASE64编码的挑战值 |
registeredKeys | sequence<RegisteredKey> | ✘ | ✘ | 待签名用户的注册信息 |
callback | function(SignResponse or Error) | ✘ | ✘ | 签名请求回调函数 |
opt_timeoutSeconds | unsigned long | ✔ | ✔ | 客户端等待请求处理的超时时间 |
2.3.2. 返回值
sign方法成功返回的数据(callback的参数)使用SignResponse结构。
dictionary SignResponse { DOMString keyHandle; DOMString signatureData; DOMString clientData; };
其中各属性含义如下:
keyHandle:请求中提供的key handle signatureData:使用websafe-base64编码后的签名数据,数据格式参看《FIDO U2F设备应用与开发(一)-原理与协议》3.4节。 clientData:使用websafe-base64编码后的clientData,数据格式参看《FIDO U2F设备应用与开发(一)-原理与协议》3.5节。 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. 接口中的数据结构 2.5.1. RegisterRequest 使用WebIDL定义的RegisterRequest结构如下: dictionary RegisterRequest { DOMString version; DOMString challenge; }; 属性含义如下: version:U2F协议版本,如“U2F_V2” challenge:使用websafe-base64编码的挑战值
2.5.2. RegisteredKey
使用WebIDL定义的RegisteredKey结构如下:
dictionary RegisteredKey { DOMString version; DOMString keyHandle; Transports? transports; DOMString? appId; };
各属性含义如下:
version:U2F协议版本,如“U2F_V2” keyHandle:用于签名用户的key handle transports:传输方式,可选参数 appId:在线服务网站应用Id
3. 编程接口实例探究
3.1. 注册过程
名称 | 值 |
---|---|
mode | bind |
username | zhangkai |
password | zhangkai |
enroll-data | {"challenge": "OlyOzHxaxx6LUXX5chXsxj4GfspKTskBANNOtQ_UwcA", "version": "U2F_V2", "appId": "https://demo.yubico.com"} |
data(u2f设备接口调用返回数据) | {"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. 鉴权过程
名称 | 值 |
---|---|
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设备接口返回数据) | {"keyHandle":"3sHb84XcS8HfFaQJ_nhf4aRlWe_wYRKcg5wKelF51hOiP4iNJtGPbsfe5InJmGfoxUSjtqT46HBwG7jkFtc01Q","clientData":"eyJ0eXAiOiJuYXZpZ2F0b3IuaWQuZ2V0QXNzZXJ0aW9uIiwiY2hhbGxlbmdlIjoiVUdaajM0dTl1M0tWV2UzakZyY0lubTdaY3JQV2FYX2o5dG9oWi0zNEZUMCIsIm9yaWdpbiI6Imh0dHBzOi8vZGVtby55dWJpY28uY29tIiwiY2lkX3B1YmtleSI6InVudXNlZCJ9","signatureData":"AQAAAAEwRQIhAMCCFSBV7V8kr07XDY2bT3aPI9siDiOFdFBIm8FVTRq1AiBVaYi06GWIHw6uHE_3MFkjrbSY13k5ukPU9_xnNAo_xQ"} |
服务端 验证签名后,返回验证成功信息。
3.3. 异常处理
实验过程中,如果在交互时不按U2F设备的按钮和不插入设备,register和sign函数都会返回错误码。错误码的定义可参看2.4节。
3.4. u2f-api.js
u2f-api.js是yubico提供的U2F js api,封装了第2节接口规范中描述的接口。可从地址: 处获取。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;
在执行3.1节的注册过程时,通过跟踪浏览器消息,可以看到第一次向服务器请求后返回的页面中包含如下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的上层函数register进行了注册,读者可以与2.2节的函数参数做一下比对,在这段代码中registeredKeys参数使用是空数组“[]”。 仔细阅读u2f-api.js,会发现脚本使用了EXTENSION_ID为“kmendfapggjehodndflmmgagdbamhnfd”的chrome内置扩展完成与U2F设备的通讯。 在执行3.2节的鉴权过程时,通过跟踪浏览器消息,可以看到第一次向服务器请求后返回的页面中包含如下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的上层函数sign进行了注册。
4. 浏览器兼容测试
TypeError: setting getter-only property "u2f"
IE浏览器使用的版本为11,不支持U2F设备。 在安卓手机上安装了chrome app,使用U2F设备的BLE模式(蓝牙功能)测试了U2F的支持,没有成功,在chrome调用register函数时,U2F设备没有闪烁。
5. 参考文献
https://fidoalliance.org/how-fido-works/ https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/FIDO-U2F-COMPLETE-v1.2-ps-20
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~