使用用户证书以Web表单签名数据的最佳方式

我们有一个C#Web应用程序,用户可以使用存储在浏览器中的数字证书进行连接。

从我们看到的示例中,一旦启用SSL,validation其身份将很容易,因为我们可以使用Request.ClientCertificate访问证书中的字段来检查用户的名称。

但是,我们还要求签署用户发送的数据(一些简单的字段和一个二进制文件),这样我们就可以毫无疑问地certificate哪个用户输入了我们数据库中的每个记录。

我们的第一个想法是创建一个小文本签名,包括字段(如果可能的话,还有文件的md5),并使用证书的私钥加密它,但是……

据我所知,我们无法访问证书的私钥来签署数据,我不知道是否有任何方法可以在浏览器中对字段进行签名,或者我们除了使用Java之外别无选择小程序。 如果是后者,我们将如何做到(我们可以使用任何开源小程序吗?如果我们自己创建一个小程序会更好吗?)

当然,如果有任何方法可以使用我们可以从用户证书访问的数据“签署”服务器中收到的字段,那会更好。 但如果没有,任何关于解决问题的最佳方法的信息将不胜感激。

我建议你使用java-applet。 这种方法适用于所有浏览器。 我们在项目中使用它。 要签署用户数据,您需要使用JCA API( http://download.oracle.com/javase/1.4.2/docs/guide/security/CryptoSpec.html#Signature )。 此外,您还需要解决从java访问Windows证书存储区的问题。

你可以用这种方式解决它:

KeyStore keystore = KeyStore.getInstance("Windows-MY", "SunMSCAPI"); keystore.load(null, null); HashMap userPublicKeys = new HashMap(); Enumeration aliasesEnum = keystore.aliases(); if (!aliasesEnum.hasMoreElements()) throw new Exception("No certificate!"); // list through windows personal store while (aliasesEnum.hasMoreElements()) { String alias = aliasesEnum.nextElement(); boolean isKey = keystore.isKeyEntry(alias); if (isKey) { BASE64Encoder encoder = new BASE64Encoder(); encoder.encode(keystore.getCertificate(alias).getEncoded()); userPublicKeys.put(alias, encoder.encode(keystore.getCertificate(alias).getEncoded())); System.out.println("Entry alias: " + alias); } // sign PrivateKey privateKey = (PrivateKey) keystore.getKey(alias,null); Provider provider = keystore.getProvider(); // data to signed byte[] data ="test data".getBytes(); // Signing the data Signature sig = Signature.getInstance("SHA1withRSA", provider); sig.initSign(privateKey); sig.update(data); byte[] signature = sig.sign(); System.out.println(ByteArrayToFromHexDigits.bytesToHexString(signature).toUpperCase()); } 

如果这是一个足够强大的“签名”,您将需要询问您的法律部门,但每个字段的发布都会让服务器记录字段值以及客户端证书握手时的证书指纹。 是的,这是“可伪造的”,因为任何有指纹知识的人都可以在数据库中创建假记录,但是如果有适当的数据库安全性,你可以删除该攻击向量并记录谁发布了什么(因为你不能伪造指纹SSL的双向认证中的客户端证书)

我们无法访问证书的私钥来签署数据,

如果不是这样,那么服务器可以记住证书本身并在使用其他服务时将其用作真正的客户端。

即完全无效使用客户端证书来validation客户端。

我不知道是否有办法在浏览器中签名字段,

如何用合适的客户端标签(例如JavaScript,浏览器)提出这个问题,以获得合适的受众。 (我确信它可以使用浏览器扩展或ActiveX对象完成 – 但这会产生自己的问题。)

有一个JavaScript方法crypto.signText,它允许使用客户端证书对任意文本进行签名。 这是一些文档和签名的表单示例 。 看来,目前只有Firefox支持它。

对于IE,有CAPICOM ActiveX对象(可从MS下载)。 以下是其用法示例。

我不确定在不同的浏览器和操作系统版本中是否支持这些function,您可能需要检查它是否适合您的配置。