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

如何阻止HTTP请求访问KTor HTTPS服务器及处理Netty TLS异常?

KTor HTTPS服务器拦截HTTP请求及抑制TLS握手失败日志方案

我用KTor搭建的HTTPS服务器和Android客户端交互正常,但总有机器人往HTTPS端口发HTTP请求,导致Netty抛出NotSslRecordException并打印大量WARN级别的堆栈日志,示例日志如下:

23-11-2023 22:51:39.249 [eventLoopGroupProxy-3-1] [WARN ] i.n.h.s.ApplicationProtocolNegotiationHandler - [id: 0x58e8b7a9, L:0.0.0.0/0.0.0.0:1234 ! R:/321.567.33.980:18765] TLS handshake failed:
io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: 474554202f7465737420485454502f312e310d0a486f73743a207777772e636172726f74736f6674676174657761792e636f6d3a343234320d0a436f6e6e656374696f6e3a206b6565702d616c6976650d0a43616368652d436f6e74726f6c3a206d61782d6167653d300d0a557067726164652d496e7365637572652d52657175657374733a20310d0a557365722d4167656e743a204d6f7a696c6c612f352e30202857696e646f7773204e542031302e303b2057696e36343b2078363429204170706c655765624b69742f3533372e333620284b48544d4c2c206c696b65204765636b6f29204368726f6d652f3131392e302e302e30205361666172692f3533372e33360d0a4163636570743a20746578742f68746d6c2c6170706c69636174696f6e2f7868746d6c2b786d6c2c6170706c69636174696f6e2f786d6c3b713d302e392c696d6167652f617669662c696d6167652f776562702c696d6167652f61706e672c2a2f2a3b713d302e382c6170706c69636174696f6e2f7369676e65642d65786368616e67653b763d62333b713d302e370d0a4163636570742d456e636f64696e673a20677a69702c206465666c6174650d0a4163636570742d4c616e67756167653a20656e2d55532c656e3b713d302e390d0a0d0a
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1225)
...(省略后续堆栈)


一、在Netty层面拦截HTTP请求

直接在Netty的ChannelPipeline最前面加一个处理器,识别HTTP请求的特征并直接关闭连接,避免走到TLS握手环节触发异常。

在KTor中可以通过自定义Netty服务器配置实现:

import io.ktor.server.netty.*
import io.netty.channel.*
import io.netty.channel.socket.SocketChannel
import io.netty.buffer.ByteBuf
import java.nio.charset.StandardCharsets

fun main() {
    embeddedServer(Netty, port = 0, sslPort = 4242) {
        // 这里配置你的路由逻辑
    }.apply {
        // 获取Netty的ServerBootstrap并添加前置处理器
        val serverBootstrap = (this as NettyApplicationEngine).serverBootstrap
        serverBootstrap.handler(object : ChannelInitializer<SocketChannel>() {
            override fun initChannel(ch: SocketChannel) {
                ch.pipeline().addFirst("http-blocker", object : ChannelInboundHandlerAdapter() {
                    override fun channelRead(ctx: ChannelHandlerContext, msg: Any) {
                        if (msg is ByteBuf) {
                            // 读取前3个字节判断是否为HTTP请求方法前缀(GET/POS/PUT等)
                            if (msg.readableBytes() >= 3) {
                                val prefixBytes = ByteArray(3)
                                msg.getBytes(msg.readerIndex(), prefixBytes)
                                val prefix = String(prefixBytes, StandardCharsets.US_ASCII)
                                if (prefix in listOf("GET", "POS", "PUT", "DEL", "HEA", "OPT")) {
                                    // 直接关闭连接,不处理后续逻辑
                                    ctx.close()
                                    return
                                }
                            }
                        }
                        // 不是HTTP请求,传递给下一个处理器(TLS握手)
                        ctx.fireChannelRead(msg)
                    }
                })
            }
        })
    }.start(wait = true)
}

二、抑制Netty的WARN日志输出

如果不想修改代码,也可以通过日志框架(以Logback为例)过滤掉特定的WARN日志,避免打印冗长的堆栈:

在logback.xml中添加如下配置:

<configuration>
    <!-- 其他配置 -->
    <logger name="io.netty.handler.ssl.ApplicationProtocolNegotiationHandler" level="WARN">
        <filter class="ch.qos.logback.classic.filter.LevelMatchFilter">
            <level>WARN</level>
        </filter>
        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
            <evaluator>
                <!-- 只过滤包含TLS握手失败且异常为NotSslRecordException的日志 -->
                <expression>message contains "TLS handshake failed" &amp;&amp; throwable instanceof io.netty.handler.ssl.NotSslRecordException</expression>
            </evaluator>
            <onMatch>DENY</onMatch>
            <onMismatch>NEUTRAL</onMatch>
        </filter>
    </logger>
</configuration>

三、通用最佳实践

  • 前置反向代理:用Nginx等反向代理接收请求,Nginx会自动拒绝HTTPS端口的HTTP请求,同时还能做IP黑名单、速率限制等防护。
  • 端口分离:如果需要支持HTTP,单独用一个端口,然后把HTTP请求重定向到HTTPS;不需要的话直接关闭HTTP端口。
  • IP黑名单:收集频繁发送无效请求的IP,通过防火墙或应用层规则拉黑。
  • 速率限制:在KTor中配置速率限制插件,限制单个IP的请求频率,减少机器人的干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:45:56