使用 Apache httpclient 进行 https

2024-04-03

我已经在 tomcat 中启用了 https 并拥有用于服务器身份验证的自签名证书。我使用 Apache httpClient 创建了一个 http 客户端。我已经设置了一个加载服务器证书的信任管理器。 http客户端可以毫无问题地与服务器连接。为了查看发生了什么,我启用了调试:

System.setProperty("javax.net.debug", "ssl");

我看到了以下我完全无法理解的内容:

***
adding as trusted cert:
  Subject: CN=Me, OU=MyHouse, O=Home, L=X, ST=X, C=BB
  Issuer:  CN=Me, OU=MyHouse, O=Home, L=X, ST=X, C=BB
  Algorithm: RSA; Serial number: 0x4d72356b
  Valid from Sat Mar 05 15:06:51 EET 2011 until Fri Jun 03 16:06:51 EEST 2011 

我的证书将显示并添加到信任库(如我所见)。然后:

trigger seeding of SecureRandom
done seeding SecureRandom

这是我没有得到的调试跟踪部分:

trustStore is: C:\Program Files\Java\jre6\lib\security\cacerts
trustStore type is : jks
trustStore provider is : 
init truststore
adding as trusted cert:
  Subject: CN=SwissSign Platinum CA - G2, O=SwissSign AG, C=CH
  Issuer:  CN=SwissSign Platinum CA - G2, O=SwissSign AG, C=CH
  Algorithm: RSA; Serial number: 0x4eb200670c035d4f
  Valid from Wed Oct 25 11:36:00 EEST 2006 until Sat Oct 25 11:36:00 EEST 2036

adding as trusted cert:
  Subject: [email protected] /cdn-cgi/l/email-protection, CN=http://www.valicert.com/, OU=ValiCert Class 1 Policy Validation Authority, O="ValiCert, Inc.", L=ValiCert Validation Network
  Issuer:  [email protected] /cdn-cgi/l/email-protection, CN=http://www.valicert.com/, OU=ValiCert Class 1 Policy Validation Authority, O="ValiCert, Inc.", L=ValiCert Validation Network
  Algorithm: RSA; Serial number: 0x1
  Valid from Sat Jun 26 01:23:48 EEST 1999 until Wed Jun 26 01:23:48 EEST 2019

看来它也使用默认的java信任存储!我的问题是为什么会发生这种情况?

在我的代码中,我明确指定要使用的特定信任存储(通过信任存储管理器)。我原本期望只使用这个。看来我的信任库和java的默认值都被使用了。这是它应该如何工作的吗?

UPDATE:
我尝试了以下方法:

System.out.println("TMF No:"+tmf.getTrustManagers().length);
System.out.println("Class is "+tmf.getTrustManagers()[0].getClass().getName());  

我认为我应该看到 2 个信任管理器,因为有 2 个密钥库(我的和 java 的默认值似乎已被使用)。
但结果只有1个信托经理!

TMF No:1
Class is com.sun.net.ssl.internal.ssl.X509TrustManagerImpl  

UPDATE2:正如您在下面的代码中看到的,我指定了我的密钥库。我的期望是只应该使用这个(而不是这个and也有证书)

    HttpClient client = new DefaultHttpClient();
    SSLContext sslContext = SSLContext.getInstance("TLS");      

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore ks = KeyStore.getInstance("JKS");
    File trustFile = new File("clientTrustStore.jks");
    ks.load(new FileInputStream(trustFile), null);
    tmf.init(ks);
    sslContext.init(null, tmf.getTrustManagers(),null);  
    SSLSocketFactory sf = new SSLSocketFactory(sslContext); 
    sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    Scheme scheme = new Scheme("https", sf, 443);
    client.getConnectionManager().getSchemeRegistry().register(scheme);
    httpGet = new HttpGet("https://localhost:8443/myApp");
    HttpResponse httpResponse = client.execute(httpGet);

对我来说没有意义。


我将这个测试应用程序放在一起,使用 Apache HttpClient 包中的 HTTP 测试框架重现该问题:

ClassLoader cl = HCTest.class.getClassLoader();
URL url = cl.getResource("test.keystore");
KeyStore keystore  = KeyStore.getInstance("jks");
char[] pwd = "nopassword".toCharArray();
keystore.load(url.openStream(), pwd);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(
        TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keystore);
TrustManager[] tm = tmf.getTrustManagers();

KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
        KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keystore, pwd);
KeyManager[] km = kmfactory.getKeyManagers();

SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(km, tm, null);

LocalTestServer localServer = new LocalTestServer(sslcontext);
localServer.registerDefaultHandlers();

localServer.start();
try {

    DefaultHttpClient httpclient = new DefaultHttpClient();
    TrustStrategy trustStrategy = new TrustStrategy() {

        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            for (X509Certificate cert: chain) {
                System.err.println(cert);
            }
            return false;
        }

    };

    SSLSocketFactory sslsf = new SSLSocketFactory("TLS", null, null, keystore, null,
            trustStrategy, new AllowAllHostnameVerifier());
    Scheme https = new Scheme("https", 443, sslsf);
    httpclient.getConnectionManager().getSchemeRegistry().register(https);

    InetSocketAddress address = localServer.getServiceAddress();
    HttpHost target1 = new HttpHost(address.getHostName(), address.getPort(), "https");
    HttpGet httpget1 = new HttpGet("/random/100");
    HttpResponse response1 = httpclient.execute(target1, httpget1);
    System.err.println(response1.getStatusLine());
    HttpEntity entity1 = response1.getEntity();
    EntityUtils.consume(entity1);
    HttpHost target2 = new HttpHost("www.verisign.com", 443, "https");
    HttpGet httpget2 = new HttpGet("/");
    HttpResponse response2 = httpclient.execute(target2, httpget2);
    System.err.println(response2.getStatusLine());
    HttpEntity entity2 = response2.getEntity();
    EntityUtils.consume(entity2);
} finally {
    localServer.stop();
}

尽管出于某种原因,Sun 的 JSSE 实现似乎总是从默认信任存储中读取信任材料,但它似乎并未添加到 SSL 上下文中,也不会影响 SSL 握手期间的信任验证过程。

这是测试应用程序的输出。如您所见,第一个请求成功,而第二个请求失败,因为连接到www.verisign.com因不可信而被拒绝。

[
[
  Version: V1
  Subject: CN=Simple Test Http Server, OU=Jakarta HttpClient Project, O=Apache Software Foundation, L=Unknown, ST=Unknown, C=Unknown
  Signature Algorithm: SHA1withDSA, OID = 1.2.840.10040.4.3

  Key:  Sun DSA Public Key
    Parameters:DSA
    p:     fd7f5381 1d751229 52df4a9c 2eece4e7 f611b752 3cef4400 c31e3f80 b6512669
    455d4022 51fb593d 8d58fabf c5f5ba30 f6cb9b55 6cd7813b 801d346f f26660b7
    6b9950a5 a49f9fe8 047b1022 c24fbba9 d7feb7c6 1bf83b57 e7c6a8a6 150f04fb
    83f6d3c5 1ec30235 54135a16 9132f675 f3ae2b61 d72aeff2 2203199d d14801c7
    q:     9760508f 15230bcc b292b982 a2eb840b f0581cf5
    g:     f7e1a085 d69b3dde cbbcab5c 36b857b9 7994afbb fa3aea82 f9574c0b 3d078267
    5159578e bad4594f e6710710 8180b449 167123e8 4c281613 b7cf0932 8cc8a6e1
    3c167a8b 547c8d28 e0a3ae1e 2bb3a675 916ea37f 0bfa2135 62f1fb62 7a01243b
    cca4f1be a8519089 a883dfe1 5ae59f06 928b665e 807b5525 64014c3b fecf492a

  y:
    f0cc639f 702fd3b1 03fa8fa6 676c3756 ea505448 23cd1147 fdfa2d7f 662f7c59
    a02ddc1a fd76673e 25210344 cebbc0e7 6250fff1 a814a59f 30ff5c7e c4f186d8
    f0fd346c 29ea270d b054c040 c74a9fc0 55a7020f eacf9f66 a0d86d04 4f4d23de
    7f1d681f 45c4c674 5762b71b 808ded17 05b74baf 8de3c4ab 2ef662e3 053af09e

  Validity: [From: Sat Dec 11 14:48:35 CET 2004,
               To: Tue Dec 09 14:48:35 CET 2014]
  Issuer: CN=Simple Test Http Server, OU=Jakarta HttpClient Project, O=Apache Software Foundation, L=Unknown, ST=Unknown, C=Unknown
  SerialNumber: [    41bafab3]

]
  Algorithm: [SHA1withDSA]
  Signature:
0000: 30 2D 02 15 00 85 BE 6B   D0 91 EF 34 72 05 FF 1A  0-.....k...4r...
0010: DB F6 DE BF 92 53 9B 14   27 02 14 37 8D E8 CB AC  .....S..'..7....
0020: 4E 6C 93 F2 1F 7D 20 A1   2D 6F 80 5F 58 AE 33     Nl.... .-o._X.3

]
HTTP/1.1 200 OK
[
[
  Version: V3
  Subject: CN=www.verisign.com, OU=" Production Security Services", O="VeriSign, Inc.", STREET=487 East Middlefield Road, L=Mountain View, ST=California, OID.2.5.4.17=94043, C=US, SERIALNUMBER=2497886, OID.2.5.4.15="V1.0, Clause 5.(b)", OID.1.3.6.1.4.1.311.60.2.1.2=Delaware, OID.1.3.6.1.4.1.311.60.2.1.3=US
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 2048 bits
  modulus: 20699622354183393041832954221256409980425015218949582822286196083815087464214375375678538878841956356687753084333860738385445545061253653910861690581771234068858443439641948884498053425403458465980515883570440998475638309355278206558031134532548167239684215445939526428677429035048018486881592078320341210422026566944903775926801017506416629554190534665876551381066249522794321313235316733139718653035476771717662585319643139144923795822646805045585537550376512087897918635167815735560529881178122744633480557211052246428978388768010050150525266771462988042507883304193993556759733514505590387262811565107773578140271
  public exponent: 65537
  Validity: [From: Wed May 26 02:00:00 CEST 2010,
               To: Sat May 26 01:59:59 CEST 2012]
  Issuer: CN=VeriSign Class 3 Extended Validation SSL SGC CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network, O="VeriSign, Inc.", C=US
  SerialNumber: [    53d2bef9 24a7245e 83ca01e4 6caa2477]

Certificate Extensions: 10
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
  [accessMethod: 1.3.6.1.5.5.7.48.1
   accessLocation: URIName: http://EVIntl-ocsp.verisign.com, accessMethod: 1.3.6.1.5.5.7.48.2
   accessLocation: URIName: http://EVIntl-aia.verisign.com/EVIntl2006.cer]
]

...

]
Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:345)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
    at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:446)
...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Apache httpclient 进行 https 的相关文章

随机推荐

  • jQuery 修剪不会删除?

    如何修剪字符串中的所有空格 即使它们是由不间断空格引起的 nbsp 例如 var foo trim p nbsp foo nbsp p text foo 的值为 foo 代替 foo UPDATE所以 问题不在于 jQuery 的修剪功能
  • 在redis队列中调用django自定义管理命令

    是否可以将 django 管理命令作为 redis 中的排队作业调用 这对我来说失败了 from django core management import call command from rq import Queue queue Q
  • 如何编写一个程序,将整数序列读入数组并计算数组中所有元素的交替和?

    编写一个程序 将整数序列读入数组 并计算数组中所有元素的交替和 例如 如果程序使用输入数据执行 1 4 9 16 9 7 4 9 11 然后它计算 1 4 9 16 9 7 4 9 11 2 到目前为止我有以下代码 import java
  • C++ 构造函数的模板特化

    我有一个模板类 A 和两个 typedef A 和 A 如何重写 A 的构造函数 以下不起作用 template
  • 无法将 GridView 绑定到 LINQ to SQL 结果

    好吧 我确实是 LINQ 的新手 上周我已经阅读了有关 LINQ 的所有内容 我只是在玩玩 试图遵循我找到的一些示例 事实上 来自 Scott Gu 的关于该主题的 PDF 但我完全不知所措 有人可以告诉我为什么当我使用下面的代码将 Gri
  • 如何将 TestNG 测试输出文件夹配置在 Maven 目标文件夹内?

    Folks 我是 TestNG 的新手 我正在尝试使用 Maven Surefire 插件 和 Eclipse 当我的测试由 Maven 运行时 其报告会按预期放在 target surefire reports 上 但是当由 Eclips
  • 在 Android 上如何从位图获取 RGB 值?

    我想在 Android 上获取位图的 RGB 值 但目前还无法做到这一点 我的目标是获取位图每个像素的 RGB 值 Android 或其他有什么特定的功能吗 我也想知道我需要colorMatrix 功能 这对我的项目非常重要 这可能有点晚了
  • Xamarin.Forms;在屏幕上显示设备上我的 SIM 卡的电话号码

    我想在屏幕上显示我设备的电话号码 在 Xamarin Android 中 代码可以正常工作 但我想使用 Xamarin Forms 中的代码 我已经搜索过 但没有找到任何结果 Android Telephony TelephonyManag
  • 下划线作为 JavaScript 变量?

    In 这个帖子 https stackoverflow com questions 3504499 how to copy table row with clone in jquery and create new unique ids f
  • CMAKE_*_OUTPUT_DIRECTORY 的正确使用

    前言 我是only谈论本地编译 not关于安装项目 这是因为我还没有对适当的研究进行足够的研究install使用 CMake 但如果我的问题直接涉及到 请插话install实践 似乎有可能 TL DR 你在什么场景下not想要将所有正在构建
  • React 中未使用 ES6 fetch 定义 fetch 方法

    我在我的第一个 React js 应用程序中遇到了 fetch 函数的问题 这是我的项目的结构 hello world app components main jsx node modules public build js index h
  • 编写 HTML 电子邮件时的最佳实践和注意事项 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我开发网站已有十多年了 但很快发现我的许多网络开发习惯在为电子邮件客户端开发时毫无用处 这让我非常沮丧 所以我想问一个问题 对于像我这样不时为
  • React-Leaflet:将地图控制组件放置在地图之外?

    这是我的其他问题的更普遍的版本 从反应传单中的地图中删除缩放控制 https stackoverflow com questions 59432189 remove zoom control from map in react leafle
  • Python 3 和 Tkinter 有缺陷且缓慢

    因此 几个月前 我制作了一个小型 GUI 用于在我正在运行的角色扮演活动中处理 NPC 从那以后我就再也没有接触过 只是现在我需要它 明天 事实上 我有一些奇怪的错误 加载 GUI 似乎工作正常 但是当我开始按下按钮时 麻烦就开始了 起初
  • Git 合并并修复具有两个分支的混合空间和选项卡

    我已经经历了一些类似的 SOQ 但没有找到适合这种情况的适当解决方案 我注意到在许多文件中 用于缩进的制表符和空格混杂在一起 目前我们遵循的编码标准使用 4 个空格作为制表符 虽然这个问题应该在发生时就得到解决 但我现在需要考虑它 并希望修
  • 广播接收器在 Android 6.0 Marshmallow 中不工作

    我刚刚将我的 Nexus 5 更新到 android 6 到目前为止我的应用程序工作正常 但现在广播接收器无法工作 新版本有什么变化吗 这是我尝试过的代码 它适用于以前的版本 但不适用于棉花糖 安卓清单
  • 如何识别模板参数是否为 std::complex?

    如何判断模板参数是否为std complex 我想要一个支持所有数据类型 如 float double int 等 的通用方法 我知道使用 std is same 我可以专门检查给定类型 例如 std complex
  • 使用 System.Text.Json 自定义可选属性的 JSON 序列化器

    我正在尝试实现一个处理两者的 JSON 序列化机制null和缺失的 JSON 值 以便能够在需要时执行部分更新 这样当值缺失时它不会触及数据库中的字段 但当值显式设置为时它会清除它 null 我创建了一个从 Roslyn 复制的自定义结构O
  • 从另一个 Jenkins 管道构建一个 Jenkins 管道时覆盖默认参数

    目标 当我从另一个 Jenkins 脚本构建时 用 false 覆盖 Jenkins 布尔参数默认值 true 我已经检查了其他 StackOverflow 项目中建议的可能答案 似乎没有什么匹配的 然而 他们确实向我展示了如何在从另一个
  • 使用 Apache httpclient 进行 https

    我已经在 tomcat 中启用了 https 并拥有用于服务器身份验证的自签名证书 我使用 Apache httpClient 创建了一个 http 客户端 我已经设置了一个加载服务器证书的信任管理器 http客户端可以毫无问题地与服务器连