2014-10-20 33 views
0

我想代理SSL數據,HTTPS在這種情況下。ruby​​ SSL代理(MITM)

這裏是我的代碼:

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 

這是 「tcp_proxy」 這是真正的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

您必須小心閱讀和選擇,因爲讀取是在SSL級完成的,而select是在TCP級。

SSL將數據放入幀中,其中每個幀最多可以包含16384個字節。它需要從底層TCP套接字讀取完整幀,然後SSL套接字上的讀取才能從幀中返回任何數據。這意味着如果你有一個有4097字節有效負載的幀,它需要從TCP套接字讀取完整幀,然後才能從SSL套接字讀取任何內容。如果您只從SSL套接字讀取4096個字節,它將返回前4096個字節,並將其餘(1個字節)留在SSL緩衝區中。如果您在TCP級別選擇新數據進行檢查,則可能會阻止它,因爲在TCP級別上沒有未讀數據,即使SSL緩衝區內仍有單字節。

有兩種方法可以解決此問題:

  • 檢查與pending是否還有在SSL緩存數據。如果有,請閱讀它們而不是進行選擇。
  • 或者嘗試每次讀取時至少讀取16384個字節,即SSL幀的最大大小。我不確定在ruby中的實現,但在Perl中,這個讀取只會調用底層的SSL_read,這隻能讀取單個幀中的數據。因此,讀取大小爲16384字節時,不會有未決數據,您可以像現在一樣調用select。
+0

使用IO.select,並將「讀取」設置爲16384似乎工作,我會研究植入掛起但目前它的竅門。 – Ba7a7chy 2014-10-20 18:51:16