discuz网站同步,手机h5建网站,台州网站设计公司,html在线编程网站因此#xff0c;我有一个幼稚的想法#xff0c;即除了证书有效性检查#xff08;在Java中#xff09;之外#xff0c;将证书透明性验证作为每个请求的一部分也很容易。 牺牲了整个周末的一半时间#xff0c;我可以证明这并不是一件小事。 但是#xff0c; 证书透明性是… 因此我有一个幼稚的想法即除了证书有效性检查在Java中之外将证书透明性验证作为每个请求的一部分也很容易。 牺牲了整个周末的一半时间我可以证明这并不是一件小事。 但是 证书透明性是什么 简而言之–它是世界上所有TLS证书的公开日志即使SSL已过时仍称为SSL证书。 您可以检查该日志中是否发布了日志如果没有发布则有些可疑因为CA必须将其所有已颁发的证书推送到日志中。 还有其他用例例如为您的域注册新证书的通知以检测可能被劫持的DNS管理面板或CA Facebook免费提供了这样的工具 。 我想做的是前者–使来自Java应用程序的每个请求在证书透明性日志中验证对方的证书。 似乎这不是开箱即用的如果可以我找不到它。 在一次有关JEP 244的讨论中 似乎讨论了与证书透明性相关的TLS扩展但是我找不到它是否是最终支持。 我开始认为您可以简单地获取证书并通过证书的指纹检查其是否包含在日志中。 这太容易了–允许通过哈希检查的日志但是它不是证书的指纹而是签名的证书时间戳–由日志在包含之前发布的签名。 引用CT RFC SCT签名证书时间戳记是日志将证书合并到Merkle树中的承诺 merkle树是一种非常酷的数据结构它通过提供比整个日志短得多的“包含证明”使外部参与者确信该日志中包含某些内容从而节省了大量带宽。 实际上merkle树的凉爽是为什么我首先对证书透明性感兴趣的原因因为我们在我当前的面向日志的公司中使用merkle树 因此为了检查是否包含 您必须以某种方式获取SCT。 最初我认为使用Certificate Transparency Java库是可能的但事实并非如此。 拥有它之后您可以使用客户端在日志中对其进行检查但是获取它比较困难。 注意对于服务器端验证可以通过HTTP查询日志 但是浏览器可以使用DNS查询来保留用户的匿名性。 可以通过三种方式来获取SCT具体取决于服务器和/或日志和/或CA选择支持的方式SCT可以包含在证书中也可以在TLS握手期间作为TLS扩展提供。 也可以在握手期间再次包含在TLS装订响应中。 不幸的是我检查的少数证书中没有存储SCT因此我必须进入较低级别并调试TLS握手。 我启用了TLS hadnshake 冗长的输出 瞧瞧-那里什么都没有。 Google确实将SCT作为TLS扩展包括在内根据Qualys但是Java输出未对此进行任何说明。 幸运的是Google发布了Conscrypt –一种基于Java安全提供程序的Google的OpenSSL分支。 事情开始变得一团糟……但我还是去了包括Conscrypt并将其注册为安全提供程序。 我必须使用Conscrypt TrustManager进行连接已使用JDK中的所有受信任证书初始化 KeyStore trustStore KeyStore.getInstance(JKS);
trustStore.load(new FileInputStream(System.getenv(JAVA_HOME) /lib/security/cacerts), changeit.toCharArray());
ctx.init(null,new TrustManager[] {new TrustManagerImpl(trustStore, null, null, null, logStore, null, new StrictCTPolicy())}, new SecureRandom());URL url new URL(https://google.com);
HttpsURLConnection conn (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ctx.getSocketFactory());
conn.connect();
conn.getInputStream();
conn.disconnect(); 当然它最初并不起作用因为Conscrypt不提供一些所需的核心接口CTLogStore和CTPolicy类的实现。 实际上CTLogStore是保存有关所有已知日志信息的重要位我仍然觉得将“日志提供程序”简称为“ log”很奇怪但这是公认的术语。 有一个以JSON形式存在的已知日志列表 这很酷只是花了我一段时间在外部帮助下才能弄清楚这些公钥的确切含义。 它们是什么-RSAECC 它们如何编码 您在RFC和文档中都找不到。 在这里可以看到它是“ SubjectPublicKeyInfo ASN.1结构的DER编码”。 啊。 BouncyCastle进行营救。 我与BouncyCastle的恋爱关系深深。 我讨厌它的直观性和API的复杂性但是我喜欢它几乎具有您可能需要的所有与密码相关的东西。 在花费一些时间试图弄清楚如何将公共密钥转换为PublicKey对象之后我发现使用PublicKeyFactory.createKey(Base64.getDecoder().decode(base64Key)); 为您提供使用任何算法的参数-它可以返回椭圆曲线关键参数或RSA关键参数。 您只需要将它们包装在另一个类中然后将它们传递到另一个工厂典型的BouncyCastle就可以拥有公共密钥。 当然现在Google的Conscrypt不再起作用因为在转换之后publicKey的编码版本与原始字节不相同因此日志ID计算错误。 但是我经过一番思考后解决了这个问题最后它奏效了–查询了证书透明性日志并证明该证书有效并且正确地包含在日志中。 整个代码可以在这里找到 。 是的它使用了几个安全提供程序一些奇怪的BouncyCastle API和Google提供程序中缺少的一些简单实现。 可能会缓存已知的证书以便不执行对日志的重复调用但这超出了我的实验范围。 证书透明性似乎是当今互联网的核心内容。 但是它是如此晦涩且难以使用。 为什么列表中的公钥类型没有记录它们至少应在公钥旁边放置一个OID因为事实证明并非所有日志都使用椭圆曲线-其中两个使用RSA。 也许有一个很好的解释但是为什么在日志中包括SCT而不是证书的指纹 为什么不然后要求将SCT包括在证书中而无需将服务器和客户端进行其他配置而不是将其包括在TLS握手中而TLS握手则需要升级呢 据我所知由于数以百万计的让我们对证书进行加密因此证书透明性计划现在面临可伸缩性问题。 每个日志提供者都应将整个日志提供给所有请求它的人。 解决这不是一件容易的事并且朝着这个方向努力了但目前尚无明显的解决方案。 最后如果Java没有简便的方法并且所有密码库都可用我想知道其他语言的情况如何。 他们支持证书透明性还是需要升级 也许我们都很好因为浏览器支持它但是浏览器并不是发出HTTP请求的唯一对象。 API调用是一个巨大的用例如果可以对其进行劫持则所造成的损害甚至可能比被骗的单个用户还要大。 因此我认为应该在两件事上付出更多的努力 1.改进RFC和2.改进编程生态系统。 我希望这篇文章至少能有所贡献。 翻译自: https://www.javacodegeeks.com/2019/01/certificate-transparency-verification-java.html