假设我正在编写一个 Web 应用程序,目标是技术倾向、安全意识强的用户,这些用户在生成和使用 GPG 或 SSH 密钥时没有问题。
是否可以使用所述密钥以安全的方式对 Web 应用程序进行身份验证,以取代传统的基于密码的身份验证?
如果可能,身份验证步骤将是什么样的?对于 Ruby、.NET、Java 或 Python 等流行语言和平台,这种想法是否有已知的良好实现?
如果不可能,原因是什么?访问 GPG 钥匙串或 SSH 密钥文件的 Web 浏览器是否存在限制?
假设我正在编写一个 Web 应用程序,目标是技术倾向、安全意识强的用户,这些用户在生成和使用 GPG 或 SSH 密钥时没有问题。
是否可以使用所述密钥以安全的方式对 Web 应用程序进行身份验证,以取代传统的基于密码的身份验证?
如果可能,身份验证步骤将是什么样的?对于 Ruby、.NET、Java 或 Python 等流行语言和平台,这种想法是否有已知的良好实现?
如果不可能,原因是什么?访问 GPG 钥匙串或 SSH 密钥文件的 Web 浏览器是否存在限制?
对于 Web 应用程序,主要问题是网站代码(浏览器中的 Javascript)不能随意读写文件。好吧,总的来说,这更像是一个问题,但这意味着 Javascript 代码将无法访问 SSH 或 PGP 私钥。
有些事情可以做,这取决于您的用户对技术的了解程度,以及他们将容忍多少手动操作:
您可以使用本地安装的浏览器扩展来代表网站访问 SSH 或 PGP 私钥。最好,一些用户控制是可取的:我们真的不希望浏览器仅仅因为网站说要签名就签名。
服务器可以充当 SSH 服务器,并要求客户端使用 SSH 和基于密钥的客户端身份验证进行连接。用户将以“SOCKS 代理”模式运行 SSH。Web 服务器本身只会监听localhost
,即除非通过这样的本地代理,否则无法访问。在这种模式下,Web 服务器甚至可以是 HTTP,而不是 HTTPS;这真的是用 SSH 代替 SSL。在服务器端,跟踪用户应该使用mod_ident或类似的东西(SSH 服务器知道客户端是谁,但信息必须转发到 HTTP 服务器;幸运的是,这是在同一台机器上,所以 Unix 级别可以使用身份)。
该网站可以将“挑战”显示为具有随机内容的可下载文件。用户获得该文件,使用 GnuPG 对其进行签名,然后将(ASCII 铠装)输出粘贴到网站上的文本字段中。服务器验证签名,并接受它作为对用户的身份验证(前提是服务器已经知道用户的公钥)。笨重,但有效。
上述基于邮件的变体可能是可取的,因为 PGP 实现通常嵌入在电子邮件软件中,并且还因为它打开了不必信任外部根 CA 的可能性。它看起来像这样:
用户使用 HTTPS 连接到 Web 服务器。服务器使用自签名证书。浏览器会发出警告(“红色可怕警告”),但允许用户继续。
在站点中,用户输入他的姓名。然后服务器向用户发送一封签名和加密的电子邮件(带有 PGP);签名的电子邮件包含随机数,以及服务器 SSL 证书指纹的副本。随机数也打印在网站本身上。
用户验证服务器电子邮件上的 PGP 签名,然后检查指纹是否与他在浏览器中看到的指纹匹配;这让用户相信他看到的是真正的服务器证书,因此没有持续的中间人攻击。(这是我们用基于 PGP 的验证替换 X.509 CA 系统的地方。)
用户还验证网站上显示的随机数是否与他在电子邮件中看到的随机数相匹配(这很重要)。
用户通过发回邮件的内容来回复邮件,这次用他自己的 PGP 私钥签名,并用服务器的公钥加密。服务器验证该电子邮件,从而知道目标用户确实收到了 nonce 值。
服务器将 nonce 值作为 cookie 发送到用户的浏览器。这允许浏览而不用进一步的身份验证来纠缠用户。由服务器决定将 cookie 作为有效身份验证令牌接受多长时间。
在上述方案中,重要的是要注意,通过发回他的电子邮件响应,用户实际上是在授权服务器假设返回随机数(包括在电子邮件中)的人确实是用户本人。这就是为什么手动检查 nonce 是否与网页上显示的内容匹配很重要的原因。
是否可以使用 OpenPGP/SSH 密钥对以安全的方式对 Web 应用程序进行身份验证,以取代传统的基于密码的身份验证?
是的。这是很有可能。
如果可能,身份验证步骤将是什么样的?对于 Ruby、.NET、Java 或 Python 等流行语言和平台,这种想法是否有已知的良好实现?
下一个问题见我的回答。
如果不可能,原因是什么?访问 GPG 钥匙串或 SSH 密钥文件的 Web 浏览器是否存在限制?
在 Web 应用程序中处理 SSH 和 OpenPGP 密钥可以使用第三方库(尤其是 C 或 Java 库,因为它们具有丰富的生态),但您将错过利用最常见的现有解决方案 - SSL/TLS。
最好的办法是让用户生成由您的服务器签名的 X509 客户端证书来验证自己 - 因为这样您的 Web 应用程序可以简单地依赖 Web 容器(Catalina Tomcat、ApacheD、IIS 等)为您的服务器执行无缝加密和身份验证应用。
在底层,OpenPGP 密钥具有与 X509 证书相同的 RSA 指数,因此openssl
可以将 GPG/PGP 密钥转换为自签名* X509 证书等工具;SSH 密钥也一样。
* 从 X509 的角度来看,OpenPGP 信任网络符合“自签名”的条件,因为据我所知,X509v3 不能拥有多根信任链。
现有答案提供了很好的建议 - 改用浏览器中的 SSL 堆栈。
但是,实际上可以完全按照您的意愿去做 - 使用 JavaScript 加密。
JavaScript http://openpgpjs.org/中有一个 OpenPGP 实现我不能保证它的质量。
此外,HTML5 JavaScript 也可以访问本地文件,例如http://www.html5rocks.com/en/tutorials/file/dndfiles/
我认为这与其说是一个实用的系统,不如说是一种好奇心。