ruby SSL代理(MITM)

时间:2014-10-20 14:18:42

标签: ruby ssl proxy

我想代理SSL数据,在这种情况下是HTTPS。

这是我的代码:

begin
        server = TCPServer.open(on_demand_port)
rescue Exception => e
        sleep 5 
        retry
end
sslContext = OpenSSL::SSL::SSLContext.new
sslContext.verify_mode = OpenSSL::SSL::VERIFY_NONE
begin
    sslContext.cert = OpenSSL::X509::Certificate.new(File.open("#{Dir.pwd}/Cert/cert.pem"))
    sslContext.key = OpenSSL::PKey::RSA.new(File.open("#{Dir.pwd}/Cert/key.pem"), "1234")

rescue Exception => e
        sleep 5
        retry
end
begin
    sslServer = OpenSSL::SSL::SSLServer.new(server, sslContext)
rescue Exception => e
        sleep 5
        retry
end

while true

    begin
        threads << Thread.new(sslServer.accept) do |client| # Putting new connections into the thread pool
        tcp_proxy(client, db_name, db_user, db_password, remote_host, remote_port, patterns)
        end
    rescue Exception => e
    end



    threads = threads.select { |t| t.alive? ? true : (t.join; false) }
        while threads.size >= on_demand_max_threads
            sleep 1
            threads = threads.select { |t| t.alive? ? true : (t.join; false) }
    end
end

这是&#34; tcp_proxy&#34;这是实际的SSL代理

begin
begin
    ssl_context = OpenSSL::SSL::SSLContext.new
    ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
    cert_store = OpenSSL::X509::Store.new
    cert_store.set_default_paths
    ssl_context.cert_store = cert_store
    tcp_socket = TCPSocket.new(remote_host, remote_port)
    server_socket = OpenSSL::SSL::SSLSocket.new tcp_socket, ssl_context
    server_socket.sync_close = true
    server_socket.connect
rescue Exception => e
            client.close
end         
while true
    # Wait for data to be available on either socket.
    (ready_sockets, dummy, dummy) = IO.select([client, server_socket])
    begin
        ready_sockets.each do |socket|
            data = socket.readpartial(4096)
            if socket == client
                # Read from client, write to server.
                server_socket.write data
                server_socket.flush
            else
                # Read from server, write to client.
                client.write data
                client.flush
            end
     end
     rescue Exception => e
     end
end
    rescue StandardError => e
    end
    begin
        client.close
        server_socket.close
    rescue Exception => e
    end

现在,这在普通的TCP和HTTP中运行良好,但是,当我在升级套接字时在SSL \ HTTPS中使用它时,它开始变得非常慢,有时只会超时。

知道为什么吗?

1 个答案:

答案 0 :(得分:1)

读取和选择时必须小心,因为读取是在SSL级别完成的,而select是在TCP级别。

SSL将数据放入帧中,每帧最多可包含16384个字节。它需要从底层TCP套接字读取完整帧,然后SSL套接字上的读取才能返回帧中的任何数据。这意味着如果你有一个4097字节有效载荷的帧,它将需要从TCP套接字读取整个帧,然后才能从SSL套接字读取任何内容。如果您只读取SSL套接字中的4096个字节,它将返回前4096个字节,并将其余部分(1个字节)保留在SSL缓冲区中。如果然后检查选择是否在TCP级别的新数据,它可能会阻止,因为在TCP级别没有未读数据,即使SSL缓冲区中仍有单个字节。

有两种方法可以解决此问题:

  • 如果SSL缓冲区中仍有数据,请与pending核对。如果有,请阅读它们而不是进行选择。
  • 或尝试每次读取至少16384个字节,即SSL帧的最大大小。我不确定ruby中的实现,但是在Perl中,这个读取只会调用底层的SSL_read,而这只会从单个帧中读取数据。因此,读取大小为16384字节时,可能没有待处理数据,您可以像现在一样调用select。