从通用浏览器访问智能卡的架构?或者:如何弥合从浏览器到 PC/SC 堆栈的差距?

Posted

技术标签:

【中文标题】从通用浏览器访问智能卡的架构?或者:如何弥合从浏览器到 PC/SC 堆栈的差距?【英文标题】:Architectures to access Smart Card from a generic browser? Or: How to bridge the gap from browser to PC/SC stack? 【发布时间】:2013-04-04 09:14:19 【问题描述】:

有哪些可能的客户端架构可以从通用浏览器(通过 http(s) 连接到服务器)访问本地智能卡,最好从 javascript 访问,并且最终用户的安装麻烦最少?服务器至少需要能够向卡发出它选择的 APDU(或者可能将其中的一些委托给它生成的客户端代码)。我假设在工作 PC/SC 堆栈的客户端可用,并配有智能卡读卡器。至少在自 XP、现代 OS X 和 Unix 之后的 Windows 上,这是一个合理的假设。

到目前为止,我已经确定了以下选项:

    一些自定义 ActiveX。这就是我现有的应用程序使用的(我们内部开发的),一旦获得安装 ActiveX 的许可,对于使用 IE 的客户来说,部署非常容易,但它不符合“通用浏览器”的要求。 更新:ActiveX 主要由已弃用的 IE 支持,包括 IE11;但不是 Edge。 一些使用 Netscape Plugin API 的 PC/SC 浏览器扩展,这似乎是上述的平滑扩展。我找到的唯一现成的是SConnect (webarchive)。它不再被推广(更新:至少在 one application 中仍然积极维护和使用 2020 年末),它的 API documentation (webarchive) 不再正式可用,它与特定的 Smart 有着密切的联系卡和读卡器供应商。原理可能很好,但是为每个平台制作这样的插件将是很多工作。 更新:许多浏览器都放弃了对 NPAPI 的支持,包括 Chrome 和 Firefox。 一个 Java 小程序,运行在 Oracle 的 JVM (1.)6 或更高版本之上,带有 javax.smartcardio。从功能的角度来看,这很好,有据可查,我可以忍受少数已知的错误,但我担心在接受 Java-as-a-browser-extension 方面会出现不可抗拒的恶性循环。 [更新,2021 年 2 月]:这个 answer 在 2015 年认为 WebUSB API 是一个很有前途的解决方案,然后在 2019 年报告说不能工作或被放弃。我提出了一个问题there。

还有什么想法吗?

另外:是否有某种方法可以防止恶意服务器滥用浏览器的任何 PC/SC 接口(例如,提供 3 个错误的 PIN 码来阻止卡,只是为了它的肮脏;或者做一些更邪恶的事情)。

【问题讨论】:

你见过***.com/questions/8792899/… @flup:感谢您的指点。看起来那里列出的解决方案是面向 PKCS#11 的,而我所针对的智能卡(用于支付公共交通的各种卡)不是。 Java Applet 是 NPAPI 插件解决方案的子集。 现在 Chrome 不再支持 NPAPI,也许需要更新... 就我而言,我在连接到阅读器的 PC 上安装了一个 signalR 集线器作为 Windows 服务,这对我来说效果很好。 【参考方案1】:

事实上,除了建立 SSL 之外,浏览器无法与(加密)智能卡进行通信。

需要由浏览器执行的附加代码来访问智能卡。

有数十个自定义和专有插件(使用您提到的所有三个选项)用于各种目的(我猜是最流行的签名),因为没有标准或普遍接受的方式,至少在欧洲和我'我肯定在其他地方也是如此。

创建、分发和维护您自己的代码将是一件大事,因为浏览器每个月左右发布一次,并且每个新版本都会更改 sanboxing ir UI 技巧,因此您可能需要经常调整代码。

而且您可能希望拥有 GUI 功能,至少在请求用户许可以访问卡片或卡片上的某些功能时。

对于创建多平台、多浏览器插件,可以使用 firebreath 之类的东西。

就我个人而言,我认为将 PC/SC 暴露在网络上没有任何好处。 PC/SC 本质上是一种低级协议,在公开此协议时,您也可以公开对磁盘的块级访问,并希望“网络上的应用程序仅属于我的,并且它们表现良好”(这应该回答您的“也”)。同时,像 SConnect 这样的薄垫片是最容易创建的,用于提供 javscript plugin.sendAPDU() 样式的代码(或者只是包装所有 PC/SC API 并让 javascript 调用者处理相同级别的细节与本地 PC/SC API 用例一样)。

为此目的创建插件通常是由严重的当前缺陷驱动的。

解决未来(移动等)是另一回事,W3C webcrypto 和 OpenMobile API 之类的东西可能最终会以某种方式创建将客户端密钥容器暴露给 Web 应用程序的东西。如果您的智能卡目标是密码学,我的建议是避免使用 PC/SC 并使用平台服务(Windows 上的 CryptoAPI、OSX 上的 Keychain、Linux 上的 PKCS#11)

任何类型的设计都有要求。如果您正在考虑使用 keys 而不是任意 APDU-s,这一切都适用。如果您的要求是发送任意 APDU-s,请创建一个插件并使用它。

【讨论】:

+1 对于使用通用浏览器插件框架的想法,不知道 firebreath。是的,我需要通用 APDU 访问权限,因为应用程序需要支持广泛且不断发展的智能卡。此外,有一个专门的,例如签名插件本质上并不比拥有 APDU 插件更安全:如果智能卡在这里签名,我们不希望流氓服务器使用插件来签名任何东西。 当然不是。这样的签名插件通常会处理(有问题的)法律警告(“您即将签署具有法律约束力的等”)和所见即所得的方案(至少比仅仅签署一些东西更好)。这里的重点是插件提供了一组固定的更高级别的功能,其中本地安装的代码(可以签名等)负责对整个模型的一些保护,并询问用户对某些事情的许可用户可以理解。 ("你要签名吗?" 是/否。你想在网站 example.com 上签名 "blablabla",然后请输入您的 PIN 码";用户理解 PIN 输入不断弹出的对话框很糟糕;用户知道在随机网页上弹出的窗口很糟糕等)而“android 风格”“您是否希望网站 X 被授予访问您的智能卡的权限”打开一个巨大的窗口可能性并假设用户可以单独批准每个 APDU 是......奇怪。 哦,无论如何,现在每个服务器的“允许访问”问题(很像它适用于 cookie、JS 和现代浏览器中的所有其他东西)是一个简单的必要条件。但是流氓服务器(最好称之为专用攻击者)还有其他方法可以让 JS 运行。 SSL 不是典型的智能卡任务,因为所涉及的密钥是新协商的,仅用于一个会话,不需要长期高度保护的秘密,作为私钥。我会将用户身份验证标记为最重要的工作。【参考方案2】:

更新 (8/2016):正在讨论一种名为 WebUSB API 的新 Web API。你可以already use it with Chrome v54+。

该标准将在所有主要浏览器中实施,并将取代对第三方应用程序或智能卡扩展的需求 :-)

所以新的答案是肯定的!

类似 OSI 的架构堆栈是:

PC/SC CCID v1.1 WebUSB API USB 驱动,i.e. libusb。

2019 年更新:正如@vlp 评论的那样,它似乎在 Chrome 中不起作用,因为他们出于某些似是而非的原因决定阻止智能卡的 WebUSB :-(


注意:Google 宣布他们在 2017 年 will abandon Chrome Apps。

上一个回答者

现在(2015 年)您可以使用 chrome.usb API 创建一个 Google Chrome 应用程序。

然后您通过其CCID-compliant 接口访问智能卡读卡器。

它不是跨浏览器,而是 JavaScript 可编程和跨平台。

现代浏览器不再支持 Netscape 插件 API (NPAPI)。浏览器供应商正在摒弃 Java 小程序。

【讨论】:

除非您运行的是 ChromeOS,否则我怀疑您是否可以通过 chrome.usb API 连接到智能卡读卡器。如果操作系统有处理设备的驱动程序(典型的 CCID 读取器就是这种情况),chrome.usb 将被拒绝访问设备(请参阅您提供的链接中的 caveats 部分)。此外,用 JavaScript 编写 CCID 和 T=0/T=1 协议栈肯定会很痛苦。 @dim。你能行的。我做到了。适用于 Windows 7-10。 说真的?!!!我无法想象。但如果你这么说,那么,我值得一试。如果它真的有效,我会在上帝创造的每一天祝福你。我马上开始投赞成票。但我仍然怀疑......操作系统如何设法使外​​设同时可供 chrome.usb API 和 PC/SC 驱动程序使用? 我使用的是 WinUSB(或 libusb,或 libusb-K)通用驱动程序,而不是 Chrome 无法识别的供应商 (Omnikey) 的通用驱动程序。如果你需要,你可以雇用我;-)。我没有实现整个 PC/SC 堆栈,但我可以选择 DF / 读 / 写 EF / 执行哈希 / 中止 .. 简称 APDU。我很痛苦,你是对的。 不幸的是,Chrome 开始在 WebUSB API 中阻止智能卡读卡器(参见例如 here 和 here)【参考方案3】:

我刚刚发布了一个测试版插件来解决这个问题。 此测试版代码可在此处获得:

https://github.com/ubinity/webpcsc-firebreath

此插件基于 firebreath 框架,并已在 Linux/WinXP/Win7 下使用 Fireofx 和 Chrome 进行 beta 测试。提供源代码和扩展包。

基本思路是提供一个 PCSLite API 访问,然后在此基础上开发更友好的 JS-api。

此插件正在积极开发中,请随时发送任何报告和请求。

【讨论】:

【参考方案4】:

对于您的第一个问题,我希望不大:要么您对智能卡的一小部分功能(例如签署电子邮件或 PDF)感到满意,那么您可以使用一些现成的软件(例如 PKCS),理想情况下由智能卡公司维护,或者您想要更广泛的功能并且需要自己投入大量精力。当然,PCSC 是选择的起点。

至少对你的“也:”有一些希望。

1) 请注意,某些规范(例如 ICAO/德国 BSI TR-3110)要求一种方法,其中 PIN 不会被阻止,但一旦错误计数器在回复前达到 1,就会使用大量时间。最终尝试必须使用不同的命令启用,否则不会进行进一步的比较和错误计数器调整。

2) 通过要求安全消息传递来简单地保护验证命令。敏感的应用程序对所有内容都使用安全消息传递,因此第一步是对会话密钥进行协商,然后将其应用于所有后续命令和响应。结果是,在错误计数器的比较或修改完成之前很久,由于 MAC 不正确,命令被拒绝。

【讨论】:

您没有回答如何弥合浏览器和 PC/SC 之间的鸿沟的问题。也许我会改写我的问题。另外:1)很好,不知道。 2) 安全消息传递需要秘密;这会阻止在其传统用例中使用 PIN:离线、无 SAM POST。【参考方案5】:

还有另一个类似于@cslashm 提出的浏览器插件,可在http://github.com/cardid/WebCard 找到。也是开源的,可以按照原始问题的要求使用“最小安装麻烦”进行安装。您可以访问http://plugin.cardid.org查看使用示例

WebCard 已经在 IE 8 到 11、Windows 中的 Chrome 和 Firefox 以及 Mac OS X 中的 Chrome 和 Safari 中进行了测试。由于它只是 PC/SC 的包装器,因此它需要在 Mac OS X 中安装来自 @ 的 SmartCard 服务987654323@

【讨论】:

它也在linux上运行? 该插件使用同样支持 Linux 的 http:://firebreath.org 框架,但我没有尝试为该平台构建。 @giuseppe 你有构建工具试试吗? 嗨。使用构建工具是指 gcc 和兄弟?是的,我有它...你能指导我吗? @giuseppe 您可以查看firebreath.org/display/documentation/Building+on+Linux,一旦您在 Linux 中构建了 Firebreath 插件示例,您就可以尝试构建 Linux 版本的 WebCard。 你能告诉我文档在哪里吗?我不明白如何向智能卡发送命令以读取其证书...【参考方案6】:

由于 chrome 和 firefox 将停止对 NPAPI 插件的支持,因此没有可用于维护智能卡读取会话的安全解决方案,而是您的卡证书支持双向 ssl,我回答了类似的问题@ 987654321@,可能有帮助

【讨论】:

【参考方案7】:

它很脏,但是如果在客户端机器上安装桥接守护程序/服务可以接受/可行,那么您可以编写一个本地桥接服务(例如在 python / pyscard 中),通过 REST 接口公开智能卡,然后有浏览器中的 javascript 在本地服务(外观)和远程服务器 API 之间进行调解。

【讨论】:

【参考方案8】:

说到 Chrome,您现在可以使用 Google 提供的 Smart Card Connector app,它捆绑了 PC/SC-Lite 端口和通用 CCID 驱动程序。

应用程序本身通过chrome.usb API 运行,前面的评论者提到了这一点。

因此,开发人员现在可以只编写在 PC/SC API 之上工作的部分(由连接器应用程序公开),而不是重写整个堆栈(从最低级别开始 - 原始 USB)。

【讨论】:

正如现在在other answer 中指出的那样,Google 宣布他们将在 2017 年 abandon Chrome Apps。因此,基于 Smart Card Connector 应用程序或/和 chrome.usb API 的解决方案是短暂的。 【参考方案9】:

客户端,客户端,客户端...插件,..JSApis.. 好.. 我们肯定知道这一点:所有浏览器在与 Apache 或 IIS 服务器通信时,实际上是在需要 https/SSL 握手过程时签署“something”。

例如,像这样的典型 Apache 配置:

SSLVerifyClient require
SSLVerifyDepth 10
SSLOptions +FakeBasicAuth +StdEnvVars +ExportCertData +OptRenegotiate

启动密码键盘弹出,用户必须插入智能卡密码才能继续。

好吧,我的想法是:为什么不转向服务器,并调整该行为,以便在握手开始时上传东西的字节流来签名?

【讨论】:

【参考方案10】:

我有一个设置,其中扫描智能卡读卡器以登录用户。 PC/SC 库在桌面上工作得很好。有人提到使用 Emscripten (https://github.com/kripken/emscripten) 编译器,将 c++ 编译成 JavaScript 代码。但这并没有很好地工作,因为 PC/SC 使用的某些功能仅在服务器端可用。 经过大量研究。我终于放弃了客户端解决方案,chrome web usb API也无法识别阅读器。 然后我决定尝试 signalR,并在连接到智能卡读卡器的 PC 上设置集线器,这种方法效果很好。

【讨论】:

以上是关于从通用浏览器访问智能卡的架构?或者:如何弥合从浏览器到 PC/SC 堆栈的差距?的主要内容,如果未能解决你的问题,请参考以下文章

从Web浏览器访问智能卡读卡器?

从浏览器访问 USB 智能卡数据

如何使用通用访问卡连接到 HTTPS 服务器

如何访问手机浏览器cookies

第2109期CodeSandbox是如何让npm上的模块直接在浏览器端运行的

如何在 Web 浏览器上使用智能卡