Fehlersuche ist ätzend. Vor allem, wenn der Fehler partout nicht gefunden werden kann. Bei einem Kunden bin ich letztens sehr lange nicht fündig geworden, bis ich den Schuldigen endlich hatte: die Referrer Policy. Was diese Policy macht, warum das Problem entsteht und wie es gefixt werden kann, erkläre ich in diesem Blogartikel.
Starten wir bei der Erklärung, was die Referrer Policy eigentlich ist. Es handelt sich um einen http-Header (wobei diese Einstellung auch in HTML ausgegeben werden kann), der dem Browser mitteilt, ob der Referrer (also die verweisende Website) übertragen werden darf. Hier die möglichen Einstellungen:
Referrer-Policy: no-referrer
Referrer-Policy: no-referrer-when-downgrade
Referrer-Policy: origin
Referrer-Policy: origin-when-cross-origin
Referrer-Policy: same-origin
Referrer-Policy: strict-origin
Referrer-Policy: strict-origin-when-cross-origin
Referrer-Policy: unsafe-url
Die Übertragung des Referrer kann also komplett deaktiviert werden, oder beim Downgrade (Wechsel von https zu http). Mit „origin
“ ist gemeint, dass nur die Domain übertragen wird, aber nicht der Teil, der danach folgt. Dies kann auch nur dann erfolgen, wenn es einen Wechsel der Domain gab („cross origin
„). Die genauen Definitionen findet ihr bei MDN.
Fun fact: Die fehlerhafte Schreibweise von „Referer“ (mit einem „r“), die einem häufiger mal begegnet, ist tatsächlich auf einen Tippfehler im RFC zurückzuführen … 😅
Was ist jetzt das Problem? In meinem Fall war es das Plugin Ninja Forms. Dieses Formular-Plugin bietet so genannte Merge Tags an, um zum Beispiel die Beitrags-URL oder den Beitragstitel in der E-Mail mitzusenden. Das wollte in meinem Fall einfach nicht klappen. Egal, was ich versuchte. Da mein Fall etwas komplexer war (Benutzerdefinierte Taxonomie und ACF) dachte ich immer an einen Fehler in dieser Kombination. Aber auch in meinen Testcase ging es nicht und da es ja eigentlich funktionieren sollte, schaute ich in mal den Quelltext bei Ninja Forms. Für den Titel und die URL wurde die Post ID genutzt und für die Erkennung dieser ID gab es eine Helfer-Funktion:
protected function post_id()
{
global $post;
if ( is_admin() && defined( 'DOING_AJAX' ) && DOING_AJAX ) {
// If we are doing AJAX, use the referer to get the Post ID.
$post_id = url_to_postid( wp_get_referer() );
} elseif( $post ) {
$post_id = $post->ID;
} else {
return false; // No Post ID found.
}
return $post_id;
}
Im Falle einer Übertragung via AJAX konnte nicht direkt auf die ID zurückgegriffen werden, also wird der Referrer bemüht. Nun hatte ich einen Ansatzpunkt und auch schone eine Befürchtung. Also prüfte ich, was der Referrer denn ausgab. Es war immer die Startseite, egal wo ich war. Okay, Problem bestätigt. Aber warum? Nächster Check, welche Referrer Policy ist denn konfiguriert? Und jetzt wurde es interessant, denn es war strict-origin und die ist wie folgt definiert:
Send only the origin when the protocol security level stays the same (HTTPS→HTTPS). Don’t send the
Referer
header to less secure destinations (HTTPS→HTTP).
Es wurde also immer nur die Domain („origin“) ohne den Pfad übermittelt. Das erklärte, warum ich immer die Startseite als Ergebnis bekommen habe. Nach Umstellung auf „same-origin
“ war das Problem beseitigt. Heureka!
Wer selber schauen möchte, welche Referrer-Policy eingestellt ist, kann dies in den Browser Entwicklertools leicht nachschauen. Einfach im Netzwerk-Tab auf die HTML-Seite gehen:
Und dann die Kopfzeilen/Header anschauen, wo sich die Referrer Policy befindet:
In diesem Fall sehen wir, dass die Wikipedia-Seite den Wert auf „origin
“ setzt.
Noch einfacher ist es auf der Website https://securityheaders.com – die uns noch mehr praktische Tipps gibt und daher ohnehin eine gute Empfehlung ist.
Neben Ninja Forms gibt es in WordPress selbst auch noch mindestens einen anderen Ort, wo auf den Referrer zurückgegriffen wird. Bei der Passwortvergabe auf einer Seite oder einem Beitrag. Kurz nach meinem Kundenproblem mit Ninja Forms stolperte ich im internationalen Slack-Channel #forums über ein Problem mit eben dieser Passwortabfrage.
Grund war in diesem Fall ein komplett leerer Referrer (ausgelöst durch die Referrer Policy „no-referrer
„), die WordPress nicht erwartet und die Passwortübergabe ergebnislos abbricht. Du landest auf der Seite /wp-login.php?action=postpass
, die komplett weiß ist und nicht auf der korrekten Seite. Auch hier ist die Lösung, die Referrer Policy auf einen Wert zu setzen, der (zumindest für same-origin
Requests) den gesamten Pfad zurückgibt, denn sonst funktioniert der Redirect nicht korrekt.
WordPress nutzt nämlich den Weg über die Loginseite, um das Passwort zu prüfen und dann gegebenenfalls den Passwort-Cookie zu setzen. Dieser Sonderweg für Passwortabfragen (statt Login) wird durch den entsprechenden Parameter („postpass
„) gestartet.
Unabhängig von der Referrer Policy kann dieser unerwartete Weg auch noch andere Probleme bereiten. Viele sichern ja den Login extra über einen Basic HTTP Auth ab. Bedenken aber nicht, dass dies dann auch bei einer Passwortabfrage getriggert wird. Wer also seinen Login absichern möchte und Seiten/Beiträge via Passwort absichert, sollte diese Ausnahme mit einbauen:
# Protect wp-login.php without interfering with post/page password protection
<files wp-login.php>
<If "%{QUERY_STRING} != 'action=postpass'">
# Protect wp-login.php
AuthName "Login erforderlich"
AuthType Basic
AuthUserFile /path/to/password-file/.htpasswd
require valid-user
</If>
</files>
Kommen wir nun zu der Lösung und dem „Wie“: Theoretisch könnte WordPress ja die Referrer Policy über das Meta-Tag in HTML selbst bestimmt, aber die Browser werten den http-Header höher ein, so dass dieser Weg nicht wirklich hilft.
Sofern der Webserver Apache ist, kann der Header bestenfalls über die .htaccess
angepasst werden:
<IfModule mod_headers.c>
Header set Referrer-Policy "same-origin"
</IfModule>
Ähnlich simpel soll es für nginx funktionieren (ungetestet):
add_header Referrer-Policy "same-origin";
Eine andere Möglichkeit ist ein kleines PHP-Snippet an geeigneter Stelle:
function add_referrer_policy_header() {
header("Referrer-Policy: same-origin");
}
add_action('send_headers', 'add_referrer_policy_header');
Theoretisch gibt es auch noch Plugins, die das anbieten. Aber ich bin kein Freund von Plugins, die deutlich mehr machen, als ich aktuell möchte und gegebenenfalls auch (aktuell) verstehe. Wer nur diesen Wert ändern möchte, der sollte lieber auch nur das tun und nicht gleich die Kavallerie rufen. Außer, du weißt, was du tust. Und dann findest du die Plugins auch selber … 😉
Kennst du noch mehr Probleme im Zusammenhang mit der Referrer Policy oder die ähnlich fies versteckt sind? Dann ab damit in die Kommentare!
Damit versuche ich mich auch seit einiger Zeit zu beschäftigen, ist aber nicht wirklich nebenbei zu machen 😀
Das W3TC Plugin hat auch diverse Einstellungsmöglichkeiten für alle Security-Headers, da kann man einiges schnell und einfach einstellen … wenn man sich damit auskennt. Ich lerne auch noch 🙂
Danke für den Beitrag hier, hilft mir vielleicht auch weiter.