与 Web 服务的相互验证
目前,只要客户端使用 Web 浏览器访问网站,我就已经成功实现了相互身份验证安全性,因为浏览器会为您处理所有证书交换。现在,我需要创建一个安全接口,用户可以使用服务器所需的相互身份验证通过 HTTPS 访问 Web 服务。
首先,有人知道有什么资源可以帮助我解决这个问题吗?我找了好久却什么也没找到。任何人都可以给我关于如何解决这个问题的其他建议吗?
其次,我认为我最大的障碍是我对如何处理证书缺乏了解。如何协商接受服务器的密钥并向服务器提供我自己的密钥?这是在Java中。
Currently, I've been successful implementing Mutual Authentication security so long as the client accesses the website using a web browser, because browsers take care of all the certificate exchange for you. Now I need to create a secure interface with which users can access web services over HTTPS, using the mutual authentication required by the server.
First off, are there any resources anyone knows of that can help me with this? I've looked for quite some time and found nothing. Any other tips anyone can give me on how to go about this?
Secondly, I think my biggest roadblock is my lack of understanding of how to handle certificates. How do I negotiate accepting the server's key and presenting my own key to the server? This is in Java.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我花了很长时间在这方面,但我终于找到了一个实际有效的例子。它是基于 Glassfish 和 Netbeans 的,但我想如果您尝试过的话,您可以让它在其他环境(例如 Eclipse 和 Tomcat)中工作。
http://java.sun.com/webservices/reference /tutorials/wsit/doc/WSIT_Security9.html#wp162511
但我发现的问题是当您想使用自己的证书,而不是 glassfish 预安装的证书时。
注意:我不是安全专家。不要将其部署到生产环境!
为此,我使用 NetBeans 6.9、JDK 1.6、GlassFish 3.0.1 和 OpenSSL v1.0(我使用非官方 Win32 二进制文件)
在 GlassFish 管理中控制台,在 http 侦听器上启用安全性,勾选 SSL3、TLS 和客户端身份验证框,将证书昵称设置为服务器,将密钥存储设置为 config\keystore.jks,将信任存储设置为 config\keystore.jks,将信任算法设置为PKIX 并将最大证书长度保留为 5。
在 NetBeans 中,创建一个新的 Web 应用程序项目。在其中创建一个新的 Web 服务。
我的 Web 服务代码如下所示:
右键单击 Web 服务并选择编辑 Web 服务属性。勾选安全服务框并选择相互证书安全作为安全机制。单击“配置...”按钮并勾选“加密签名”框。现在取消选中“使用开发默认值”框,然后单击“密钥库”按钮。设置 server.jks 密钥库的位置并选择
server
别名。对信任库配置执行相同的操作(尽管您不必在此处选择别名)。将 client1.p12 客户端证书导入到浏览器中。将您的 Web 服务部署到 Glassfish。在浏览器中打开您的 Web 服务并通过 HTTPS 浏览到已部署的 WSDL。下载 WSDL 和任何其他架构。将任何引用的架构重命名为本地副本,以便在使用 WSDL2Java 时 NetBeans 不会使用任何远程资源。 (本段是因为您已将 WSDL 限制为具有已批准证书的客户端,但 NetBeans 无法远程获取它,因为它无权访问相关证书)。
创建一个新的 Java 项目。创建一个新的 Web 服务客户端。出现提示时,将 NetBeans 指向您保存的 WSDL 文件。导入 METRO2.0 库文件 (
C:\Program Files\Netbeans 6.9\enterprise\modules\ext\metr\webservices-*.jar
)。我的代码如下所示:将 webservices-api.jar 复制到 Java\jdk1.6\jre\lib\endorsed 目录中。
右键单击 Web 服务引用并选择编辑 Web 服务属性。将密钥库位置设置为 client1.jks 并将别名设置为
client1
。将信任库位置设置为 client1.jks 并将别名设置为server
。希望您现在可以运行您的客户端,并且您应该看到如下输出:
[电子邮件受保护],CN=Bob Smith, =某事, O=SomethingElse, L=AnyTown, ST=AnyState, C=US
I spent a long time on this but I finally found an example that actually works. It's Glassfish and Netbeans-based but I guess you could get it working in other environments (e.g. Eclipse and Tomcat) if you played around with it.
http://java.sun.com/webservices/reference/tutorials/wsit/doc/WSIT_Security9.html#wp162511
The problem I've found though is when you want to use your own certificates, not the ones that come pre-installed with glassfish.
Note: I am not a security expert. Don't deploy this to a production environment!
To do this I'm using NetBeans 6.9, JDK 1.6, GlassFish 3.0.1 and OpenSSL v1.0 (I'm using the unofficial Win32 binaries)
In the GlassFish admin console, enable Security on your http-listener, tick the SSL3, TLS and Client Authentication boxes, set the Certificate NickName to server, the Key Store to config\keystore.jks, the Trust Store to config\keystore.jks, the Trust Algorithm to PKIX and leave the Max Certificate Length at 5.
In NetBeans, create a new Web Application project. Within that, create a new Web Service.
My Web Service code looked like this:
Right click on the Web Service and select Edit Web Service Attributes. Tick the Secure Service box and select Mutual Certificates Security as the Security Mechanism. Click on the Configure... button and tick the Encrypt Signature box. Now untick the Use Development Defaults box and then click the Keystore button. Set the location of your server.jks keystore and select the
server
alias. Do the same for the Truststore configuration (although you don't have to select an alias here).Import the client1.p12 client certificate into your browser. Deploy your Web Service to Glassfish. Open up your web service in a browser and browse to the deployed WSDL via HTTPS. Download the WSDL and any other schemas. Rename any referenced schemas to local copies so that when you use WSDL2Java NetBeans won't use any remote resources. (This paragraph is because you've restricted your WSDL to clients with an approved certificate but NetBeans can't fetch it remotely because it doesn't have access to the certificate in question).
Create a new Java Project. Create a new Web Service Client. When prompted, point NetBeans to your saved WSDL file. Import the METRO2.0 library files (
C:\Program Files\Netbeans 6.9\enterprise\modules\ext\metr\webservices-*.jar
). My code looked like this:Copy webservices-api.jar into your Java\jdk1.6\jre\lib\endorsed directory.
Right-click on the Web Service reference and select Edit Web Service Attributes. Set the keystore location to client1.jks and set the alias to
client1
. Set the truststore location to client1.jks and set the alias toserver
.Hopefully you can now run your client and you should see output like so:
[email protected], CN=Bob Smith, OU=Something, O=SomethingElse, L=AnyTown, ST=AnyState, C=US
要在浏览器外部使用 SSL(又称双向 SSL)进行相互身份验证,您需要... 好吧,实际上,让我们首先看看单向 SSL 需要什么:
服务器密钥库包含服务器的(可能是自签名的)证书和私钥。服务器使用此存储来签署消息并将凭据返回给客户端。
客户端信任库包含服务器的(自签名)证书(从服务器密钥库提取到独立证书中,没有服务器私钥)。如果证书不是由受信任的 CA 签名的,而您在与 JRE 捆绑的信任库中已拥有该证书的证书,则需要执行此操作。此步骤允许创建信任链。
这样,您就可以实现单向 SSL(传统用例)。
要实现双向 SSL,您需要使此设置“对称”,因此我们需要添加:
客户端密钥库包含客户端(可能是自签名)证书和私钥。客户端使用此存储的目的与服务器密钥存储相同,即在 TLS 相互身份验证握手期间将客户端凭据发送到服务器。
服务器信任库包含客户端(自签名)独立证书(从客户端密钥库提取到独立证书,没有客户端私钥)。出于与前面提到的完全相同的原因,需要这样做。
一些资源可帮助您生成所有这些内容并实施最终解决方案:
For mutual authentication with SSL (aka two-way SSL) outside a browser, you'll need... Well, actually, let's see what you need for one-way SSL first:
The server keystore contains the server's (possibly self-signed) certificate and private key. This store is used by the server to sign messages and to return credentials to the client.
The client truststore contains the server's (self-signed) certificate (extracted from the server keystore into a stand-alone certificate, without the server private key). This is required if the certificate is not signed by a trusted CA for which you already have a certificate in the truststore bundled with the JRE. This step allows to create a chain of trust.
With this, you can implement one-way SSL (the traditional use case).
To implement two-way SSL, you need to make this setup "symmetric" so we'll need to add:
The client keystore contains the client's (possibly self-signed) certificate and private key. This store is used by the client for the same purpose than the server keystore i.e. to send client credentials to the server during the TLS mutual authentication handshake.
The server truststore contains the clients (self-signed) standalone certificates (extracted from the clients keystore into stand-alone certificates, without the clients private key). This is required for the exact same reasons as previously mentioned.
Some resources to help you to generate all this stuff and to implement the final solutions:
如果Web服务库使用标准
java.net.URL
类作为HTTP客户端,则可以设置一些系统属性 和双向身份验证将由内置的 HTTPS 支持处理。必要的属性是:
javax.net.ssl.trustStore
:包含根 CA 证书javax.net.ssl.keyStore
:包含客户端证书和私钥javax.net.ssl.keyStorePassword
:保护客户端私钥的密码这些设置将成为该进程所有 SSL 连接的默认设置。如果您想要更好的控制,您必须设置自己的
SSLContext
。您的 Web 服务运行时是否可以实现这一点取决于您选择的运行时。If the web service library uses the standard
java.net.URL
class as an HTTP client, you can set some system properties and the two-way authentication will be handled by the built-in HTTPS support.The necessary properties are:
javax.net.ssl.trustStore
: Contains root CA certificatesjavax.net.ssl.keyStore
: Contains client certificate and private keyjavax.net.ssl.keyStorePassword
: The password protecting the client's private keyThese settings become the defaults for all SSL connections by the process. If you want finer control, you have to set up your own
SSLContext
. Whether that's possible with your webservice runtime depends on which runtime you've chosen.此博客条目中给出了一个简单的秘诀。
但我认为真正的答案可能取决于您使用什么 Java API 来实现客户端 HTTP 交互。例如,看起来您会做一些事情一点不同的是使用JAX-RPC。
A simple recipe is given in this blog entry.
But I think the real answer may depend on what Java APIs you are using to implement your client-side HTTP interactions. For example, it looks like you would do things a bit differently using JAX-RPC.