【问题标题】:Netty SSL headersNetty SSL 标头
【发布时间】:2016-02-18 10:05:38
【问题描述】:

我不想问这个问题,因为我确信答案就在那里,但正如我之前所说的,令人失望的是我没有发现 Netty 文档很有帮助。

无论如何,显然,我已经构建了一个使用 Netty 进行 HTTP 和 HTTPS 连接的 Java Web 服务器。服务器提供静态和动态内容,可以通过多个虚拟主机(加上直接 IP)访问这些内容。我已经使用单个证书成功实现了 SSL 服务器范围,但是由于我的服务器旨在托管虚拟主机,并且可能为每个虚拟主机提供不同的 SSL 证书,因此我需要在 SSL 握手开始之前知道请求的域,以便我可以正确访问正确的证书,但正如我被告知的那样,SSL 也会加密标头,不幸的是,直到握手完成后我才看到标头(这是在我的 Handler 类中调用 messageReceived 方法时)。

那么任何人都可以建议我如何克服这个问题吗?我是否需要协商初始 SSL 连接,然后使用正确的证书或其他东西重新协商? Apache 如何处理这个问题?非常感谢您的帮助。仅供参考,我使用的是 Netty 5.0.0 Alpha2。

【问题讨论】:

  • 您需要查看套接字通道的本地地址以查看它被寻址到哪个主机。
  • 除此之外,我正在寻找虚拟主机,例如使用 DNS 路由的 example.com。查看本地地址只会显示服务器的 IP 或主机名。

标签: java ssl https netty


【解决方案1】:

好的,所以也许是个人的第一次,我在发布这个问题之后找到了答案,那是在过去几个小时搜索谷歌之后。因此,我将分享我的发现,希望可以帮助其他人。

在发现 Apache 使用 SNI 将虚拟主机映射到多个证书后,我发现 Netty 有一个名为 SniHandler 的类,显然服务器端 SNI 支持大部分仅在 Java 8 中可用。我最近刚刚将所需的最低版本更新为Java 8,一切都很好。在稍微弄乱了类之后,我能够轻松地将 SniHandler 放在我的服务器范围的 SSL 实现之间,并为每个虚拟主机添加额外的证书。这就是我对 Netty 爱恨交织的原因,它通常有一个很好的内置解决方案,但我很难找到它。

以防万一这里是我的源代码,你可以在https://github.com/ChioriGreene/ChioriWebServer找到我的整个网络服务器项目

SslContextFactory.class

public class SslContextFactory
{
    private static DomainNameMapping<SslContext> mapping;

    private SslContextFactory()
    {

    }

    public static void addMapping( String hostname, SslContext context )
    {
        // Using *.example.com will include all subdomains, including the root TLD
        mapping.add( hostname, context );
    }

    public static SniHandler getSniHandler()
    {
        return new SniHandler( mapping );
    }

    public static void init() throws StartupException
    {
        final File sslCert = new File( "server.crt" );
        final File sslKey = new File( "server.key" );
        final String sslSecret = "SslSecret";

        if ( !sslCert.exists() )
            throw new StartupException( "We could not start the HTTPS Server because the '" + sslCert.getName() + "' (aka. SSL Cert) file does not exist. Please generate one and reload the server, or disable SSL in the configs." );

        try
        {
            NetworkManager.getLogger().info( String.format( "Initalizing the SslContext using cert '%s', key '%s', and hasSecret? %s", sslCert.getName(), sslKey.getName(), ( sslSecret != null && !sslSecret.isEmpty() ) ) );

            SslContext sslContext;
            if ( sslSecret == null || sslSecret.isEmpty() )
                sslContext = SslContext.newServerContext( sslCert, sslKey );
            else
                sslContext = SslContext.newServerContext( sslCert, sslKey, sslSecret );

            mapping = new DomainNameMapping<SslContext>( sslContext );
        }
        catch ( SSLException e )
        {
            throw new StartupException( "We could not start the HTTPS Server because " + e.getMessage(), e );
        }
        catch ( Exception e )
        {
            throw new StartupException( "We could not start the HTTPS Server for an uncaught exception", e );
        }
    }
}

HttpsInitializer.class

public class HttpsInitializer extends ChannelInitializer<SocketChannel>
{
    @Override
    protected void initChannel( SocketChannel ch ) throws Exception
    {
        ChannelPipeline p = ch.pipeline();

        try
        {
            p.addLast( SslContextFactory.getSniHandler() );
        }
        catch ( Exception e )
        {
            NetworkManager.shutdownHttpsServer();
            throw new IllegalStateException( "The SSL engine failed to initalize", e );
        }

        p.addLast( "decoder", new HttpRequestDecoder() );
        p.addLast( "aggregator", new HttpObjectAggregator( 104857600 ) );
        p.addLast( "encoder", new HttpResponseEncoder() );
        p.addLast( "deflater", new HttpContentCompressor() );
        p.addLast( "handler", new HttpsHandler() );
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-16
    • 2012-02-25
    • 2017-12-01
    • 2023-04-01
    • 2012-06-22
    • 1970-01-01
    • 2012-07-08
    • 2019-06-20
    相关资源
    最近更新 更多