You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TLSv1.3握手时检测缺失ALPN并终止握手?

TLSv1.3服务器强制ALPN验证的问题

核心需求

客户端发起TLSv1.3连接时,必须在Client Hello中携带包含特定条目的ALPN扩展;若未携带,需立即终止握手并发送TLS致命告警。

当前技术栈

使用C++结合Boost.Asio v1.83与OpenSSL 3.1搭建TLSv1.3服务器,核心异步操作依赖:

boost::asio::async_accept(...);
boost::asio::async_handshake(...);
boost::asio::async_read_some(...);
boost::asio::async_write(...);
boost::asio::async_shutdown(...);

现有ALPN验证逻辑(正常场景)

当客户端Client Hello包含ALPN扩展时,OpenSSL会触发自定义的alpn_select_cb回调,在此可完成ALPN校验,根据结果返回对应状态终止握手,该逻辑运行正常:

// 基于SSL_select_next_proto实现ALPN协商
int ServerSession::alpn_select_cb(SSL *ssl,
                               const unsigned char **out,
                               unsigned char *outlen,
                               const unsigned char *in,
                               unsigned int inlen,
                               void *arg)
{
    ServerSession* srvSession = static_cast<ServerSession*>(arg);
    int status = SSL_select_next_proto(const_cast<unsigned char **>(out),
                                       outlen,
                                       srvSession->m_serverAlpnList.data(),
                                       srvSession->m_serverAlpnList.size(),
                                       in,
                                       inlen);

    switch (status)
    {
        case OPENSSL_NPN_NEGOTIATED:  return SSL_TLSEXT_ERR_OK;             // ALPN协商成功
        case OPENSSL_NPN_UNSUPPORTED: return SSL_TLSEXT_ERR_NOACK;          // ALPN不被支持,返回告警
        case OPENSSL_NPN_NO_OVERLAP:  return SSL_TLSEXT_ERR_ALERT_FATAL;    // 无匹配ALPN,发送致命告警终止握手
    }
}

此场景下,Wireshark抓包显示服务器会正常发送致命告警,握手终止符合预期。

异常场景问题

当客户端未携带ALPN扩展时,OpenSSL不会触发alpn_select_cb回调,握手会完整完成,之后只能在服务器端主动关闭连接,抓包流程如下:

No.  Time       Source      Destination  Protocol  Length  Info
---------------------------------------------------------------------------------------------------------------------------
24   18.605087  127.0.0.1   127.0.0.5    TLSv1.3  273      Client Hello                          --> 客户端发起无ALPN的TLSv1.3连接
26   18.607975  127.0.0.5   127.0.0.1    TLSv1.3  1479     Server Hello, Change Cipher Spec, Application Data, Application Data, Application Data, Application Data
28   18.609183  127.0.0.1   127.0.0.5    TLSv1.3  124      Change Cipher Spec, Application Data
30   18.612081  127.0.0.5   127.0.0.1    TLSv1.3  554      Application Data, Application Data    --> 握手完成
32   18.613404  127.0.0.5   127.0.0.1    TLSv1.3  68       Application Data                      --> 服务器发送close_notify关闭连接
34   22.126810  127.0.0.1   127.0.0.5    TLSv1.3  71       Application Data                      --> 客户端同时尝试发送数据
36   22.127768  127.0.0.1   127.0.0.5    TLSv1.3  68       Application Data                      --> 客户端发送close_notify

这种流程不符合需求,需要在握手阶段直接终止并发送致命告警。

尝试的解决方案(无效)

尝试使用OpenSSL的消息回调cb_ssl_msg,在处理完Client Hello后检查是否有选中的ALPN,尝试终止握手:

// SSL消息回调,尝试在握手阶段检查ALPN
void ServerSession::cb_ssl_msg(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg)
{
    if (SSL_get_state(ssl) == TLS_ST_SW_SRVR_HELLO)
    {
        // 获取选中的ALPN
        unsigned int alpnLen;
        const unsigned char* alpnData;
        SSL_get0_alpn_selected(ssl, &alpnData, &alpnLen);

        if (alpnLen == 0) // 无ALPN被选中(客户端未发送ALPN扩展)
        {
            // 尝试关闭连接,但无法阻止握手完成
            ServerSession* srvSession = static_cast<ServerSession*>(arg);
            srvSession->m_socket.async_shutdown(boost::bind(&ServerSession::shutdownHandler, srvSession, boost::asio::placeholders::error));
            return; 
        }
    }
}

问题:async_shutdown无法中断正在进行的握手流程,握手仍会完成,无法实现需求。

求助

如何在检测到客户端未携带ALPN扩展时,立即终止TLS握手并发送致命告警,行为与ALPN不匹配时一致?


内容的提问来源于stack exchange,提问作者SBond

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 15:43:18