2

我目前正在开发一个客户端/服务器 TLS 工具,该工具需要我们通过防火墙进行连接。由于我们无法控制的原因,我们只被授予传出 TCP 连接。

问题是我们客户端的防火墙阻止了客户端 Hello v2 消息(可能还有整个 SSL 握手)。

有没有办法以某种方式混淆流? 我正在考虑尝试使用压缩来使防火墙无法读取流。(也许使用 JDK7 的 GzipOutputStream 现在允许同步刷新)

我不是 SSL 专家,但在我看来应该可以翻译整个流,这应该使防火墙无法获取连接并阻止它。

据我所知,有几种(两种?)方法可以解决这个问题:

  • 覆盖默认实现
  • 实现 SSLServerSocketFactory

第一个选项对我来说不起作用,因为我找不到 com.sun.net.ssl.internal.ssl.SSLServerSocketFactoryImpl 的源代码,这是默认实现。我确实浏览了它的 openJDK 源代码,但即使在那里,源似乎也丢失了。

实现 SSLServerSocketFactory 超出了我的能力范围。正如我所说,我不是 SSL 专家。

请注意,该应用程序确实可以通过其他不那么激进的防火墙/防火墙规则正常工作。

4

4 回答 4

4

压缩加密流没有用,实际上您只需要一些屏蔽来避开防火墙。

在客户端,您可以使用SSLSocketFactory的方法createSocket(socket, host, port, autoclose)来创建基于另一个套接字的 SSL 套接字 - 这个另一个套接字可以获得您的特殊 SocketImpl 实现,对前几个字节进行简单的 XOR 屏蔽。

在服务器端,它更复杂,因为 SSLServerSocketFactory 没有这样的方法。

在对Java RMI + SSL + Compression = IMPOSSIBLE的回答中!,我描述了如何建立一个委托的 Socket 工厂。那里是为 Rmi(Client|Server)SocketFactory 完成的,但对于 ServerSocketFactory 或 SocketFactory 的工作方式类似。


但当然,您的防火墙可能实际上并没有阻止 SSL 流量,而是阻止了任何未列入白名单的内容(如 HTTP)。在构建包装套接字实现之前,请尝试发送一些随机数据并接收它们的简单套接字+服务器套接字是否有效。

于 2011-07-18T21:30:20.610 回答
2

可能有点跑题了,但如果问题是关于 SSLv2,并且如果 SSLv3 或 TLS 1.x 握手工作正常,您可以禁用 V2 ClientHello,使用SSLSocket.setEnabledProtocols(new String[] { "SSLv3", "TLSv1", "TLSv1.1" }).

请参阅JSSE 参考指南(关于 的部分SSLContext

编辑:对于那些不阅读评论的人,这里是@EJP 答案的链接,其中包含有关此主题的更多详细信息:为什么 Java 的 SSLSocket 发送版本 2 客户端你好?

于 2011-07-18T23:57:35.697 回答
2

无需额外开发即可通过 HTTP 建立 TCP 隧道。有各种各样的工具。看看GNU httptunnel。httptunnel 在 HTTP 请求中创建一个双向虚拟数据连接。如果需要,可以通过 HTTP 代理发送 HTTP 请求。Httpc也很有趣。

于 2011-07-18T22:24:00.950 回答
1

看来解决方案是将布鲁诺的建议和保罗的解决方案结合起来。

Paulo 的解决方案允许我们使用委托自定义 SSLSocket 或 SSLServerSocket 的行为。

Bruno 的建议允许我们告诉默认 SSL 实现使用我们修改后的 SSLSocket 或 SSLServerSocket。

这是我所做的:

  • 创建一个委托 ServerSocket 类 ( MyServerSocket )
  • 创建一个委托 ServerSocketFactory 类 (MyServerSocketFactory)
  • 创建一个委托 SocketFactory 类 (MySocketFactory)
  • 创建一个委托 Socket 类 (MySocket)
  • 创建 XorInputStream(在这里找到)
  • 创建 XorOutputStream(在这里找到)

在服务器端:

    // Initialisation as usual
    ...
    sslSocketFactory = sslContext.getSocketFactory();

    serverSocketFactory = ServerSocketFactory.getDefault();
    serverSocketFactory = new MyServerSocketFactory(serverSocketFactory);
    serverSocket = serverSocketFactory.createServerSocket(port);
    ...
    Socket s = (Socket) serverSocket.accept();
    sslSocket = (SSLSocket) sslSocketFactory.createSocket(s, null, s.getPort(), false);
    sslSocket.setUseClientMode(false);
    sslSocket.setEnabledCipherSuites(new String[]{"SSL_RSA_WITH_RC4_128_MD5"});
    sslSocket.setNeedClientAuth(true);
    ...

在客户端:

    Socket s = new MySocketFactory(SocketFactory.getDefault()).createSocket(host, port);
    SSLSocket socket = (SSLSocket) factory.createSocket(s, host, port, false);

来源



    public class MyServerSocket extends ServerSocket {
    private ServerSocket baseSocket;

    public MyServerSocket(ServerSocket baseSocket) throws IOException {
        this.baseSocket = baseSocket;
    }

    @Override
    public Socket accept() throws IOException {
        return new MySocket(baseSocket.accept());
    }

    @Override
    public void bind(SocketAddress endpoint) throws IOException {
        baseSocket.bind(endpoint);
    }

    @Override
    public void bind(SocketAddress endpoint, int backlog) throws IOException {
        baseSocket.bind(endpoint, backlog);
    }

    @Override
    public void close() throws IOException {
        baseSocket.close();
    }

    @Override
    public ServerSocketChannel getChannel() {
        return baseSocket.getChannel();
    }

    @Override
    public InetAddress getInetAddress() {
        return baseSocket.getInetAddress();
    }

    @Override
    public int getLocalPort() {
        return baseSocket.getLocalPort();
    }

    @Override
    public SocketAddress getLocalSocketAddress() {
        return baseSocket.getLocalSocketAddress();
    }

    @Override
    public synchronized int getReceiveBufferSize() throws SocketException {
        return baseSocket.getReceiveBufferSize();
    }

    @Override
    public boolean getReuseAddress() throws SocketException {
        return baseSocket.getReuseAddress();
    }

    @Override
    public synchronized int getSoTimeout() throws IOException {
        return baseSocket.getSoTimeout();
    }

    @Override
    public boolean isBound() {
        return baseSocket.isBound();
    }

    @Override
    public boolean isClosed() {
        return baseSocket.isClosed();
    }

    @Override
    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
        baseSocket.setPerformancePreferences(connectionTime, latency, bandwidth);
    }

    @Override
    public synchronized void setReceiveBufferSize(int size) throws SocketException {
        baseSocket.setReceiveBufferSize(size);
    }

    @Override
    public void setReuseAddress(boolean on) throws SocketException {
        baseSocket.setReuseAddress(on);
    }

    @Override
    public synchronized void setSoTimeout(int timeout) throws SocketException {
        baseSocket.setSoTimeout(timeout);
    }

    @Override
    public String toString() {
        return baseSocket.toString();
    }


    }


    public class MyServerSocketFactory extends ServerSocketFactory {

    private ServerSocketFactory baseFactory;

    public MyServerSocketFactory(ServerSocketFactory baseFactory) {
        this.baseFactory = baseFactory;
    }


    @Override
    public ServerSocket createServerSocket(int i) throws IOException {
        return new MyServerSocket(baseFactory.createServerSocket(i));
    }

    @Override
    public ServerSocket createServerSocket(int i, int i1) throws IOException {
        return new MyServerSocket(baseFactory.createServerSocket(i, i1));
    }

    @Override
    public ServerSocket createServerSocket(int i, int i1, InetAddress ia) throws IOException {
        return new MyServerSocket(baseFactory.createServerSocket(i, i1, ia));
    }


    }


    public class MySocket extends Socket {
    private Socket baseSocket;

    public MySocket(Socket baseSocket) {
        this.baseSocket = baseSocket;
    }

    private XorInputStream xorInputStream = null;
    private XorOutputStream xorOutputStream = null;
    private final byte pattern = (byte)0xAC;

    @Override
    public InputStream getInputStream() throws IOException {
        if (xorInputStream == null)
        {
            xorInputStream = new XorInputStream(baseSocket.getInputStream(), pattern);
        }
        return xorInputStream;
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        if (xorOutputStream == null)
        {
            xorOutputStream = new XorOutputStream(baseSocket.getOutputStream(), pattern);
        }
        return xorOutputStream;
    }

    @Override
    public void bind(SocketAddress bindpoint) throws IOException {
        baseSocket.bind(bindpoint);
    }

    @Override
    public synchronized void close() throws IOException {
        baseSocket.close();
    }

    @Override
    public void connect(SocketAddress endpoint) throws IOException {
        baseSocket.connect(endpoint);
    }

    @Override
    public void connect(SocketAddress endpoint, int timeout) throws IOException {
        baseSocket.connect(endpoint, timeout);
    }

    @Override
    public SocketChannel getChannel() {
        return baseSocket.getChannel();
    }

    @Override
    public InetAddress getInetAddress() {
        return baseSocket.getInetAddress();
    }

    @Override
    public boolean getKeepAlive() throws SocketException {
        return baseSocket.getKeepAlive();
    }

    @Override
    public InetAddress getLocalAddress() {
        return baseSocket.getLocalAddress();
    }

    @Override
    public int getLocalPort() {
        return baseSocket.getLocalPort();
    }

    @Override
    public SocketAddress getLocalSocketAddress() {
        return baseSocket.getLocalSocketAddress();
    }

    @Override
    public boolean getOOBInline() throws SocketException {
        return baseSocket.getOOBInline();
    }

    @Override
    public int getPort() {
        return baseSocket.getPort();
    }

    @Override
    public synchronized int getReceiveBufferSize() throws SocketException {
        return baseSocket.getReceiveBufferSize();
    }

    @Override
    public SocketAddress getRemoteSocketAddress() {
        return baseSocket.getRemoteSocketAddress();
    }

    @Override
    public boolean getReuseAddress() throws SocketException {
        return baseSocket.getReuseAddress();
    }

    @Override
    public synchronized int getSendBufferSize() throws SocketException {
        return baseSocket.getSendBufferSize();
    }

    @Override
    public int getSoLinger() throws SocketException {
        return baseSocket.getSoLinger();
    }

    @Override
    public synchronized int getSoTimeout() throws SocketException {
        return baseSocket.getSoTimeout();
    }

    @Override
    public boolean getTcpNoDelay() throws SocketException {
        return baseSocket.getTcpNoDelay();
    }

    @Override
    public int getTrafficClass() throws SocketException {
        return baseSocket.getTrafficClass();
    }

    @Override
    public boolean isBound() {
        return baseSocket.isBound();
    }

    @Override
    public boolean isClosed() {
        return baseSocket.isClosed();
    }

    @Override
    public boolean isConnected() {
        return baseSocket.isConnected();
    }

    @Override
    public boolean isInputShutdown() {
        return baseSocket.isInputShutdown();
    }

    @Override
    public boolean isOutputShutdown() {
        return baseSocket.isOutputShutdown();
    }

    @Override
    public void sendUrgentData(int data) throws IOException {
        baseSocket.sendUrgentData(data);
    }

    @Override
    public void setKeepAlive(boolean on) throws SocketException {
        baseSocket.setKeepAlive(on);
    }

    @Override
    public void setOOBInline(boolean on) throws SocketException {
        baseSocket.setOOBInline(on);
    }

    @Override
    public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
        baseSocket.setPerformancePreferences(connectionTime, latency, bandwidth);
    }

    @Override
    public synchronized void setReceiveBufferSize(int size) throws SocketException {
        baseSocket.setReceiveBufferSize(size);
    }

    @Override
    public void setReuseAddress(boolean on) throws SocketException {
        baseSocket.setReuseAddress(on);
    }

    @Override
    public synchronized void setSendBufferSize(int size) throws SocketException {
        baseSocket.setSendBufferSize(size);
    }

    @Override
    public void setSoLinger(boolean on, int linger) throws SocketException {
        baseSocket.setSoLinger(on, linger);
    }

    @Override
    public synchronized void setSoTimeout(int timeout) throws SocketException {
        baseSocket.setSoTimeout(timeout);
    }

    @Override
    public void setTcpNoDelay(boolean on) throws SocketException {
        baseSocket.setTcpNoDelay(on);
    }

    @Override
    public void setTrafficClass(int tc) throws SocketException {
        baseSocket.setTrafficClass(tc);
    }

    @Override
    public void shutdownInput() throws IOException {
        baseSocket.shutdownInput();
    }

    @Override
    public void shutdownOutput() throws IOException {
        baseSocket.shutdownOutput();
    }

    @Override
    public String toString() {
        return baseSocket.toString();
    }



    }

    public class MySocketFactory extends SocketFactory {

    private SocketFactory baseFactory;


    public MySocketFactory(SocketFactory baseFactory) {
        this.baseFactory = baseFactory;
    }


    @Override
    public Socket createSocket() throws IOException {
        return baseFactory.createSocket();
    }


    @Override
    public boolean equals(Object obj) {
        return baseFactory.equals(obj);
    }



    @Override
    public int hashCode() {
        return baseFactory.hashCode();
    }

    @Override
    public String toString() {
        return baseFactory.toString();
    }



    @Override
    public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
        return new MySocket(baseFactory.createSocket(string, i));
    }

    @Override
    public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
        return baseFactory.createSocket(string, i, ia, i1);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i) throws IOException {
        return baseFactory.createSocket(ia, i);
    }

    @Override
    public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
        return baseFactory.createSocket(ia, i, ia1, i1);
    }

    }

于 2011-07-19T14:27:51.730 回答