WordPress Sicherheit neu definiert?

Eine umfassendes umdenken für Plugin-Entwickler

Als Idee für mehr WordPress Sicherheit?

WordPress ist eines der beliebtesten Content-Management-Systeme der Welt, das von Millionen von Menschen genutzt wird. Doch trotz seiner Popularität gibt es immer noch Sicherheitsbedenken, die viele Entwickler und Website-Besitzer beschäftigen. Aus diesem Grund ist es entscheidend, dass Plugins und Erweiterungen für WordPress nach den höchsten Sicherheitsstandards entwickelt werden.

Als WordPress-Entwickler habe ich mich aus diesem Grund auf die Entwicklung einer neuen Boilerplate spezialisiert, die auf den neuesten Sicherheitsstandards basiert und es Plugin-Entwicklern ermöglicht, sicherere und qualitativ hochwertige Plugins zu erstellen. In diesem Artikel werde ich Ihnen diese neue Boilerplate näher bringen und Ihnen zeigen, wie Sie diese verwenden können, um die Sicherheit Ihrer WordPress-Webseite zu erhöhen.

Demo Plugin “Hello World PDO Shortcode”

<?php
/**
 * Plugin Name: Hello World PDO Shortcode
 * Plugin URI: https://wordpress-webmaster.de
 * Description: A simple shortcode that outputs "Hello World" using PDO and prepared statements.
 * Version: 1.0
 * Author: Volkan Sah
 * Author URI: https://wordpress-webmaster.de
 */
class HelloWorldPDO {
	protected $pdo;
	public function __construct() {
		try {
			$this->pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASSWORD);
			$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		} catch (PDOException $e) {
			die("Connection failed: " . $e->getMessage());
		}
		$this->add_shortcodes();
	}
	private function add_shortcodes() {
		add_shortcode( 'hello-world', array( $this, 'hello_world_shortcode' ) );
	}
	public function hello_world_shortcode( $atts ) {
		$stmt = $this->pdo->prepare( "SELECT 'Hello World' AS message" );
		$stmt->execute();
		$result = $stmt->fetch();
		return $result['message'];
	}
}
new HelloWorldPDO();

Wenn ein Entwickler PDO und prepared statements nutzt, sollte er in erster Linie darauf achten, dass alle Datenbankanfragen durch diese Mechanismen abgesichert werden. Das bedeutet, dass alle Anfragen, die Benutzereingaben enthalten, mit prepare und bindParam ausgestattet sein sollten, um SQL-Injections zu vermeiden.

In unserem Hello World Plugin Beispiel haben wir gezeigt, wie man eine PDO-Verbindung aufbaut und eine vorbereitete Abfrage durchführt, um eine einfache Ausgabe zu erzeugen. Dabei haben wir auch darauf geachtet, dass alle Benutzereingaben vorher validiert werden, um eine sichere Verwendung in der Abfrage zu gewährleisten.

Für eine weitere praktische Anwendung zeigen wir Ihnen anhand der ad_action Funktion, wie man mit PDO und prepared statements umgeht. Statt dem normalen add_action verwenden wir eine preparete PDO-Anfrage, um die Hook-Action zu registrieren. Hier ist ein Beispielcode:

public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1) {
    global $wpdb;
    $table_name = $wpdb->prefix . 'my_custom_table';
    $stmt = $this->pdo->prepare("INSERT INTO $table_name (hook, component, callback, priority, accepted_args) VALUES (?, ?, ?, ?, ?)");
    $stmt->bindParam(1, $hook);
    $stmt->bindParam(2, $component);
    $stmt->bindParam(3, $callback);
    $stmt->bindParam(4, $priority);
    $stmt->bindParam(5, $accepted_args);
    $stmt->execute();
}

Wie Sie sehen können, binden wir die Parameter direkt an die vorbereitete Anfrage und führen sie aus. Dies stellt sicher, dass alle Benutzereingaben ordnungsgemäß validiert und gesichert sind und SQL-Injection-Angriffe vermieden werden.

Neben der Erhöhung der Sicherheit gibt es noch weitere Vorteile bei der Verwendung von PDO und Prepared Statements. Ein wichtiger Aspekt ist die Performance. Im Vergleich zu den veralteten MySQL-Methoden kann die Verwendung von PDO und Prepared Statements dazu führen, dass Datenbankabfragen schneller ausgeführt werden. Zudem sind diese Methoden auch benutzerfreundlicher, da sie beispielsweise automatisch Datentypen korrekt behandeln und SQL-Injection-Angriffe verhindern.

Beispiel:

Dieser Code blockiert beispielsweise die Ausgabe von Query-Strings in statischen Ressourcen und aktiviert GZIP-Komprimierung, um die Ladegeschwindigkeit von WordPress-Webseiten zu verbessern.

// Enable GZIP compression
if ( ! ini_get( 'zlib.output_compression' ) ) {
  add_action( 'init', function() {
    ob_start( 'ob_gzhandler' );
  } );
}
// Remove query strings from static resources
add_filter( 'script_loader_src', function( $src ) {
  if ( strpos( $src, '?ver=' ) ) {
    $src = remove_query_arg( 'ver', $src );
  }
  return $src;
} );
add_filter( 'style_loader_src', function( $src ) {
  if ( strpos( $src, '?ver=' ) ) {
    $src = remove_query_arg( 'ver', $src );
  }
  return $src;
} );

Ein weiterer Vorteil ist die Möglichkeit, Datenbanken schneller zu wechseln. Wenn ein Entwickler seine Datenbank von MySQL auf eine andere Datenbank wie PostgreSQL oder SQLite ändern möchte, ist dies mit PDO wesentlich einfacher, da PDO eine einheitliche Schnittstelle für die Verbindung zu verschiedenen Datenbanken bietet. Somit kann der Entwickler seine bestehende Codebasis relativ einfach an die neue Datenbank anpassen.

Beispiel:

In diesem Beispiel wird eine Verbindung zu MySQL, PostgreSQL und SQLite-Datenbanken hergestellt und eine Query ausgeführt, um alle Benutzer aus der Tabelle “users” abzurufen. Durch die Verwendung von PDO wird die Verwendung einer einheitlichen Schnittstelle ermöglicht, was es dem Entwickler erleichtert, zwischen verschiedenen Datenbanken zu wechseln.

try {
    // Verbindung zu MySQL-Datenbank mit PDO
    $pdo_mysql = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASS);
    
    // Verbindung zu PostgreSQL-Datenbank mit PDO
    $pdo_pgsql = new PDO("pgsql:host=" . DB_HOST . ";port=5432;dbname=" . DB_NAME, DB_USER, DB_PASS);
    
    // Verbindung zu SQLite-Datenbank mit PDO
    $pdo_sqlite = new PDO("sqlite:/path/to/database.db");
    // Query an MySQL-Datenbank ausführen
    $stmt_mysql = $pdo_mysql->query("SELECT * FROM users");
    $result_mysql = $stmt_mysql->fetchAll(PDO::FETCH_ASSOC);
    
    // Query an PostgreSQL-Datenbank ausführen
    $stmt_pgsql = $pdo_pgsql->query("SELECT * FROM users");
    $result_pgsql = $stmt_pgsql->fetchAll(PDO::FETCH_ASSOC);
    // Query an SQLite-Datenbank ausführen
    $stmt_sqlite = $pdo_sqlite->query("SELECT * FROM users");
    $result_sqlite = $stmt_sqlite->fetchAll(PDO::FETCH_ASSOC);
    
    // Ergebnisse ausgeben
    var_dump($result_mysql);
    var_dump($result_pgsql);
    var_dump($result_sqlite);
    
} catch (PDOException $e) {
    die("Connection failed: " . $e->getMessage());
}

Zusammenfassend lässt sich sagen, dass die Verwendung von PDO und Prepared Statements eine effektive Methode ist, um die Sicherheit und Performance von WordPress-Plugins und -Webseiten zu verbessern. Durch die Nutzung einer einheitlichen Schnittstelle ist es auch einfacher, auf verschiedene Datenbanken umzusteigen und den Code an neue Anforderungen anzupassen. Wir hoffen, dass dieser Artikel Ihnen dabei geholfen hat, die Vorteile von PDO und Prepared Statements besser zu verstehen und zukünftig sicherere und leistungsstärkere WordPress-Lösungen zu entwickeln. Ich würde mich über Feedback in den Kommentaren sehr freuen und hoffe auf Vorschläge für eine neue Idee.

Autor: Volkan Sah