2

私は現在、ファイアウォールを介して接続する必要があるクライアント/サーバーTLSツールに取り組んでいます。制御できない理由により、発信TCP接続のみが許可されます。

問題は、クライアントのファイアウォールがクライアントのHello v2メッセージ(および場合によってはSSLハンドシェイク全体)をブロックすることです。

何らかの方法でストリームを難読化する方法はありますか? 圧縮を使用してストリームをファイアウォールで読み取れないようにすることを考えていました。(多分、syncFlushフラッシングを可能にするJDK7のGzipOutputStreamを使用しています)

私はSSLの専門家ではありませんが、ストリーム全体を変換できるはずです。これにより、ファイアウォールが接続を取得してブロックすることができなくなります。

私が見る限り、これを行うにはいくつかの(2つ?)方法があります:

  • デフォルトの実装をオーバーライドする
  • SSLServerSocketFactoryを実装する

デフォルトの実装であるcom.sun.net.ssl.internal.ssl.SSLServerSocketFactoryImplのソースコードが見つからないため、最初のオプションはうまくいきませんでした。私はそれについてopenJDKソースコードを閲覧しましたが、それでもソースが欠落しているようです。

SSLServerSocketFactoryの実装は私の能力を超えています。私が言ったように、私はSSLの専門家ではありません。

アプリケーションは、他の攻撃性の低いファイアウォール/ファイアウォールルールを介して正常に動作することに注意してください。

4

4 に答える 4

4

暗号化されたストリームの圧縮は役に立ちません。実際には、ファイアウォールを回避するために一部のマスキングのみが必要です。

クライアント側では、SSLSocketFactoryのメソッドcreateSocket(socket, host, port, autoclose)を使用して、別のソケットに基づいてSSLソケットを作成できます。この別のソケットは、最初の数バイトで単純なXORマスキングを実行して、特別なSocketImpl実装を取得できます。

サーバー側では、SSLServerSocketFactoryにそのようなメソッドがないため、より複雑になります。

Java RMI + SSL+圧縮=不可能への答えで!、委任ソケットファクトリを構築する方法について説明しました。ここでは、Rmi(Client | Server)SocketFactoryに対して実行されましたが、ServerSocketFactoryまたはSocketFactoryに対しても同様に機能します。


ただし、もちろん、ファイアウォールが実際にSSLトラフィックをブロックしているのではなく、ホワイトリストに登録されていないもの(HTTPなど)をブロックしている可能性があります。ラッピングソケットの実装を構築する前に、ランダムなデータを送信して受信する単純なソケット+サーバーソケットが機能するかどうかを試してください。

于 2011-07-18T21:30:20.610 に答える
2

追加の開発なしで、HTTPを介してTCPをトンネリングすることが可能です。さまざまなツールがあります。GNUhttptunnelを見てください。httptunnelは、HTTPリクエストでトンネリングされた双方向の仮想データ接続を作成します。必要に応じて、HTTPリクエストをHTTPプロキシ経由で送信できます。Httpcも非常に興味深いものです。

于 2011-07-18T22:24:00.950 に答える
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 に答える
1

解決策は、ブルーノの提案とパウロの解決策を組み合わせることだと思われます。

Pauloのソリューションでは、デリゲートを使用してSSLSocketまたはSSLServerSocketの動作をカスタマイズできます。

Brunoの提案により、変更されたSSLSocketまたはSSLServerSocketを使用するようにデフォルトのSSL実装に指示することができます。

これが私がしたことです:

  • デリゲートServerSocketクラス(MyServerSocket)を作成します
  • デリゲートServerSocketFactoryクラスを作成します(MyServerSocketFactory)
  • デリゲートSocketFactoryクラスを作成します(MySocketFactory)
  • デリゲートソケットクラスを作成する(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 に答える