如何从通用浏览器访问智能卡?或者说:如何将浏览器与PC / SC堆栈连接起来?

61
有哪些现有的客户端架构可通过PC/SC智能卡读卡器(ISO 7816-3,ISO 14443)从通用浏览器(通过http(s)连接到服务器)访问本地智能卡,最好使用Javascript,并且对终端用户的最小安装困扰?服务器至少需要能够向智能卡发出其选择的APDU(或者也许将其中一部分委托给它生成的客户端代码)。我假设在客户端可以获得完整的PC/SC堆栈,包括智能卡读卡器。这至少在Windows自XP以来、现代的OS X和Unix上是一个合理的假设。
到目前为止,我已经确定了以下选项:
一些自定义的ActiveX。这是我现有应用程序所使用的(我们在公司内部开发),一旦客户获得安装ActiveX的许可,使用IE进行部署非常容易,但它不符合“通用浏览器”的要求。
更新:ActiveX主要由已停用的IE支持,包括IE11;但Edge不支持。
一些使用Netscape插件API的PC/SC浏览器扩展,似乎是上述方法的平稳扩展。我找到的唯一现成的一个是SConnect (webarchive)。它不再推广(更新:尽管仍然在至少一个应用程序中活跃维护和使用),它的API 文档(webarchive)不再正式提供,并且它与特定智能卡和读卡器供应商有着紧密联系。这个原则可能很好,但为每个平台制作这样的插件需要大量的工作。
更新:NPAPI被许多浏览器放弃,包括Chrome和Firefox。
一个Java小程序,运行在Oracle的JVM(1.)6或更高版本之上,带有javax.smartcardio。从功能角度来看,这很好,有很好的文档,我可以忍受一些已知的错误,但我担心Java作为浏览器扩展的接受度会出现不可抵制的下降趋势。
[更新,2021年2月]:这个答案在2015年认为WebUSB API是一个有前途的解决方案,然后在2019年报告说不能工作或被放弃。我在那里发了一个问题there
任何其他想法吗? 此外:是否有办法防止不良服务器滥用浏览器具有的任何PC/SC接口(例如,提供3个错误的PIN码以封锁卡,只是出于恶意;或者进行更邪恶的事情)?

2
你看过这个网址吗 https://dev59.com/9Goy5IYBdhLWcg3wEJ9n - flup
@flup:感谢您的指引。看起来那里列出的解决方案都是面向PKCS#11的,而我所针对的智能卡(一种用于公共交通支付的混合卡)并非如此。 - fgrieu
Java Applet 是 NPAPI 插件解决方案的一个子集。 - Vanuan
3
既然Chrome不再支持NPAPI,或许需要更新一下了... - Seva Alekseyev
在我的情况下,我将SignalR Hub安装为Windows服务在连接到读取器的PC上,这对我来说效果很好。 - Syler
我有一个基本问题 - 服务器是否要求客户端在响应中提供证书,还是浏览器在第一次请求时就发送它?我试图将其与SPNEGO相关联,在此情况下,浏览器仅在从服务器接收到401 / Negotiate响应后才发送kerberos / ntlm票证。这里是否有类似的情况?如果是,是否有任何特定的HTTP响应代码/标头告诉浏览器获取客户端证书? - Bhushan Karmarkar
11个回答

28
事实上,浏览器不能与(加密的)智能卡进行除建立SSL之外的其他用途的通信。
您需要额外的代码由浏览器执行以访问智能卡。
有数十个定制和专有插件(使用您提到的所有三个选项)用于各种目的(签名可能是最受欢迎的),因为至少在欧洲,没有标准或普遍接受的方式,我相信其他地方也是如此。
创建、分发和维护您自己的插件将是一场轰动,因为浏览器每月发布一次左右,每个新版本都会更改沙盒化ir UI技巧,因此您可能需要经常调整代码。
而且您可能希望具备GUI功能,至少可以请求用户访问卡或其中某些功能的权限。
要创建一个多平台、多浏览器插件,可以使用firebreath之类的东西。
个人而言,我并不认为将PC/SC暴露在Web上有任何好处。PC/SC本质上是一种相当低级的协议,当你暴露它时,你可能会像希望“网络应用程序只属于我并且它们表现良好”一样暴露块级访问你的磁盘(这应该回答了你的“Also”)。同时,像SConnect这样的薄层包装是最容易创建的,可以提供类似于javascript plugin.sendAPDU()样式的代码(或者只需包装所有PC/SC API,并让javascript调用者处理与本机PC/SC API使用案例中相同级别的细节)。
为此目的创建插件通常是由当前的急需驱动的。
解决未来(移动设备等)则是另一回事,在那里,诸如W3C webcrypto和OpenMobile API之类的东西可能最终会创建出一些将客户端密钥容器暴露给Web应用程序的东西。如果您的智能卡目标是加密,我的建议是避免使用PC/SC,而使用平台服务(Windows上的CryptoAPI,OSX上的Keychain,Linux上的PKCS#11)。
任何设计都有需求。如果您想使用密钥而不是任意APDU,则适用于所有内容。如果您的要求是发送任意APDU,请创建一个插件并继续使用它。

1
对于使用通用浏览器插件框架的想法表示赞同,之前不知道FireBreath。是的,我需要通用APDU访问,因为应用程序需要支持各种智能卡,并且这些智能卡的范围还在不断扩大。此外,拥有专用的签名插件并不比拥有APDU插件更安全:如果智能卡用于签名,我们不希望恶意服务器使用插件来签署任何内容。 - fgrieu
1
当然不是。这样的签名插件通常会处理(可疑的)法律警告(“您即将签署具有法律约束力等等”)和WYSIWYS之类的方案(至少比仅仅签署某些东西要好)。这里的重点是插件提供了一组固定的高级功能,本地安装的代码(可以签名等等)负责某些保护整个模型,并请求用户允许用户可以理解的事情。 - Martin Paljak
1
“你想签署什么吗?”是/否。如果您想在example.com网站上签署“blablabla”,请输入您的PIN码。用户理解弹出PIN输入对话框是不好的;用户理解在随机网页上弹出窗口也是不好的等等。而“Android风格”的“您是否允许网站X访问您的智能卡”则打开了巨大的可能性窗口,假设用户可以逐个批准每个APDU是...奇怪的。 - Martin Paljak
哦,顺便说一下,一个基于服务器的“允许访问”问题(就像现代浏览器中的cookie、JS和其他所有内容一样)是当今必不可少的。但是一个流氓服务器(最好称之为专门的攻击者)有其他方法来运行JS。 - Martin Paljak
1
SSL并不是典型的智能卡任务,因为所涉及的密钥是新协商的,仅用于一个会话,并且不需要长期高度保护的秘密(如私钥)。我认为用户身份验证是最重要的任务。 - guidot
@guidot 由于我们正在讨论智能卡,我也指的是使用来自卡片的客户端证书(和密钥)进行SSL身份验证。 - Martin Paljak

26

更新(8/2016):正在讨论一个名为WebUSB API的Web API。您可以在Chrome v54+中使用它

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

所以新答案是YES!

OSI类似的架构堆栈是:

2019年更新: 正如@vlp所评论的那样,由于某些牵强附会的原因,Chrome决定阻止智能卡的WebUSB功能,因此它似乎不再起作用。


注意: 谷歌宣布他们将在2017年放弃Chrome应用程序

之前的回答:

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

然后通过其符合CCID标准的接口访问智能卡读卡器。

它不是跨浏览器的,但是可编程且跨平台的JavaScript。

无论如何,现代浏览器不再支持Netscape插件API(NPAPI)。而Java小程序也正在被浏览器供应商淘汰。


1
除非您正在运行ChromeOS,否则我怀疑您无法通过chrome.usb API连接到智能卡读卡器。如果操作系统有处理设备的驱动程序(这对于典型的CCID读卡器来说是情况),那么chrome.usb将被拒绝访问该设备(请参见您提供的链接中的“注意事项”部分)。此外,在JavaScript中编写CCID和T=0/T=1协议栈肯定会很麻烦。 - dim
1
@dim。你可以做到。我已经做到了。适用于Windows 7-10。 - Supersharp
1
真的吗?!我无法想象。但如果你这么说,那么我值得一试。如果它真的有效,我会每天祝福你。我现在就开始点赞了。但我仍然怀疑...操作系统如何同时使外围设备可用于chrome.usb API和PC/SC驱动程序? - dim
4
不幸的是,Chrome 开始在 WebUSB API 中阻止智能卡读取器(详见例如这里这里)。 - vlp
1
2022年现在还有希望吗? - holydragon
显示剩余3条评论

7
我刚刚发布了一个解决这个问题的测试版插件。 这个测试代码可以在这里找到:https://github.com/ubinity/webpcsc-firebreath
这个插件基于firebreath框架,并已在Linux / WinXP / Win7下通过Fireofx和Chrome进行了测试。提供源代码和扩展包。
基本思路是提供一个PCSLite API访问,然后在其上开发更友好的JS-api。
此插件正在积极开发中,欢迎发送任何报告和请求。

4
有另一个与@cslashm提出的类似浏览器插件,可在http://github.com/cardid/WebCard找到。它也是开源的,并且可以像原始问题所需的 “最小安装麻烦” 一样安装。您可以访问http://plugin.cardid.org查看使用示例。
WebCard在Windows的IE 8至11、Chrome和Firefox以及Mac OS X的Chrome和Safari中经过测试。由于它只是PC/SC的包装器,在Mac OS X中需要安装来自http://smartcardservices.macosforge.com的SmartCard服务。

它也可以在Linux上运行吗? - gdm
该插件使用http://firebreath.org框架,该框架也支持Linux,但我尚未尝试为该平台构建。@giuseppe您是否有构建工具来尝试一下? - Adrian
1
嗨。你说的构建工具是指gcc和其他类似的工具吗?是的,我有它...你能给我指点一下吗? - gdm
@giuseppe,你可以查看http://www.firebreath.org/display/documentation/Building+on+Linux。一旦你在Linux上构建了一个Firebreath插件的示例,你就可以尝试构建WebCard的Linux版本。 - Adrian
你能告诉我文档在哪里吗?我不明白如何发送命令到智能卡以读取其证书... - gdm

4
对于您的第一个问题,我没有太大希望:如果您只需要很小一部分智能卡功能(例如签署电子邮件或PDF),那么您可以使用一些现成的软件(如PKCS),最好由智能卡公司维护;如果您需要更广泛的功能,则需要自己投入相当大的精力。当然,PCSC是选择的起点。
至少对于您的“另外一个问题”,有一些希望。
1)请注意,某些规范(例如ICAO/German BSI TR-3110)要求使用一种方法,在错误计数器达到1后,PIN不会被锁定,但会使用相当长的时间来回复。必须使用不同的命令启用最终尝试,否则将不进行进一步的比较和错误计数器调整。
2)通过要求安全消息保护验证命令,简单地实现保护。敏感应用程序为所有内容使用安全消息,因此第一步是协商会话密钥,该密钥随后应用于所有后续命令和响应。其效果将是在进行比较或修改错误计数器之前,由于MAC不正确而拒绝命令。

你没有回答如何弥合浏览器和PC/SC之间的差距的问题。也许我可以重新表达我的问题。此外:1)很好,我不知道那个。2)安全消息需要一个秘密;这防止了在其传统用例中使用PIN码:离线,无SAM POST。 - fgrieu

2

你能举个使用API的例子吗? - holydragon
@holydragon 这个API有几个通用的教程,不同的串口读卡器使用不同的协议。我已经为ACR1281S串口读卡器编写了一个工作的PoC,但很遗憾我不能分享它。 - vlp

2

如果在客户机上安装桥接守护程序/服务是可接受/可行的话,那么您可以编写本地桥接服务(例如使用 Python / pyscard),通过 REST 接口公开智能卡,并在浏览器中使用 JavaScript 介于本地服务(门面)和远程服务器 API 之间进行中介。


2
由于Chrome和Firefox即将停止支持NPAPI插件,因此没有安全的解决方案可用于维护智能卡读取的会话,除非您的卡证书支持相互SSL。我回答了类似问题的来源,可能会有所帮助。

1
谈到Chrome,现在您可以使用Google提供的智能卡连接器应用程序,该应用程序捆绑了PC/SC-Lite端口和通用CCID驱动程序。
该应用程序本身通过chrome.usb API工作,这是之前评论者提到的。
因此,开发人员现在可以仅编写在PC/SC API顶部工作的部分,而无需重写整个堆栈(从最低级别-原始USB开始)-该API由Connector应用程序公开。

1
正如在另一个答案中所指出的那样,谷歌宣布他们将在2017年放弃Chrome应用程序。因此,基于智能卡连接器应用程序或/和chrome.usb API的解决方案已经很短暂了。 - fgrieu
1
@fgrieu,智能卡连接器应用程序仍在维护并运行良好(自您的评论以来已经过去了5年)。Chrome应用程序的弃用已经多次延迟,即使在弃用后,我们也将迁移到不同的技术。 - Max

1
Clients, clients, clients... plugins, JSApis... 好的... 我们知道这一点:所有浏览器在与Apache或IIS服务器通信时,当需要进行https/SSL握手过程时,实际上都会签署“something”。
例如,像这样的典型Apache配置:
SSLVerifyClient require
SSLVerifyDepth 10
SSLOptions +FakeBasicAuth +StdEnvVars +ExportCertData +OptRenegotiate

启动PIN码输入框,用户必须插入智能卡PIN码才能继续。
我的想法是:为什么不将转向服务器的行为进行调整,以便在握手启动时上传要签署的内容字节流呢?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接