ssl连接过程中session复用失败的原因

时间:2019-01-10
本文章向大家介绍ssl连接过程中session复用失败的原因,主要包括ssl连接过程中session复用失败的原因使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

最近在开发过程中,遇到了一次https访问失败的场景,场景描述:

在chrome浏览器访问我们的https后端时,如果长时间没有更新请求的话,再次刷新该请求将会返回连接失败的错误,必须重启浏览器方能正常访问,在 safri浏览器下不会出现这个问题,chrome浏览器端显示的错误码为ERR_SSL_VERSION_INTERFERENCE,在网上检索该错误的通用解决方法(https://merabheja.com/solved-fix-err_ssl_version_interference-chrome-error/)均无法解决该问题,通过检查后端日志看到,ssh handshake的错误码为336433429,无论是在百度还是谷歌上检索该错误码的结果都非常少,无法提供有效信息,谷歌上有人提过类似问题(https://sourceforge.net/p/asio/mailman/message/26696960/),大概意思是说这个只有在重复使用相同的客户端证书才会出现这种情况,后来在git上找到了类似问题的解法,鉴于这个问题解答方法很少,特记录如下,方便后人。

首先说下错误码的含义:

336433429,错误码的含义是session id context uninitialized 

解决方法:

在server端(只需要在server端)设置session id context即可,代码如下

    static int context_id = 1;
    if (!SSL_CTX_set_session_id_context(ctx->native_handle(), (const unsigned char*)&context_id, sizeof(context_id))) {
        LOG_ERROR("SSL set session id context failed");
        return false;
    }

也就是调用了下openssl的SSL_CTX_set_session_id_context方法,这个方法的介绍如下:

https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_session_id_context.html

为了方便及加深自己的记忆,翻译如下:

SSL_CTX_set_session_id_context

命名

SSL_CTX_set_session_id_context, SSL_set_session_id_context - 设置context,在这个context中session可以被复用(server side only)

语法

 #include <openssl/ssl.h>

 int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx,
                                    unsigned int sid_ctx_len);
 int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx,
                                unsigned int sid_ctx_len);

描述

SSL_CTX_set_session_id_context() 为ctx设置了一个context --- sid_ctx,长度为sid_ctx_len,这样的话在sid_ctx中一个session可以被复用

SSL_set_session_id_context() 为ssl对象设置一个context -- sid_ctx,长度为sid_ctx_len,这样的话在sid_ctx中一个session可以被复用

注释

sessions都是从一个确定的context生成的,当使用i2d_SSL_SESSION/d2i_SSL_SESSION来导入导出session是可能的,但是当导入一个从其他context(比如另一个应用)生成的session将可能带来冲突。这样的话,每个应用都必须设置自己的session id context ---- sid_ctx,这是用来区分context,它是被保存在导出的session里吗。sid_ctx可以是任意的给定长度的二进制数据,所以它可以是应用名、主机名或者服务的名字。

这个session id context成为了session的一部分,这个context是由ssl/tls server服务端来设置的,所以这两个api只会在server端有用。openssl 客户端会在复用session的时候检查这个session id context。

sid_ctx的最大长度限制为SSL_MAX_SSL_SESSION_ID_LENGTH。

警告

如果session id context没有在ssl/tls server端设置并且客户端证书被使用了,那么存储的session将不能够被复用,否则将会引发一个fatal error,并且握手将会失败。

当复用session的时候server返回给openssl client返回一个不同的session id context,那么一个error将会触发,握手将会失败。openssl server将总是会返回正确的session id context,这是因为在复用session时候自己检查session id context。

返回值

0表示失败,1表示操作成功

 

综上,我觉得上面的问题原因是chrome缓存了ssl的session,在刷新过程中复用了这些session,但是服务端没有设置session id context,导致握手失败连接不成功,服务端设置后一切正常了,待确认。。。。