相互问题

HTTPS协议是用于确保我们的连接安全的公认标准。 理解此协议的工作原理不是问题,并且从2000年起可以使用相应的RFC文档

尽管HTTPS的使用如此广泛,但您仍然可以找到一种无需不必要的复杂性就无法处理此协议的软件。 不幸的是,在使用该语言进行相互身份验证的过程中遇到了问题,这一点都不会让我感到惊讶。 它是Java

HTTPS如何工作?

在描述实现过程中遇到的问题之前,我将描述相互认证的工作原理。 HTTPS协议使用TLS / SSL协议来保护连接。 TLS / SSL协议定义了身份验证握手,该握手允许以安全方式将任何客户端与服务器连接。 在握手过程中,执行以下步骤:

  • 客户端发送消息以启动连接。
  • 服务器将其证书发送给客户端。
  • 客户端使用由可信机构颁发的证书来验证证书。
  • 服务器发送对客户端证书的请求。
  • 客户端将其证书发送到服务器。
  • 服务器验证客户端的证书。
  • 服务器和客户端交换在数据加密期间使用的主密钥。
  • 建立连接。

我们和队友一起尝试用Java实现HTTPS客户端。 结合我们对TLS / SSL握手的了解以及对curl进行手动测试的经验,我们假设实现客户端只需要三个文件: 一个客户端的证书一个客户端的私钥一个用于验证服务器证书的受信任证书

哦,我们这么认为是多么错误。

Java –问题,解决方案以及为什么如此困难

由于每天使用相互身份验证是很不常见的,因此我们要求世界上最好的消息来源提供少量帮助。 初看Google叔叔提供的结果并没有揭示实现背后的复杂性,但是每次点击结果都使我们找到了越来越混乱的解决方案(其中一些来自90年代)。 更糟的是,我们不得不使用Apache HttpComponents来实现我们的连接,但是大多数提议的解决方案都基于纯Java库。

来自互联网的知识使我们能够确定:

  • Java不能直接使用任何证书或私钥(例如curl
  • Java需要单独的文件( Java Keystores ),其中可以包含原始证书和密钥。
  • 我们需要一个受信任的密钥库,其中包含每个HTTPS连接的服务器证书验证所需的证书。
  • 我们需要一个密钥密钥库,其中包含客户端的证书和客户端的私钥以进行相互认证。

首先,我们必须创建受信任的密钥库。 我们使用keytool命令使用证书创建了密钥库:

$ keytool -import -alias trusted_certificate -keystore trusted.jks -file trusted.crt

我们将证书trusted.crt存储在密钥库文件trusted.jks中,别名为trusted_certificate 。 在执行此命令期间,要求我们输入此密钥库的密码。 我们稍后使用此密码来访问密钥库文件。

要创建密钥库,需要执行一些其他步骤。 在大多数情况下,您可能会从公司获得两个文件,这些文件会颁发客户的证书。 第一个文件将是pem格式的客户证书。 该证书将被发送到服务器。 第二个文件是客户端的私钥(也是pem格式),在握手期间使用该私钥来确认您是客户端证书的所有者。

不幸的是, Java仅支持PKCS12格式。 因此,我们必须将我们的证书和私钥转换为PKCS12格式。 我们可以使用OpenSSL做到这一点。

$ openssl pkcs12 -export \
    -in client.crt \
    -inkey client.key \
    -out key.p12 \
    -name client

我们从文件client.crtclient.key生成了文件key.p12 。 再次需要输入密码。 该密码用于保护私钥。

通过将PKCS12导入新的密钥库,我们可以从PKCS12格式的文件中生成另一个密钥库:

$ keytool -importkeystore \
    -destkeystore key.jks \
    -deststorepass <<keystore_password>> \
    -destkeypass <<key_password_in_keystore>> \
    -alias client \
    -srckeystore key.p12 \
    -srcstoretype PKCS12 \
    -srcstorepass <<original_password_of_PKCS12_file>>

这个命令看起来有点复杂,但是解密起来却很容易。 在命令的开头,我们声明名为key.jks的新密钥库的参数。 我们定义了密钥库的密码和此密钥库将使用的私钥的密码。 我们还将私钥分配给密钥库中的某些别名(在本例中为client )。 接下来,我们指定源文件( key.p12 ),该文件的格式和原始密码。

使用trusted.jkskey.jks我们已经准备好进行编码。 在第一步中,我们必须描述我们如何使用密钥库。

File trustedKeystoreFile = new File("trusted.jks");
File keystoreFile = new File("key.jks");

SSLContext sslcontext = SSLContexts.custom()
    .loadTrustMaterial(trustedKeystoreFile, 
                    "<<trusted_keystore_password>>".toCharArray())
    .loadKeyMaterial(keystoreFile, 
                    "<<keystore_password>>".toCharArray(), 
                    "<<original_password_of_PKCS12_file>>".toCharArray())
    .build();

SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1.2"},
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());

我们获取了密钥库文件,并构建了SSL上下文。 接下来,我们创建了套接字工厂,该套接字工厂为请求提供了正确的HTTPS连接。

最后,我们可以从Java调用端点:

try (CloseableHttpClient httpclient = HttpClients.custom()
        .setSSLSocketFactory(sslsf)
        .build()) {

    HttpGet httpGet = new HttpGet("https://ourserver.com/our/endpoint");

    try (CloseableHttpResponse response = httpclient.execute(httGet)) {
        HttpEntity entity = response.getEntity();
        System.out.println(response.getStatusLine());
        EntityUtils.consume(entity);
    }
}

做完了 在创建了两个额外的文件(密钥库)之后,这些文件等效于我们的原始证书和私钥,我们使用Java实现了相互身份验证 。 用Java实现HTTPS连接也许有一定道理,但是现在这只是一个头痛的事情。

翻译自: https://www.javacodegeeks.com/2016/03/mutual-problems-2.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值