monkeyWie / proxyee

HTTP proxy server,support HTTPS&websocket.MITM impl,intercept and tamper HTTPS traffic.
MIT License
1.51k stars 566 forks source link

Secure connection from browser to HTTP proxy #165

Open worldworldwest opened 3 years ago

worldworldwest commented 3 years ago

I am trying to provide a secure channel from browser to HTTP proxy to encyrpt all the traffic between the browser and HTTP proxy. To establish a secure connection I have added a new SSLHandler in the pipeline in HttpProxyServer class as follows:

 SslContext sslCtx= SslContextBuilder.forServer(serverConfig.getServerPriKey(),
                            CertPool.getCert(port, "localhost", serverConfig)).build();
 SslHandler sslHandler = sslCtx.newHandler(ch.alloc());
 ch.pipeline().addLast("sslHandler", sslHandler );
 ch.pipeline().addLast("httpCodec", new HttpServerCodec());
 ch.pipeline().addLast("serverHandle",
         new HttpProxyServerHandler(serverConfig, proxyInterceptInitializer, tunnelIntercept, proxyConfig,
                 httpProxyExceptionHandle));

It works for HTTP websites but while navigating to HTTPS websites it prints the following error if I enable printing error messages in HttpProxyExceptionHandle.beforeCatch() method.

io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: close_notify
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:478)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:748)
Caused by: javax.net.ssl.SSLException: Received fatal alert: close_notify
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1647)
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1615)
    at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1781)
    at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1070)
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:896)
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:766)
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
    at io.netty.handler.ssl.SslHandler$SslEngineType$3.unwrap(SslHandler.java:282)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1387)
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:508)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:447)
    ... 17 more

To enable HTTPS proxy for Chrome, following command can be used:

chrome --proxy-server=https://localhost:9999

So how should we modify the pipeline to provide secure communication between browser and proxy?

monkeyWie commented 3 years ago

It is troublesome, I don't want to support. Maybe you shoud manually generate a new root certificate for proxy server instead of CertPool.getCert().