Archiv für den Monat: Januar 2013

WordPress, SSL und Load-Balancing

WordPress ((http://www.wordpress.org)) ist ein weit verbreitetes Weblog- oder kurz Blog-System ((http://de.wikipedia.org/wiki/Blog)). Einige würden sogar sagen, DAS Blog-System. WordPress als OpenSource-Projekt ((http://de.wikipedia.org/wiki/WordPress)) besticht durch seine Kontinuität und die Möglichkeit zur Implementierung von Plugins und Themes, die zu tausenden schon entstanden und meist frei verfügbar sind. Dieser Blog basiert auch auf WordPress.

Um die technische Kommunikation zwischen dem Browser des Bloggers und der WordPress-Installation auf einem Server zu sichern bedient sich WordPress SSL ((http://de.wikipedia.org/wiki/Transport_Layer_Security)), zu erkennen an dem „https“ in der URL. Ein entsprechend gültiges und auf dem Server installiertes SSL-Zertifikat vorausgesetzt, lässt sich mit folgenden Konfigurationseinstellungen ((http://codex.wordpress.org/Administration_Over_SSL)) eine sichere Verbindung für das Login oder den gesamten Administrationszugang von WordPress erzwingen.

Für ein gesichertes Login:

define('FORCE_SSL_LOGIN', true);

Für den gesicherten Administrationsbereich (schließt Login mit ein):

define('FORCE_SSL_ADMIN', true);

Sind diese Einstellungen in der Konfigurationsdatei wp-config.php gesetzt, „überwacht“ WordPress die eingehenden Anfragen und leitet diese ggf. auf https um (redirect) bzw. wandelt alle angezeigten Links in https-Links um. Diese Funktionalität funktioniert ohne Plugins. Sie ist Bestandteil des WordPress-Core.

Problematisch wird dies, wenn eine WordPress-Installation (zumindest Version 3.1) über einen Load-Balancer ((http://de.wikipedia.org/wiki/Load_Balancer)) ausgeliefert wird, auf dem direkt das SSL-Zertifikat installiert ist und der „nach hinten“ zu den eigentlichen WordPress-Installation (-Servern) nur http spricht. Dann ergibt sich nämlich folgendes Problem einer Totschleife:

  1. wordpress_lb_sslDer Browser fragt per https und landet mit seiner Anfrage beim Load-Balancer.
  2. Dieser gibt die Anfrage per http an eine der parallelen WordPress-Installationen weiter.
  3. Die WordPress-Installation merkt, dass hier nicht per https angefragt wird und „befiehlt“ (redirect) dem Browser auf https anzufragen.
  4. Der Browser fragt per https und … siehe 1.

Damit ist ein per SSL abgesicherter Administrationsbereich von WordPress mit dieser Load-Balancing-Konfiguration nicht zu erreichen.

Die Installation des SSL-Zertifikates auf den einzelnen WordPress-Servern war für uns keine Option, da u.a. die Server einerseits mit verschiedenen anderen Domänen auch per https umgehen müssen und dies ein Wildcard-SSL-Zertifikat voraussetzen würde, welches wir (zumindest zum damaligen Zeitpunkt) nicht erhalten haben. Darüber hinaus hätte dies den Wartungs- und Konfigurationsaufwand der Webserver unverhältnismäßig erhöht. Was also tun?

Mit einem kleinen Eingriff (4 kleine Code-Änderungen in insgesamt 4 Dateien vom WordPress-Core), der im Folgenden beschrieben wird, haben wir das Problem gelöst. Die Idee der Problemlösung ist, dass WordPress zwar alle Links als https anbietet, aber kein Redirect erzwungen wird, wenn doch mal eine Anfrage auf http ankommt.

wp-config.php

Hier kann wahlweise eine der folgenden Konstanten bzw. Einstellungsoptionen definiert werden.

define('USE_SSL_LOGIN', true);
define('USE_SSL_ADMIN', true);

 

wp-includes/functions.php

In die functions.php müssen zwei neue Funktionen an beliebiger Stelle eingefügt werden.

/**
 * Whether SSL login should be used.
 *
 * @since patch 01.11.2010
 *
 * @param string|bool $use Optional.
 * @return bool True if used, false if not used.
 */
function use_ssl_login( $use = null ) {
    static $used = false;

    if ( !is_null( $use ) ) {
        $old_used = $used;
        $used = $use;
        return $old_used;
    }

    return $used;
}

/**
 * Whether to use SSL used for the Administration Panels.
 *
 * @since patch 01.11.2010
 *
 * @param string|bool $use
 * @return bool True if used, false if not used.
 */
function use_ssl_admin( $use = null ) {
    static $used = false;

    if ( !is_null( $use ) ) {
        $old_used = $used;
        $used = $use;
        return $old_used;
    }

    return $used;
}

 

wp-includes/default-constants.php

Hier gilt es die Funktion wp_ssl_constants anzupassen bzw. zu erweitern (siehe hervorgehobenen Bereich).

/**
 * Defines cookie related WordPress constants
 *
 * @since 3.0.0
 */
function wp_ssl_constants( ) {
   /**
    * @since 2.6.0
    */
   if ( !defined('FORCE_SSL_ADMIN') )
      define('FORCE_SSL_ADMIN', false);
   force_ssl_admin(FORCE_SSL_ADMIN);

   /**
    * @since 2.6.0
    */
   if ( !defined('FORCE_SSL_LOGIN') )
      define('FORCE_SSL_LOGIN', false);
   force_ssl_login(FORCE_SSL_LOGIN);

    /**
     * @since patch 01.11.2010
     */
    if ( !defined('USE_SSL_LOGIN') )
        define('USE_SSL_LOGIN', false);
    use_ssl_login(USE_SSL_LOGIN);

    /**
     * @since patch 01.11.2010
     */
    if ( !defined('USE_SSL_ADMIN') )
        define('USE_SSL_ADMIN', false);
    use_ssl_admin(USE_SSL_ADMIN);
}

 

wp-includes/link-template.php

Hier muss die Funktion get_site_url beim ersten IF angepasst werden (siehe hervorgehobenen Bereich).

/**
 * Retrieve the site url for a given site.
 *
 * Returns the 'site_url' option with the appropriate protocol,  'https' if
 * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
 * overridden.
 *
 * @package WordPress
 * @since 3.0.0
 *
 * @param int $blog_id (optional) Blog ID. Defaults to current blog.
 * @param string $path Optional. Path relative to the site url.
 * @param string $scheme Optional. Scheme to give the site url context. Currently 'http','https', 'login', 'login_post', or 'admin'.
 * @return string Site url link with optional path appended.
*/
function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
   // should the list of allowed schemes be maintained elsewhere?
   $orig_scheme = $scheme;
   if ( !in_array( $scheme, array( 'http', 'https' ) ) ) {
      if ( ( 'login_post' == $scheme || 'rpc' == $scheme ) && ( force_ssl_login() || force_ssl_admin() || use_ssl_login() || use_ssl_admin() ) )
         $scheme = 'https';
      elseif ( ( 'login' == $scheme ) && ( force_ssl_admin() || use_ssl_admin() ) )
         $scheme = 'https';
      elseif ( ( 'admin' == $scheme ) && ( force_ssl_admin() || use_ssl_admin() ) )
         $scheme = 'https';
      else
         $scheme = ( is_ssl() ? 'https' : 'http' );
   }

   if ( empty( $blog_id ) || !is_multisite() )
      $url = get_option( 'siteurl' );
   else
      $url = get_blog_option( $blog_id, 'siteurl' );

   if ( 'http' != $scheme )
      $url = str_replace( 'http://', "{$scheme}://", $url );

   if ( !empty( $path ) && is_string( $path ) && strpos( $path, '..' ) === false )
      $url .= '/' . ltrim( $path, '/' );

   return apply_filters( 'site_url', $url, $path, $orig_scheme, $blog_id );
}

Das Problem und die Lösung hab ich (selbstverständlich) als Feature Request und Patch ((http://core.trac.wordpress.org/ticket/15277)) an die WordPress-OpenSource-Entwicklung geschickt.

Achtung: Grundsätzlich öffnet sich hier eine Sicherheitslücke, da WordPress ja trotz „nutze bitte SSL“ auch auf nur http reagiert; wobei der Nutzer selbständig immer das „s“ aus der URL entfernen muss bzw. automatisierte Skripte, die mit der Web-Oberfläche von WordPress arbeiten, ggf. nicht „abhör sicher“ sind. Diesem sollte man sich bewusst sein. In unserer Umgebung kommt diese Lücke nicht zum Tragen, da der Load-Balancer selbst alle http-Anfragen direkt auf https umlenkt.

Adobe Presenter und Microsoft PowerPoint

Mit dem Presenter von Adobe können „hochwertige Adobe Flash- und E-Learning-Inhalte aus PowerPoint-Präsentationen“ ((http://www.adobe.com/de/products/presenter/)) erzeugt werden, wenn man den denn installiert bekommt.

Aktuell (Mitte März 2013) liegt der Presenter in der Version 7 mit 6 Patches vor. Er kann einzeln oder in Bundles bezogen werden. Ich selbst habe den Presenter in der eLearning Suite 2 ((http://www.adobe.com/de/products/elearningsuite/)) von Adobe vorgefunden. Und aktuell sind zwei Probleme bei der Nutzung vom Presenter sehr häufig anzutreffen:

  1. Mit Office 2010 bzw. in PowerPoint 2010 erscheint der Reiter/Tab Presenter nicht, obwohl die Installation vom Presenter ohne Probleme durch lief.
  2. Mit Office 2007 bzw. in PowerPoint 2007 erscheint bei der ersten Nutzung ein Fenster, welches sofort wieder verschwindet. Bei der zweiten Nutzung kommt dann die Fehlermeldung, dass was mit der Lizenz nicht stimmen würde.

Für das Problem Nummer 2 hab ich eine Lösung im Forum von Adobe ((http://forums.adobe.com/message/3655065)) gefunden, die ich hier kurz vorstellen möchte. Doch zunächst zum Problem, welches bei mir auf Win 7 64-bit auf direkter Hardware und auf Win 7 32-bit auf virtualisierter Hardware (WMware Player und Virtual PC) auftrat.

Das sofort verschwindene Fenster ist das Lizenz-Zustimmungsfenster, in dem man eigentlich den Lizenzbedingungen zustimmen soll. Es verschwindet sofort, ohne das es die Chance gibt, dort zu zustimmen, und der Presenter registriert: Lizenz NICHT zu gestimmt. Beim zweiten Aufruf kommt dann auch die logische Fehlermeldung zum Lizenzierungsproblem und der Presenter ist nicht zu benutzen. Wie nun also das Problem lösen?

Ein findiger User ((http://forums.adobe.com/message/3655065)) hat das Lizenzierungsfenster als HTML-Seite auf der Festplatte lokalisiert und dieses durch eine kurze HTML-Seite ausgetauscht, die automatisch den Lizenzbedingungen zustimmt. Voilà, der Presenter ist benutzbar. Hier der Work-a-round im einzelnen:

  1. Frische Installation vom Presenter.
  2. Austausch der Datei: C:\Program Files (x86)\Adobe\Presenter 7\adobe_epic\eula\install.html durch eine Datei install.html mit folgenden Inhalt.
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    <title>License Agreement</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link href="./../default.css" rel="stylesheet" type="text/css">
    <script language="javascript" src="./../domutils.js"></script>
    <script language="javascript" src="./../wizardcore.js"></script>
    </head>
    
    <body onload="doAccept()" background="./../background.png">
    
    </body>
    </html>
  3. Aufruf des Presenters in PowerPoint 2007.

Die ebenfalls in dem Forum ((http://forums.adobe.com/message/3655065)) vorgeschlagene Lösung, die cache.db zu entfernen hat bei mir nicht funktioniert und nur dazugeführt, dass ich den Lizenz-Key für den Presenter eingeben sollte. An dieser Stelle wird aber nicht der Lizenz-Key der eLearning Suite 2 akzeptiert, obwohl der Presenter ja im meinem Fall als Teil der Suite mitgekommen ist. So konnte ich nur die Nutzung als Test-Installation auswählen und musste den Presenter anschließend noch einmal von der original eLearning Suite 2 Installation „drüber installieren“.