排查https请求出现received fatal alert: internal_error的问题

这篇具有很好参考价值的文章主要介绍了排查https请求出现received fatal alert: internal_error的问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

背景

https网络协议交互

net.debug查看信息

Apache Httpclient与 Netty的http请求

 server_name

错误原因

修复方案

方案一

方案二


背景

通知某个商户时,突然出现大量的https握手失败了,出现received fatal alert: internal_error错误。商户sre那边当时将多个域名绑定在一个主机上,开了SNI(Server Name Indication)。

https网络协议交互

https的握手阶段图,如下:

description:internal error,Http,http

 对于每一步的解释如下:
步骤 1: 客户端通过发送 Client Hello 报文开始 SSL 通信。报文中包含客户端支持的 SSL 的指定版本、加密组件(Cipher Suite)列表(所使用的加密算法及密钥长度等)。

步骤 2: 服务器可进行 SSL 通信时,会以 Server Hello 报文作为应答。和客户端一样,在报文中包含 SSL 版本以及加密组件。服务器的加密组件内容是从接收到的客户端加密组件内筛选出来的。

步骤 3: 之后服务器发送 Certificate 报文。报文中包含公开密钥证书。

步骤 4: 最后服务器发送 Server Hello Done 报文通知客户端,最初阶段的SSL握手协商部分结束。

步骤 5: SSL 第一次握手结束之后,客户端以 Client Key Exchange 报文作为回应。报文中包含通信加密中使用的一种被称为 Pre-master secret 的随机密码串。该报文已用步骤 3 中的公开密钥进行加密。

步骤 6: 接着客户端继续发送 Change Cipher Spec 报文。该报文会提示服务器,在此报文之后的通信会采用 Pre-master secret 密钥加密。

步骤 7: 客户端发送 Finished 报文。该报文包含连接至今全部报文的整体校验值。这次握手协商是否能够成功,要以服务器是否能够正确解密该报文作为判定标准。

步骤 8: 服务器同样发送 Change Cipher Spec 报文。

步骤 9: 服务器同样发送 Finished 报文。

步骤 10: 服务器和客户端的 Finished 报文交换完毕之后,SSL 连接就算建立完成。当然,通信会受到 SSL 的保护。从此处开始进行应用层协议的通信,即发送 HTTP请求。

步骤 11: 应用层协议通信,即发送 HTTP 响应。

步骤 12: 最后由客户端断开连接。断开连接时,发送 close_notify 报文。上图做了一些省略,这步之后再发送 TCP FIN 报文来关闭与 TCP 的通信。在以上流程中,应用层发送数据时会附加一种叫做 MAC(Message Authentication Code)的报文摘要。MAC 能够查知报文是否遭到篡改,从而保护报文的完整性。

net.debug查看信息

了解了如上https的交互内容,那我们可以强行前进了。到底出现在了哪一部分?

在程序启动脚本中我们增加配置项:-djavax.net.debug=all

javax.net.debug=[ssl|all]

If ssl, turns on SSL debugging. If all, turns on SSL debugging with verbose messages.

开启了网络SSL的debugging,我们看到可客户端和服务端交互的更多细节,如下:

javax.net.ssl|FINE|3D|New I/O client worker #4-1|2022-01-23 15:53:10.703 CST|ClientHello.java:567|Produced ClientHello handshake message (
"ClientHello": {
  "client version"      : "TLSv1.2",
  "random"              : "F9 D9 EC 33 BD B7 E3 5F B2 0E F8 7B 5E AE 10 F0 FC 6F 89 5A B6 C6 F4 5C 17 EC A4 A6 85 60 CB 75",
  "session id"          : "",
  "cipher suites"       : "[TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(0xC02C), TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(0xC02B), TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(0xC030), TLS_RSA_WITH_AES_256_GCM_SHA384(0x009D), TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(0xC02E), TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(0xC032), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(0x009F), TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(0x00A3), TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(0xC02F), TLS_RSA_WITH_AES_128_GCM_SHA256(0x009C), TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(0xC02D), TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(0xC031), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(0x009E), TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(0x00A2), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(0xC024), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(0xC028), TLS_RSA_WITH_AES_256_CBC_SHA256(0x003D), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(0xC026), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(0xC02A), TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(0x006B), TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(0x006A), TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(0xC00A), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(0xC014), TLS_RSA_WITH_AES_256_CBC_SHA(0x0035), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(0xC005), TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(0xC00F), TLS_DHE_RSA_WITH_AES_256_CBC_SHA(0x0039), TLS_DHE_DSS_WITH_AES_256_CBC_SHA(0x0038), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(0xC023), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(0xC027), TLS_RSA_WITH_AES_128_CBC_SHA256(0x003C), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(0xC025), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(0xC029), TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(0x0067), TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(0x0040), TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(0xC009), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(0xC013), TLS_RSA_WITH_AES_128_CBC_SHA(0x002F), TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(0xC004), TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(0xC00E), TLS_DHE_RSA_WITH_AES_128_CBC_SHA(0x0033), TLS_DHE_DSS_WITH_AES_128_CBC_SHA(0x0032), TLS_EMPTY_RENEGOTIATION_INFO_SCSV(0x00FF)]",
  "compression methods" : "00",
  "extensions"          : [
    "supported_groups (10)": {
      "versions": [secp256r1, secp384r1, secp521r1, ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192]
    },
    "ec_point_formats (11)": {
      "formats": [uncompressed]
    },
    "signature_algorithms (13)": {
      "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
    },
    "signature_algorithms_cert (50)": {
      "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp521r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
    },
    "extended_master_secret (23)": {
      <empty>
    },
    "supported_versions (43)": {
      "versions": [TLSv1.2, TLSv1.1, TLSv1]
    }
  ]
}
)
javax.net.ssl|FINE|3D|New I/O client worker #4-1|2022-01-23 15:53:10.704 CST|SSLEngineOutputRecord.java:505|WRITE: TLS12 handshake, length = 250
javax.net.ssl|FINE|3D|New I/O client worker #4-1|2022-01-23 15:53:10.779 CST|SSLEngineOutputRecord.java:523|Raw write (
  0000: 16 03 03 00 FA 01 00 00   F6 03 03 F9 D9 EC 33 BD  ..............3.
  0010: B7 E3 5F B2 0E F8 7B 5E   AE 10 F0 FC 6F 89 5A B6  .._....^....o.Z.
  0020: C6 F4 5C 17 EC A4 A6 85   60 CB 75 00 00 56 C0 2C  ..\.....`.u..V.,
  0030: C0 2B C0 30 00 9D C0 2E   C0 32 00 9F 00 A3 C0 2F  .+.0.....2...../
  0040: 00 9C C0 2D C0 31 00 9E   00 A2 C0 24 C0 28 00 3D  ...-.1.....$.(.=
  0050: C0 26 C0 2A 00 6B 00 6A   C0 0A C0 14 00 35 C0 05  .&.*.k.j.....5..
  0060: C0 0F 00 39 00 38 C0 23   C0 27 00 3C C0 25 C0 29  ...9.8.#.'.<.%.)
  0070: 00 67 00 40 C0 09 C0 13   00 2F C0 04 C0 0E 00 33  .g.@...../.....3
  0080: 00 32 00 FF 01 00 00 77   00 0A 00 12 00 10 00 17  .2.....w........
  0090: 00 18 00 19 01 00 01 01   01 02 01 03 01 04 00 0B  ................
  00A0: 00 02 01 00 00 0D 00 22   00 20 04 03 05 03 06 03  .......". ......
  00B0: 08 04 08 05 08 06 08 09   08 0A 08 0B 04 01 05 01  ................
  00C0: 06 01 04 02 02 03 02 01   02 02 00 32 00 22 00 20  ...........2.". 
  00D0: 04 03 05 03 06 03 08 04   08 05 08 06 08 09 08 0A  ................
  00E0: 08 0B 04 01 05 01 06 01   04 02 02 03 02 01 02 02  ................
  00F0: 00 17 00 00 00 2B 00 07   06 03 03 03 02 03 01     .....+.........
)
javax.net.ssl|FINE|3D|New I/O client worker #4-1|2022-01-23 15:53:10.791 CST|SSLEngineInputRecord.java:177|Raw read (
  0000: 15 03 03 00 02 02 50                               ......P
)
javax.net.ssl|FINE|3D|New I/O client worker #4-1|2022-01-23 15:53:10.791 CST|SSLEngineInputRecord.java:214|READ: TLSv1.2 alert, length = 2
javax.net.ssl|FINE|3D|New I/O client worker #4-1|2022-01-23 15:53:10.792 CST|Alert.java:238|Received alert message (
"Alert": {
  "level"      : "fatal",
  "description": "internal_error"
}
)

Apache Httpclient与 Netty的http请求

Apache Httpclient 请求,建立SSL连接时握手正常

​
CloseableHttpClient httpClient = HttpClients.custom().build();

String url = "https://test.com";

HttpGet httpGet = new HttpGet(url);

HttpResponse response = httpClient.execute(httpGet);

​

Netty的http异步请求,建立SSL连接时握手失败

private final AsyncHttpClient asyncHttpClient = new AsyncHttpClient(new NettyAsyncHttpProvider(new AsyncHttpClientConfig.Builder().build()));

AsyncHttpClient.BoundRequestBuilder boundRequestBuilder = asyncHttpClient.preparePost(url);

ListenableFuture<Response> future = boundRequestBuilder.execute();

Response response = future.get(5, TimeUnit.SECONDS);

两者的错误日志相比较,Apache httpClient的请求中,扩展字段多了个server_name。
description:internal error,Http,http

 server_name

根据文档TLS扩展字段文档对server_name的描述,如下图片:
description:internal error,Http,http

 如果一台服务器托管多个域,那么很明显server_name是对于每个域的所有者来说,这是必要的,以确保满足他们的安全需要。
因为客户端可以显示不同的server_name。在应用程序协议中,应用程序服务器实现了这一点,必须检查这些名称是相同的,以确保客户端在应用程序协议中没有显示不同的名称。
 

错误原因

商户那边将多个域名绑定在一个主机上,开了SNI(Server Name Indication)。米币请求建立ssl连接时,没有传送上server name,而商户服务端检查了server_name扩展,则nginx不知道使用哪个server,直接抛出异常。
在Client Hello阶段,通过SNI扩展,将域名信息提前告诉服务器,服务器根据域名取得对应的证书返回给客户端已完成校验过程。

导致没有SNI的原因

  1. jdk版本过低,1.8的低版本和1.7或者1.6,均有可能,参考https://www.codetd.com/article/9814188
  2. httpclient,4.3.12这个版本之前的,会有这个bug
  3. 系统类设置了System.setProperty("jsse.enableSNIExtension", "false");

修复方案

方案一

继续使用 下面依赖的相关异步请求方法

<dependency>

<groupId>com.ning</groupId>

<artifactId>async-http-client</artifactId>

<version>1.7.14</version>

</dependency>

让请求携带上server_name, 创建特定的asyncHttpClient供该商户使用,其他商户依旧保持用之前的aysncHttpClient来调用。

SSLContext sslcontext = SSLContexts.createSystemDefault();

SSLEngine sslEngine = sslcontext.createSSLEngine("test.com", 443);
// 配置sslEngine在握手时使用客户端模式。
sslEngine.setUseClientMode(true);

AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder().setSSLEngineFactory(new SSLEngineFactory() {
    @Override
    public SSLEngine newSSLEngine() throws GeneralSecurityException {
        return sslEngine;
    }
});

AsyncHttpClient asyncHttpClient = new AsyncHttpClient(new NettyAsyncHttpProvider(builder.build()));

方案二

用apache的HttpAsyncClient来处理

maven依赖

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.4.1</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpasyncclient</artifactId>
    <version>4.1.4</version>
</dependency>

相关调用代码如下:文章来源地址https://www.toymoban.com/news/detail-622580.html

CloseableHttpAsyncClient client = HttpAsyncClients.custom()
        .setSSLHostnameVerifier(new NoopHostnameVerifier())
        .setDefaultRequestConfig(REQUEST_CONFIG)
        .build();
        
        
        
HttpPost httpPost = new HttpPost(url);
try {
    client.start();
    Future<HttpResponse> future = client.execute(httpPost, 
        new FutureCallback<HttpResponse> {
            @Override
            public void completed(HttpResponse result) {
            }
        
            @Override
            public void failed(Exception e) {
            }
        
            @Override
            public void cancelled() {
            }
    });
    HttpResponse response = future.get(5, TimeUnit.SECONDS);
} catch (Exception e) {
    logger.error("httpAysncPost exception, url: {}, message: {}", url, e.getMessage(), e);
}

注意:需要防止HttpAsyncClient资源没关闭引起的内存泄漏(吃过这方面的亏,哭唧唧)。诊断由 Apache HttpAsyncClient 引起的内存泄漏 - Think different - 生活的美好

批量执行完一部分请求后,需要进行client.close(); 不然线程会飙升到几万,然后服务会挂掉。  

方案三:

System.setProperty("jsse.enableSNIExtension", "true");

到了这里,关于排查https请求出现received fatal alert: internal_error的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • netty整合websocket支持自签证书出现netty websocket ssl Received fatal alert: certificate_unknown

    win+r cmd 生成自己jks文件,指向自己要生成jks的文件位置下,我直接生成到项目resources下 2.生成证书 3.迁移到行业标志 成功生成证书 将jks文件考入项目resources下 yaml配置: netty证书加载 这里我就只上关键代码了 不添加信任netty websocket ssl Received fatal alert: certificate_unknown。 错误原

    2024年02月02日
    浏览(40)
  • javax.net.ssl.SSLException: Received fatal alert: protocol_version

    双方ssl版本协议不一致,会爆出这个异常 解决方案:在HttpClientUtil类设置

    2024年02月07日
    浏览(36)
  • javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

    原因:从java8 Update31开始,由于SSL协议中的安全漏洞,默认情况下禁用SSL v3协议 。 排查过程:可使用如下代码,打印http请求协议过程 插曲:最初报错异常是javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate),按网上教程,找到jdk.tls.

    2024年02月11日
    浏览(41)
  • javax.net.ssl.SSLException: Received fatal alert: protocol_version解决

    今天在开发过程中,调用一个https的接口引发错误 在Java 1.8上,默认TLS协议是v1.2。在Java 1.6和1.7上,默认是已废弃的TLS1.0,由于此项目使用的是jdk1.6,因此引发错误。 解决方法1: 在发起请求前面设置 TLSv1.2 协议 解决方法2: 在发起请求前忽略ssl认证: 工具类: 使用方法:

    2024年02月11日
    浏览(52)
  • Caused by: javax.net.ssl.SSLException: Received fatal alert: protocol_version

        at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1575)     at com.alibaba.druid.pool.DruidDataSource.init(DruidDataSource.java:854)     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)     

    2024年02月06日
    浏览(53)
  • Java(92):javax.net.ssl.SSLException:Received fatal alert: protocol_version的解决方法

    2022-05-19 15:11:56 [ERROR] com.cipherxxx.utils.HttpsClientUtils - javax.net.ssl.SSLException: Received fatal alert: protocol_version 在Java 1.8上,默认TLS协议是v1.2。在Java 1.6和1.7上,默认是已废弃的TLS1.0,由于此项目使用的是jdk1.6,因此引发错误。 ------------------------------------------------------------- 服务端的

    2024年02月16日
    浏览(33)
  • nginx反向代理https域名时,请求报错502问题排查

    微信公众号:运维开发故事,作者:冬子先生 一. 现象 在使用nginx反向代理后端服务器的时候,因为配置的是域名,导致HTTPS 请求转发失败,报 SSL 错误,js 报 502 img img 二. 排查过程 1、查看nginx日志,发现报502,但是本地curl upstream中的后端域名是可以正常通的 img 2、查看后端

    2024年02月11日
    浏览(41)
  • git clone出现 fatal: unable to access ‘https://github.com/...‘的解决办法

    发生这种情况是因为代理是在git中配置的。既然它是https代理(而不是http)git config http.proxy和git config --global http.proxy也无济于事。 1、看看你的git配置 git config --global -l 如果你没有任何与https代理相关的内容,例如https_proxy = …问题不在这里。 如果您有与https代理相关的内容,

    2024年02月08日
    浏览(64)
  • Git clone 出现 fatal: unable to access ‘https://github.com/n....‘ 的解决办法(亲自有效)

    如图所示,当我想要github上面的文件clone到本地的时候出现了这样的错误。  发生这样的错误是因为 Git 无法验证 GitHub 的 SSL 证书。这可能是由于本地的证书问题或网络问题导致的。 在 git clone 命令后面加上 -c 参数,并配置 Git 忽略 SSL 证书检查,如下所示: 这样就可以绕过

    2024年02月11日
    浏览(57)
  • Git链接出现报错:fatal: unable to access ‘https://github.com/.../‘: Failed to connect to github

    在链接GIT或者克隆过程中git出现报错如下: 可能原因为DNS 解析出现问题,需要刷新下DNS即可 cmd 窗口输入 ipconfig/flushdns ,清除缓存后再重新进行 git 操作即可

    2024年02月08日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包