Christian Seiler: fsockopen zu server hinter proxy

Beitrag lesen

Hallo!

$fp = fsockopen("ssl://zielserver.com",443,$errstr,$errno);

Du willst offensichtlich Dich mit SSL mit dem Server verbinden. Das Problem: Wenn Du einen HTTP-Proxy dazwischen hast, dann musst Du vorher mit dem Proxy im Klartext reden, um einen HTTP-CONNECT-Aufruf abzusetzen. DANACH musst Du dann die TLS-Verschlüsselung aktivieren. Das heißt aber auch, dass Du das nicht mehr bequem per fsockopen() machen kannst (dort musst Du erst einmal eine normale TCP-Verbindung aufbauen), sondern Du musst den TLS-Handshake erst im Laufe der Verbindung (sobald CONNECT durchgegangen ist) anstoßen. Dafür bietet PHP eine Funktion an, nämlich stream_socket_enable_crypto, die aber erst ab PHP 5.1 funktioniert (unter PHP 5.2.6 würde ich aber aus Sicherheitsgründen sowieso kein PHP einsetzen wollen).

Hier mal ein Beispiel, wie man das machen kann:

$proxy_host = 'proxyhost.lan';  
$proxy_port = 3128;  
  
$remote_host = 'zielhost.test';  
$remote_port = 443;  
  
$fp = fsockopen ("tcp://$proxy_host:$proxy_port", 0, $errstr, $errno);  
if (!is_resource ($fp)) {  
  // verbindung zum proxy geht nicht  
  throw new Exception ("Could not open connection to proxy server");  
}  
  
// CONNECT-request senden  
fputs ($fp, "CONNECT $remote_host:$remote_port HTTP/1.1\r\n\r\n");  
  
// antwort einlesen  
$line = fgets ($fp, 8192);  
$line = trim ($line);  
if (substr ($line, 0, 7) != 'HTTP/1.') {  
  fclose ($fp);  
  // ungültige antwort  
  throw new Exception ("Invalid response: $line");  
}  
if (substr ($line, 9, 3) != '200') {  
  fclose ($fp);  
  // keinr 200er-Antwort, also fehlgeschlagen  
  throw new Exception ("CONNECT failed: $line");  
}  
// solange man keine leerzeile eingelesen hat, einfach neue zeilen  
// einlesen, Leerzeile markiert Ende des HTTP-Headers und danach  
// kann's mit TLS losgehen  
while (trim ($line) != "") {  
  $line = fgets ($fp, 8192);  
}  
$res = stream_socket_enable_crypto ($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);  
if (!$res) {  
  // konnte keinen TLS-Handshake durchführen  
  throw new Exception ("TLS Handshake failed");  
}  
  
// Und JETZT über die Verbindung ganz normal den HTTP-Request absetzen  
// und die Antwort auslesen, so wie vorher  
  
fputs ($fp, "GET / HTTP/1.1\r\n");  
// etc.

-------- schnipp ---------------

Im Falle von einer Klartextverbindung (d.h. **KEIN** SSL/TLS über den Proxy) hättest Du das ganze VIEL einfacher:

Im Klartextfall musst Du Dich nämlich lediglich mit dem Proxy verbinden statt mit dem richtigen Server und den Namen des richtigen Servers in dem Request verarbeiten, d.h.

Vereinfachter voriger Code (Klartext-Fall!):

$fp = fsockopen ('tcp://zielserver.test:80', 0, ...);  
fputs ($fp, "POST /bla HTTP/1.1\r\n");

Vereinfachter neuer Code (Klartext-Fall!):

$fp = fsockopen ('tcp://proxyserver.lan:3128', 0, ...);  
fputs ($fp, "POST http://zielserver.test/bla HTTP/1.1\r\n");

Viele Grüße,
Christian