繁体   English   中英

尝试通过从基础浏览器构建的代理隧道穿过https永远不会回复?

[英]Trying to tunnel through https via a proxy built from ground up browser never responds back?

由于各种原因,有必要创建我们自己的代理。 一切都在通过HTTP工作。 一旦我们通过SSL收到CONNECT到隧道,就会出现问题。 我们逻辑上做的是将CONNECT解析出主机和端口,以便我们知道我们在哪里发送未来​​的ssl请求并创建一个请求发送回浏览器,说明我们已经成功地进行了ssl握手,如下所示:

建立HTTP / 1.0 200连接\\ r \\ nProxy-agent:test \\ r \\ n \\ r \\ n

我们期望发生的是,一旦收到此成功消息,浏览器将向我们发送下一个https请求。 但是,我们反复发送另一个CONNECT请求。很明显,它不喜欢我们发回的响应。 问题是我不确定为什么? 是否需要通过https套接字返回响应? 我只是不明白这个过程足以向前推进。

这是我的服务器类:

public class HttpServer extends Observable implements IWebServer, Runnable
{
int Port = -1;
int State = HttpState.IDLE;
ArrayList<WebTransactionEvent> History = new ArrayList<WebTransactionEvent>();
ArrayList<HttpService> myServices = new ArrayList<HttpService>();

SocketChannel myChannel = null;
boolean needResponse = false;
boolean shouldStop;
Logger logger = OpsToolsLogger.getLogger(HttpServer.class.getName());
Selector selector ;
static Hashtable<String, HttpServer> myInstances = new Hashtable<String, HttpServer>(); 
Hashtable<HttpTransaction, HttpService> myTaskTable = new Hashtable<HttpTransaction, HttpService>(); 
Vector<HttpTransaction> transactionQueue = new Vector<HttpTransaction>(); 

private HttpServer(){}

private HttpServer(int Port) 
{
    logger.log(Level.WARNING, "HttpServer: startup - listening to port: " + Port);
    this.Port = Port;
    shouldStop = false;

    // Create the selector
    try {
            selector = Selector.open();
            ServerSocketChannel serverChannel = ServerSocketChannel.open();
            serverChannel.configureBlocking(false);
            serverChannel.socket().bind(new InetSocketAddress(Port));
            this.registerSocket(serverChannel);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    new Thread(this).start();
}

public static HttpServer getInstance(String port)
{
    if( !myInstances.containsKey( port ) )
    {   
        myInstances.put( port, new HttpServer(Integer.parseInt(port)));
    }

    return myInstances.get(port);
}

public int getState()
{
    return State;
}

public void stop()
{
    shouldStop = true;
}

public boolean needResponse()
{
    return needResponse;
}

public HttpTransaction getNextTransaction()
{
    if(transactionQueue.isEmpty())
    {
        return null;
    }
    //System.out.println("grabbing next trans");
    HttpTransaction temp = transactionQueue.firstElement();
    transactionQueue.remove(0);//pop trans from  queue
    return temp;
}

public void dropTransaction()
{
    myTaskTable.clear();
    needResponse = false;

}

public synchronized boolean respond(HttpTransaction transaction, IHttpResponse editedResponse, boolean closeConnection)
{
    logger.log(Level.FINE, "HttpServer: responding ");
    needResponse = false;
    if(myTaskTable.isEmpty())
    {
        return false;
    }

    //see if there isn't a service object registered with that transaction
    if(!myTaskTable.containsKey(transaction))
    {
        return false;
    }

    State = HttpState.SENDING_RESPONSE;
    ManipulatedHttpTransaction myTrans = (ManipulatedHttpTransaction) transaction;
    HttpResponse response = (HttpResponse) editedResponse;
    myTrans.setManipulatedResponse( response );
    HttpService serv = myTaskTable.get(transaction);
    if(!serv.respond(myTrans.getManipulatedResponse(), closeConnection))
    {
        History.add( new WebTransactionEvent( myTrans, WebTransactionEvent.TRANSACTION_ERROR ) );
        return false;
    }

    myTaskTable.remove(transaction);

    History.add( new WebTransactionEvent( myTrans, WebTransactionEvent.TRANSACTION_COMPLETED ) );

    needResponse = !myTaskTable.isEmpty();

    return true;
}

public void registerSocket(ServerSocketChannel theSocket)
{
    try {
        theSocket.register(selector, SelectionKey.OP_ACCEPT);
    } catch (ClosedChannelException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

@Override
public void run()
{
    try {

        while (!shouldStop ) {
            // Wait for an event
            selector.select();

            // Get list of selection keys with pending events
            Iterator it = selector.selectedKeys().iterator();

            // Process each key
            while (it.hasNext()) {
                // Get the selection key
                SelectionKey selKey = (SelectionKey)it.next();

                // Remove it from the list to indicate that it is being processed
                it.remove();

                // Check if it's a connection request
                if (selKey.isAcceptable()) {
                    // Get channel with connection request
                   ServerSocketChannel ssChannel = (ServerSocketChannel)selKey.channel();
                   SocketChannel theChannel =  ssChannel.accept();
                   if(theChannel != null)
                    {

                        logger.log(Level.FINEST, "HttpServer: Connection established");

                        try
                        {
                            theChannel.configureBlocking(false);
                        }
                        catch(Exception e)
                        {
                            logger.log(Level.WARNING, "myChannel = null ( configureBlocking() )");
                            //bytesRead = -1;
                        }

                        myServices.add( new HttpService(this, theChannel ) );
                        needResponse = true;

                    }

                    //needResponse = !myTaskTable.isEmpty();                
                    //System.out.println("need response: "+ needResponse);

                }
            }
        }
    } catch (IOException e) {
    }
    //shutdown
    logger.log(Level.WARNING, "Server stopping - " + Port);
}

public ArrayList<WebTransactionEvent> getHistory() 
{
    return new ArrayList<WebTransactionEvent>(History);
}

public boolean switchServerToSSL()
{
    //HttpService tempService = myTaskTable.get(PendingTransaction);
    //tempService.useSSL = true;
    return true;
}

/**
 * Adds the transaction from browser to the transaction queue and also ties it to a service by adding it to myTasks map
 * @param myTrans
 * @param httpService
 */
public void addTransaction(ManipulatedHttpTransaction myTrans,
        HttpService httpService) {
    // TODO Auto-generated method stub
    //ensure vector has room to add another transaction
    if(transactionQueue.capacity() <= transactionQueue.size())
        transactionQueue.ensureCapacity(transactionQueue.size() * 2);

    transactionQueue.add(myTrans);//add transaction to queue
    myTaskTable.put(myTrans, httpService);//tie the transaction toits service
   // System.out.println("server notifying proxy: " + myTrans.getFullURL());
    this.setChanged();
    this.notifyObservers(myTrans);
}

}

以下是代理中处理CONNECT的部分:

if(tempTransaction.getOriginatingRequest().getMethod().contentEquals("CONNECT"))
            {
                /*tell the browser that the connection exists
                 * 
                 * Each time you connect to an SSL-protected website, Burp generates a server certificate for that host, signed by the CA certificate
                 * 
                 * The server certificates presented to the client (i.e. a web browser) are dynamically generated/signed by the proxy and contain most of the same fields as the original webserver certificate. The subject DN, serial number, validity dates, and extensions are preserved. However, the issuer DN is now set to the name of the proxy's self-signed 
                 * certificate and the public/private keys of the proxy are used in creating the forged certificate. These forged certificates are cached (in memory) by the proxy, for better performance
                 */
                HttpResponse tunnelResponse = new HttpResponse("HTTP/1.0 200 Connection established\r\nProxy-agent: Ops Assistant\r\n\r\n");
                tempTransaction.setResponse(tunnelResponse);

                if(!finishResponse2(tempTransaction,tempTransaction.getResponse(), false));
                {
                    //close the connection
                }

                myServer.switchServerToSSL();
            }

这是节发送请求回浏览器:

 public boolean respond(IHttpResponse response, boolean closeConnection)
{
    isCloseConnectionRequested = closeConnection;

    try 
    {
        if(useSSL)
        {
            ByteBuffer tmpBuffer = response.getData();
            tmpBuffer.position(0);
            myConnection.SecureWrite( tmpBuffer );
        }
        else
        {
            ByteBuffer tmpBuffer = response.getData();
            tmpBuffer.position(0);
            myConnection.Write(tmpBuffer);
        }
        if(closeConnection)
        {
            myChannel.close();
            myChannel = null;
        }
    }
    catch (Exception e) 
    {
        isResponded = true;
        return false;
    }

    isResponded = true;
    return true;

}

可能最重要的socket类:

 public class SocketConnection implements IConnection
   {

public SocketChannel theSocketChannel;
public InetSocketAddress theRemoteAddress;
public int TimeoutThreshold;

private int TimeOutThreshold = 30;
private SSLEngine theSSLEngine;
private SSLContext theSSLContext;
private ByteBuffer inNetworkDataBuffer;
private ByteBuffer inAppDataBuffer;
private ByteBuffer outNetworkDataBuffer;
private ByteBuffer outAppDataBuffer;

//create outbound connection to host/port
public SocketConnection(String Host, int Port ) throws IOException
{
    theRemoteAddress = new InetSocketAddress( Host, Port);
    theSocketChannel = SocketChannel.open();
    theSocketChannel.configureBlocking(false);
    theSocketChannel.connect( theRemoteAddress );
    theSocketChannel.finishConnect();
}

//use existing socket connection
public SocketConnection(SocketChannel existingChannel) throws IOException
{
    theSocketChannel = existingChannel;
    theSocketChannel.configureBlocking(false);
    theRemoteAddress = new InetSocketAddress( existingChannel.socket().getInetAddress(), existingChannel.socket().getPort() );
}

public boolean setTimeOut(int newTimeOutThreshold) 
{
    TimeOutThreshold = newTimeOutThreshold; 
    return true;
}

public void waitForSocketToConnect() throws Exception
{
    int i = 0;
    while( !this.isConnected() )
    {
        this.finishConnect();
        if(i>=3000)
        {
            throw new Exception();
        }
        i++;

        try{Thread.sleep(10);}catch(Exception e){}
    }
}

public boolean Write( ByteBuffer DataToSend )
{
    try 
    {
        //DataToSend.flip();
        int numBytesWritten = theSocketChannel.write(DataToSend);
        try
        {
            DataToSend.compact();
        }
        catch (ReadOnlyBufferException e)
        {
            DataToSend.rewind();
        }
    } 
    catch (IOException e)
    {
        // Connection may have been closed
    }

    return true;
}

public ByteBuffer Read()
{   
    ByteBuffer ResponseBytes = ByteBuffer.allocateDirect(0);

    try 
    {
        ByteBuffer netBuffer = ByteBuffer.wrap(new byte[10000]);


        // Clear the buffer and read bytes from socket
        netBuffer.clear();

        int numBytesRead = theSocketChannel.read(netBuffer);
        if(numBytesRead == -1)
            return null; //-1 means we done return null as the flag
        netBuffer.flip();

        ByteBuffer tempBuffer = ByteBuffer.wrap(new byte[ ResponseBytes.limit() + netBuffer.limit() ]);
        ResponseBytes.position(0);
        netBuffer.position(0);
        tempBuffer.put(ResponseBytes);
        tempBuffer.put(netBuffer);
        netBuffer.flip();
        ResponseBytes = tempBuffer;

    } 
    catch (IOException e) 
    {
        // Connection may have been closed
        e = e;
        return ByteBuffer.wrap( e.getMessage().getBytes() );
    }

    return (ByteBuffer) ResponseBytes.flip();

}

public boolean SecureWrite( ByteBuffer DataToSend )
{
    boolean writeSuccess = true;

    try
    {
        //if we don't have a SSLEngine make one
        if(theSSLEngine==null)
        {
            setupSSL();
        }

        //Convert Data 
        outAppDataBuffer.clear();
        outAppDataBuffer.put(DataToSend);
        outAppDataBuffer.flip();
        SSLEngineResult sslResult = theSSLEngine.wrap(outAppDataBuffer, outNetworkDataBuffer);
        outAppDataBuffer.compact();  
        //outNetworkDataBuffer.flip();
        //int numBytesWritten = theSocketChannel.write(outNetworkDataBuffer);
        if(sslResult.getStatus() == SSLEngineResult.Status.OK)
        {
            if(sslResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
            {   
                // Write bytes
                outNetworkDataBuffer.flip();
                int numBytesWritten = theSocketChannel.write(outNetworkDataBuffer);
                outNetworkDataBuffer.compact();

                if(finishHandshake(sslResult))
                {
                    DataToSend.rewind();
                    return SecureWrite(DataToSend);
                }
                else
                {
                    return false;
                }
            }
            else
            {
                // Write bytes
                outNetworkDataBuffer.rewind();
                Write(outNetworkDataBuffer);
            }

        }
        else
        {

        }

    }
    catch(Exception e)
    {
        writeSuccess = false;
    }

    return writeSuccess;

}

public ByteBuffer SecureRead() throws ReadTimedOutException
{
    int timeElapsed = 0;
    ByteBuffer ResponseBytes = ByteBuffer.allocateDirect(0);

    try 
    {
        //if we don't have a SSLEngine make one
        if(theSSLEngine==null)
        {
            setupSSL();
        }

        int consumedCount = 0;
        SSLEngineResult sslResult;
        do
        {
            //inNetworkDataBuffer.clear();
            inNetworkDataBuffer.put( Read() );
            inNetworkDataBuffer.flip();
            sslResult = theSSLEngine.unwrap( inNetworkDataBuffer, inAppDataBuffer );
            consumedCount += sslResult.bytesConsumed();     
            inNetworkDataBuffer.compact();

            if( sslResult.getStatus() == SSLEngineResult.Status.OK ) 
            {

                if(sslResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
                {

                    if(finishHandshake(sslResult))
                    {
                        return SecureRead();
                    }
                    else
                    {
                        return ByteBuffer.allocateDirect(0);
                    }
                }
                else
                {
                    timeElapsed = 0;
                    inAppDataBuffer.flip();
                    ByteBuffer tempBuffer = ByteBuffer.wrap(new byte[ ResponseBytes.limit() + inAppDataBuffer.limit() ]);
                    ResponseBytes.position(0);
                    inAppDataBuffer.position(0);
                    tempBuffer.put(ResponseBytes);
                    tempBuffer.put(inAppDataBuffer);
                    inAppDataBuffer.flip();
                    ResponseBytes = tempBuffer;
                    ResponseBytes.flip();       
                }
            }
            else
            {
                //the status wasn't ok
                timeElapsed++;
            }
        }while(consumedCount < inNetworkDataBuffer.limit() && sslResult.getStatus() != SSLEngineResult.Status.OK);


    }
    catch (Exception e) 
    {
        System.out.println(e.toString());
    }

    if(timeElapsed>=TimeOutThreshold)
    {
        throw new ReadTimedOutException();
    }


    return ResponseBytes;
}

public boolean Disconnect()
{
    try
    {
        theSocketChannel.close();
    }
    catch(Exception e)
    {
        return false;
    }

    return true;
}

public boolean isClosed()
{
    return !theSocketChannel.isOpen();
}

@Override
public String getHost() 
{
    return theRemoteAddress.getHostName();
}

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

public boolean isConnected() 
{
    return theSocketChannel.isConnected();
}


@Override
public boolean hasSecure() 
{
    return true;
}

public boolean finishConnect() throws Exception
{
    return theSocketChannel.finishConnect();
}

private void setupSSL() throws NoSuchAlgorithmException, KeyManagementException
{

    //create a new SSLEngine instance
    System.setProperty( "javax.net.debug", "ssl");
    TrustManager[] tm = new TrustManager[] { new NaiveTrustManager() };
    SSLContext theSSLContext = SSLContext.getInstance ("TLS");
    theSSLContext.init( new KeyManager[0], tm, new SecureRandom( ) );

    theSSLEngine = theSSLContext.createSSLEngine( theRemoteAddress.getHostName(), theRemoteAddress.getPort());
    theSSLEngine.setUseClientMode(true);

    inNetworkDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getPacketBufferSize()]);
    inAppDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getApplicationBufferSize()]);
    outNetworkDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getPacketBufferSize()]);
    outAppDataBuffer = ByteBuffer.wrap(new byte[theSSLEngine.getSession().getApplicationBufferSize()]);

}

private boolean finishHandshake(SSLEngineResult sslResult)
{   
    boolean bFinished = false;

    while(sslResult.getHandshakeStatus() != SSLEngineResult.HandshakeStatus.FINISHED)
    {
        if( sslResult.getStatus() == SSLEngineResult.Status.CLOSED ) 
        {   
            bFinished = false;
            //break;
        }


        if(sslResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK)
        {
            Runnable task;
            while ((task=theSSLEngine.getDelegatedTask()) != null)
            {
                task.run();
            }

            try 
            {
                //outNetworkDataBuffer.flip();
                sslResult = theSSLEngine.wrap(outAppDataBuffer, outNetworkDataBuffer);
                //outNetworkDataBuffer.compact();
            } 
            catch (SSLException e) 
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
        else if(sslResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)
        {
            try 
            {
                outAppDataBuffer.flip();
                sslResult = theSSLEngine.wrap(outAppDataBuffer, outNetworkDataBuffer);
                outAppDataBuffer.compact();
            } catch (SSLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if((sslResult.getStatus() == SSLEngineResult.Status.BUFFER_OVERFLOW) || (outNetworkDataBuffer.position() > 0))
            {
                try 
                {
                    outNetworkDataBuffer.flip();
                    int numBytesWritten = theSocketChannel.write(outNetworkDataBuffer);
                    outNetworkDataBuffer.compact();
                } 
                catch (Exception e) 
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        else if(sslResult.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)
        {
            try 
            {
                int numBytes;
                //read data from the socket into inNetworkBuffer                    
                inNetworkDataBuffer.flip();
                sslResult = theSSLEngine.unwrap( inNetworkDataBuffer, inAppDataBuffer );
                inNetworkDataBuffer.compact();
                if(theSSLEngine.isInboundDone())
                {

                }
                else
                {
                    numBytes = theSocketChannel.read(inNetworkDataBuffer);
                    numBytes = numBytes;
                }

            } 
            catch (Exception e) 
            {
                e.printStackTrace();
                return false;
            }
        }
    }

    return true;
}

}

任何人都有关于如何最好地与浏览器建立此握手的任何提示?

你读过网络草案了吗? CONNECT以明文形式接收。 您形成上游连接并返回'HTTP / 1.0 200建立连接'响应。 在那之后,代理不处理请求和响应,它只是在两个方向上复制字节,无论它们可能发生什么。 具体而言,代理不以任何形式或形式关注SSL。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM