V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
realpg
V2EX  ›  程序员

Java 的证书信任问题求解。

  •  
  •   realpg ·
    realpg · 2016-02-03 18:30:28 +08:00 · 5494 次点击
    这是一个创建于 3224 天前的主题,其中的信息可能已经有所发展或是发生改变。
    近日服务器开始启动全线 HTTPS 加密。
    采用了 Let's Encrypt 的证书,根证书是 DST Root CA X3 。

    我的 Android 程序大多是用 Java 8 编译的,默认就信任这个根证书

    然后这两天改一个之前写的 Java 程序,然后发现 JDK7 并不信任 DST Root CA X3

    此程序界面是 Swing 的,原开发基于 JDK7 ,升级到 JDK8 , Swing 的 Error 满天飞,只得放弃升级。

    通信部分采用 Apache HttpClient , 我知道 HC 是可以在链接时指定服务器证书,添加证书信任的,但是 Let's Encrypt 的证书只给 3 个月有效期,而且内部通信有大量不同的域名不同的证书。总不能一个证书到期就重新编译一次程序,或者更新一次证书吧。

    所以我想有没有办法在 Runtime 阶段,添加一个指定 CA 的信任?毕竟 CA 证书有效期长且不变。随便 google 了一下,都是提前在客户端 jre 用命令行维护本地 keystore ,把 CA 加入本地 keystore ,这种对白痴用户太麻烦了。
    21 条回复    2016-02-06 03:38:48 +08:00
    yangff
        1
    yangff  
       2016-02-03 18:39:19 +08:00 via Android
    内部用的?自己签嘛。。
    wy315700
        2
    wy315700  
       2016-02-03 18:39:46 +08:00
    把根证书加进去
    realpg
        3
    realpg  
    OP
       2016-02-03 18:47:02 +08:00
    @wy315700
    我 google 的结果,根证书只能加入本地的 jre keystore ,用命令行指令

    在代码中添加证书信任, google 到的结果并测试通过的只有把服务器当前的证书加入,这个操作可以代入根证书而不是当次连接的证书么?
    wy315700
        4
    wy315700  
       2016-02-03 18:59:46 +08:00
    @realpg
    自己的 APP 的话 自己签一个 20 年的证书丢进去其实就行了,,
    realpg
        5
    realpg  
    OP
       2016-02-03 19:05:00 +08:00
    @wy315700
    不只是自己的 APP
    有 APP 有 web 有客户端 有触摸屏 还有公众访问
    realpg
        6
    realpg  
    OP
       2016-02-03 19:05:53 +08:00
    @wy315700
    使用 let's encrypt 是因为逗比客户不给钱买证书……
    现在被劫持的比较厉害
    wy315700
        7
    wy315700  
       2016-02-03 19:07:14 +08:00
    @realpg
    证书都不给买,,,
    ,,,活该被劫持
    realpg
        8
    realpg  
    OP
       2016-02-03 19:10:43 +08:00
    @wy315700
    对公的项目,事儿比较多,合同案值进第三方担保户里之后再申请一分钱都得去财政审批,没戏的。
    wy315700
        9
    wy315700  
       2016-02-03 19:15:58 +08:00
    @realpg 我一般给他们用 wosign ,,,
    7654
        10
    7654  
       2016-02-03 19:17:54 +08:00
    写个脚本自动做啊
    realpg
        11
    realpg  
    OP
       2016-02-03 19:32:10 +08:00
    @wy315700
    收费不收费再说,域名太多。一个个申请不起。
    Let's Encrypt 好歹是自动化的。
    项目早就做完了的,这是改,都找不到人了才折腾我头上帮忙。
    kaneg
        12
    kaneg  
       2016-02-03 22:01:46 +08:00
    如果客户端代码是自己写的,可以设置信任所有证书(当然安全自负了)。我以前用 apache 的 http client 做过,如果楼主需要我明天找找那段代码发给你
    realpg
        13
    realpg  
    OP
       2016-02-03 22:06:29 +08:00
    @kaneg
    谢谢,这个我会的。
    sslSF.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    但是不能这么写。
    我说了劫持很严重,这里面有问题,不敢这么信任

    我发这个贴就是想问问,有没有 runtime 临时信任一个根证书的方法
    vibbow
        14
    vibbow  
       2016-02-04 05:59:46 +08:00
    记得好像可以手动指定一个 keystore
    kaneg
        15
    kaneg  
       2016-02-04 22:02:37 +08:00
    @realpg
    你这个是是否校验 hostname ,如果证书链不被信任,还是无法通过的。你要有选择性的信任一个或多个证书链,可以参考以下方式:

    SSLSocketFactory mysf = new SSLSocketFactory(new TrustStrategy() {
    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    //这里检验你的证书链是否被信任
    return false;
    }
    });
    Scheme https = new Scheme("https", 443, mysf);
    client.getConnectionManager().getSchemeRegistry().register( https);
    realpg
        16
    realpg  
    OP
       2016-02-04 22:11:28 +08:00
    @kaneg
    sslSF.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    事实上,这段代码现在就存在于我的 JAVA 程序内,只要注释掉就报错,恢复程序就能正常使用。
    看 ALLOW_ALL_HOSTNAME_VERIFIER 是效验域名,实际上,加上这个,我这里就根本不检测证书链了直接无报错了
    wql
        17
    wql  
       2016-02-05 11:06:46 +08:00 via Android
    建议改用 Start SSL
    realpg
        18
    realpg  
    OP
       2016-02-05 11:20:15 +08:00
    @wql
    一百四十个域名…… StartSSL 上哪搞得过来……
    wql
        19
    wql  
       2016-02-05 11:25:26 +08:00 via Android
    @realpg 那只有收费证书一条路了,或者让他们 startSSL 买一个 59.99 或 199.99 刀的两年无限证书套餐。
    realpg
        20
    realpg  
    OP
       2016-02-05 11:32:57 +08:00
    @wql
    今年春节申请 200 块钱
    明年春节能给我就不错
    折腾个鬼啊……
    zhxq
        21
    zhxq  
       2016-02-06 03:38:48 +08:00
    说到 Java 证书吧 我就想起来当初两三年前我申请了个 StartSSL 个人某网站用 免费啊……
    然后因为用户主要在国内 所以接入了支付宝接口。
    死活接收不到支付宝的异步通知(将已收款信息写入数据库)
    无奈 咨询支付宝客服。
    支付宝客服告知 只支持 Java 1.5 的默认支持根证书列表……
    无奈,看到有 GeoTrust 的 RapidSSL 和 COMODO 的 PositiveSSL ,看前者贵( 7.99$/年,怕便宜的 PositiveSSL 不好用)然后买了一个,一切搞定。

    结果吧,新的一年又有某个新网站需要证书。知道 StartSSL 不好使了,于是乎先买了个 COMODO 的,感觉还挺便宜,三年也就 15$(对我来说在学校约等于一顿饭钱……资本主义国家的大学伤不起,食堂照样是学校垄断的……)
    结果还是不好使!!仍然接收不到异步通知!
    然后乖乖买了 PositiveSSL ……换上了之后,一切正常……

    坑爹的支付宝啊……
    @realpg 这事儿我在群里讲过 23333333333
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2849 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 12:07 · PVG 20:07 · LAX 04:07 · JFK 07:07
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.