Ausgangslage

Im Intranet einer Bildungseinrichtung wird auf dem Web-Server srv.org.local die Lernplattform Moodle betrieben. Interne Web-Browser erreichen Moodle unter der URL http://srv.org.local/moodle/ im lokalen Netzwerk.

Externe Web-Browser müssen sich zunächst auf dem SSL-Proxy erfolgreich authentifizieren und können dann über eine verschlüsselte Verbindung auf Moodle zugreifen. Im vorliegenden Fall würde sich die URL wie folgt aus dem Namen der beteiligten Server zusammen setzen: https://prx.sec.inet/go/http://srv.org.local/moodle/

Abbildung der Netzwerkstruktur:
Abbildung der Netzwerkstruktur

Gegenüber dem Web-Server tritt der SSL-Proxy als Client auf, gegenüber dem externen Web-Browser vertritt er die Rolle des Web-Servers. Dabei muss er URLs im HTML-Quelltext der Seiten automatisch angepassen, da im Internet außerhalb des lokalen Netzwerkes Adressen der Form http://srv.org.local/... nicht funktionieren.

Problemsituation

Betrachten wir zwei stark gekürzte Auszüge aus HTML-Quelltexten, zunächst die eines internen Web-Browsers und danach die eines externen Web-Browsers.

 1: <html>
 2:  <head>
 3:   <script type="text/javascript" src="http://srv.org.local/moodle/..."></script>
 4:   <link rel="stylesheet" type="text/css" href="http://srv.org.local/moodle/..." />
 5:   <script type="text/javascript">
 6:    //<![CDATA[
 7:     M.yui.loader = {"base":"http:\/\/srv.org.local\/moodle\/..."};
 8:    //]]>
 9:   </script>
10:  </head>
11:  <body>
12:   <form action="http://srv.org.local/moodle/..." method="post">
13:    <input name="url" type="hidden" value="http://srv.org.local/moodle/..." />
14:    <img src="http://srv.org.local/moodle/..." />
15:   </form>
16:  </body>
17: </html>
			  

 1: <html>
 2:  <head>
 3:   <script type="text/javascript" src="http://prx.sec.inet/go/http://srv.org.local/moodle/..."></script>
 4:   <link rel="stylesheet" type="text/css" href="http://prx.sec.inet/go/http://srv.org.local/moodle/..." />
 5:   <script type="text/javascript">
 6:    //<![CDATA[
 7:     M.yui.loader = {"base":"http:\/\/srv.org.local\/moodle\/..."};
 8:    //]]>
 9:   </script>
10:  </head>
11:  <body>
12:   <form action="http://prx.sec.inet/go/http://srv.org.local/moodle/..." method="post">
13:    <input name="url" type="hidden" value="http://srv.org.local/moodle/..." />
14:    <img src="http://prx.sec.inet/go/http://srv.org.local/moodle/..." />
15:   </form>
16:  </body>
17: </html>
			  

Problematisch sind die Zeilen 7 und 13. Hier wurden vom SSL-Proxy die URLs nicht korrekt angepasst. Dass führt dazu, dass beim externen Zugriff der Funktionsumfang von Moodle nur sehr eingeschränkt genutzt werden kann. Vor allem die an den externen Web-Browser ausgelieferten Javascript-Routinen arbeiten wegen unpassender absoluter URLs nicht korrekt.

Problembehebung

Im an den externen Web-Browser ausgelieferten HTML-Quelltext müssen alle URLs angepasst werden, sowohl im Javascript-Code wie in Zeile 7 als auch in besonderen Attributen wie in Zeile 13. Im Prinzip kann die erforderliche Anpassung entweder am SSL-Proxy oder am Web-Server vorgenommen werden. Hier soll der Web-Server angepasst werden.

Schritt 1: Clientidentifizierung

Die Konfiguration des Apache-Servers wird ergänzt, damit die Verbindungsaufnahme über den SSL-Proxy erkannt werden kann. Die Erkennung erfolgt anhand der Adresse des Proxy-Servers im lokalen Netzwerk. Falls der SSL-Proxy als Quasi-Client auftritt, wird die Umgebungsvariable viaproxy auf 1 gesetzt. Der Eintrag kann in der zentralen Konfigurationsdatei httpd.conf erfolgen.

<IfModule setenvif_module>
    SetEnvIfNoCase Remote_Addr "10\.1\.1\.5" viaproxy
</IfModule>
              

Schritt 2: PHP-Script erstellen

Das Problem mit absoluten URL-Pfaden tritt nur in den Seiten auf, die vom PHP-Code der Anwendung Moodle erzeugt werden. Daher stützt sich die Problembehebung ebenfalls auf PHP. Alle absoluten URLs werden angepasst mit Ausnahme solcher, die vom SSL-Proxy ohnehin korrekt gehandhabt werden.

Script auto_prepend.php
<?php
// URL-Filterfunktion einrichten
function local_sslproxy_callback($buffer1) 
{
  static $search1 = array(
    'http:\\/\\/srv.org.local\\/',
	'http://srv.org.local/'
  );
  static $replace1 = array(
    'https:\\/\\/prx.sec.inet\\/go\\/http:\\/\\/srv.org.local\\/',
	'https://prx.sec.inet/go/http://srv.org.local/'
  );
  static $search2 = array(
    'src="https://prx.sec.inet/go/',
    'href="https://prx.sec.inet/go/',
    'action="https://prx.sec.inet/go/'
  );
  static $replace2 = array(
    'src="',
    'href="',
    'action="'
  );
  $buffer2 = str_replace($search1, $replace1, $buffer1);
  return (str_replace($search2, $replace2, $buffer2));
}

// URL-Filterfunktion anwenden, wenn Zugriff per SSL-Proxy erfolgt
if ( $_SERVER['viaproxy'] ) { 
  define("LOCAL_CALLBACK_FUNCTION", 1);
  ob_start("local_sslproxy_callback", 2048);
} else {
  define("LOCAL_CALLBACK_FUNCTION", 0);
}
?>
              
Script auto_append.php
<?php
// Filtervorgang bei Bedarf abschliessen
if ( LOCAL_CALLBACK_FUNCTION ) ob_end_flush();
?>			
              

Schritt 3: PHP-Script aktivieren

Die Konfiguration des Apache-Servers wird ergänzt, damit die zuvor definierte Filterfunktion auf alle Ausgaben von Moodle angewendet werden.

<Directory "D:/apm/htdocs/moodle">
    <IfModule php5_module>
      php_admin_value auto_append_file "D:\apm\php5\local\auto_append.php"
      php_admin_value auto_prepend_file "D:\apm\php5\local\auto_prepend.php"
    </IfModule>
</Directory>
              

Im Anschluss an die Änderungen muss natürlich der HTTP-Server Apache neu gestartet werden.

Die vorgenommenen Änderungen wirken sich auf alle Inhalte aus, die PHP im Rahmen der Lernplattform Moodle erzeugt, also nicht nur auf HTML-Seiten, sondern auch auf Javascript-Code und JSON-Daten.

Schritt 4: Ergebniskontrolle

Im letzten Schritt müssen die vorgenommenen Änderungen auf ihre Wirksamkeit überprüft werden. Zunächst empfiehlt sich ein Blick in den HTML-Quelltext auf einem externen Web-Browser. Die Problemzeilen 7 bzw. 13 sollten jetzt anders aussehen.

    ...
 7:     M.yui.loader = {"base":"http:\/\/prx.sec.inet\/go\/http:\/\/srv.org.local\/moodle\/..."};
    ...
13:    <input name="url" type="hidden" value="http://prx.sec.inet/go/http://srv.org.local/moodle/..." />
    ...
			  

Danach sollten die Funktionen von Moodle praktisch ausprobiert werden, z.B. durch einen Datei-Upload. Zuvor sollte der Cache-Speicher des Web-Browsers bereinigt werden, sonst bleiben noch für eine gewisse Zeit die Probleme durch nicht angepasste URLs bestehen. Das gilt entsprechend, wenn der SSL-Proxy ebenfalls Inhalte zwischenspeichern sollte.


Moodle-Optionen

Moodle kann auch so konfiguriert werden, dass die Lernplattform hinter einem Reverse-Proxy bzw. einem SSL-Proxy arbeitet. Dies hilft beim vorliegenden Problem aber nicht weiter, da eine simultane Nutzung der selben Lernplattform sowohl im lokalen Netzwerk als auch im Internet per Proxy-Server in den Konfigurationsoptionen nicht vorgesehen ist.

Apache-Filter

Statt den Ausgabe-Filter mit PHP zu realieren, könnte man diese Aufgabe auch Apache überlassen. In diesem Fall konnte eine auf Proxy-Verbindungen beschränkte Filterung mit dem Apache-Modul mod_ext_filter und dem externen Programm sed nicht störungsfrei zum Laufen gebracht werden.