Wiele osób narzeka na dosyć uciążliwy błąd w skrypcie WordPressa uniemożliwiający wylogowanie się z poprzez kliknięcie odpowiedniego linka w niektórych miejscach strony, takich jak panel administracyjny i formularz dodawania komentarza. Na oficjalnej stronie systemu, tudzież znajdujących się tam forach są pewne informacje na temat problemu, użytkownicy próbują sobie pomóc, jednak skuteczność rozwiązań [mierzona na podstawie wypowiedzi i nastrojów samych zainteresowanych] bynajmniej nie jest stuprocentowa. Nie lubię kiedy jakakolwiek funkcjonalność nie działa, nawet jeśli z niej nie korzystam - postanowiłem więc, że zrobię mały rekonesans, sprawdzę co dolega Wordpressowi i dowiem się jak to naprawić.

Mnie osobiście problem dotyczy jedynie połowicznie, ponieważ sama funkcja nie działa, ale ze względu na to, że bloga piszę wyłącznie na własnym komputerze, ciasteczka pamiętają, że lubię być zalogowany i praktycznie nie korzystam z wylogowywania. Mimo to postaram się Wam pomóc wskazać i naprawić błąd. Do dzieła!

Kilka słów o przyczynie.

Cała historia rozpoczyna się od WordPressa 2.7. W “kodeksie” na jednej ze stron został opisany proces migracji i wymaganych zmian dla wtyczek i szablonów z poprzednich wersji, w którym znajduje się rozdział zatytułowany: “Logout from Site”. Możemy się z niego dowiedzieć, że został zmieniony sposób tworzenia linka kierującego do akcji wylogowania. W nowej wersji wymagany jest parametr “_wpnonce”, zapewniający większe bezpieczeństwo poprzez wprowadzenie “tymczasowości” linka. Aktualny [poprawny] format wygląda następująco [pominąłem opcjonalny parametr “redirect_to”]:
http://[domena bloga]/wp-login.php?action=logout&_wpnonce=[nonce]
Samo słowo “nonce”, a szczególnie wartość tego parametru oznacza w Wordpressie unikalny, [zwykle] dziesięcioznakowy identyfikator, który jest generowany dla każdej sesji [w rozumieniu języka PHP] po to, aby zapobiec atakom typu CSRF / XSRF, właśnie przez fakt, że potencjalny atakujący wie, jaki link należy spreparować, ale [praktycznie] nie jest w stanie zgadnąć wartości samego nonce’a - cały atak skończy się więc na błędzie wykonania. Więcej informacji można znaleźć na odpowiedniej stronie dokumentacji.

Brak parametru nonce lub jego niepoprawna wartość w adresie URL powoduje reakcję obronną skryptu przed potencjalnym atakiem. Wygląda to nastepująco [próba skasowania posta w dziale “Wpisy”, skopiowałem adres URL i zmieniłem dwa znaki w wartości nonce]:

Próba usunięcia wpisu “[nazwa wpisu]” nie powiodła się.
Krótko mówiąc - obrona działa. Nie zmienia to jednak faktu, że w teraz cała defensywa zdaje się być przeciwko nam, dlatego muszę odpowiedzieć na pytanie:

Czy Twój blog wymaga naprawy?

Sposób na sprawdzenie poprawności działania mechanizmu jest bardzo prosty: należy po prostu spróbować wylogować się z serwisu / panelu administracyjnego. Jeśli wszystko jest w porządku [użytkownik został wylogowany i przekierowany do adresu URL pobranego z wartości parametru “redirect_to”], można pominąć lekturę reszty posta [ale nie rób tego, zostań jeszcze chwilę!], ponieważ jesteś szczęśliwym użytkownikiem poprawnie działającego skryptu. W przeciwnym wypadku zostanie pokazana strona o bardzo poważnym na pierwszy rzut oka tytule:
Informacja o niepowodzeniu WordPressa
której treść będzie brzmiała następująco:
Zamierzasz wylogować się z [nazwa bloga]

Proszę spróbować ponownie.

Bez paniki, przynajmniej w tym momencie nie oznacza to, że z naszym skryptem dzieje się coś złego. Jeśli problem wystąpił, mamy dwa wyjścia:

Wstawienie parametru _wpnonce.

Pierwsze rozwiązanie polega na zlikwidowaniu przyczyny problemu [nie ma to jak innowacyjność, co nie? ;]]. Czy Twój link wylogowujący zawiera parametr “_wpnonce”? Jeśli nie, powinieneś sprawdzić, jaki kod odpowiada za jego wyświetlanie. W przypadku, gdy w Twoim odnośniku brakuje parametru z wartością nonce’a, masz dwa wyjścia:
  • samodzielne dodanie go do adresu URL za pomocą funkcji:

wp_nonce_url($actionurl, $action);

Pełna dokumentacja dla powyższej funkcji znajduje się pod tym adresem.

  • lub skorzystanie z gotowej funkcji:

wp_logout_url($redirect);

Pełną dokumentację uzyskamy tutaj. Należy zauważyć, że możemy zrobić bardzo użyteczny “trik”, łącząc wywołanie wp_logout_url(); z wywołaniem funkcji get_permalink(); jako parametrem $redirect:

<?php
echo wp_logout_url(get_permalink());
?>

Zostaniemy wtedy przekierowani z powrotem na aktualną stronę. Oczywiście można tam wstawić dowolny URL, więc jeśli ktoś woli przekierowanie na stronę główną bloga, bądź własny profil na jednym z serwisów społecznościowych, jego sprawa. ;] Nie jest to jednak sposób działający w 100%, więc jeśli nadal nie możesz się wylogować, spójrz na kolejny akapit:

Czy nadal masz problem z wylogowaniem się?

Drugie rozwiązanie zasługuje raczej na miano “obejścia” [nie znam lepszego tłumaczenia słowa “bypass”, jeśli takie znasz, podziel się ;]], ponieważ nie likwiduje problemu, ale pozwala [w 100%] osiągnąć cel, jakim jest poprawne wylogowanie. Należy je zastosować wtedy, kiedy powyższy sposób [dodanie nonce’a] z niewiadomych powodów nie zadziała. [Nie]stety mój przypadek należy właśnie do tej rangi “beznadziejnych”, gdzie dopiero zmiana kodu w rdzeniu Wordpressa mogłaby w jakikolwiek sposób pomóc. Ze względu na to, że nie mam aktualnie czasu na taką zabawę, publikuję rozwiązanie tymczasowe, działające, chociaż trochę… uciążliwe.

Polega ono na tym, że mając już parametr nonce w wylogowującym URLu klikamy w odnośnik, który jak zwykle wyświetla nam błąd. W tym momencie zamiast po raz kolejny narzekać na twórców, szybko klikamy w pasek adresu przeglądarki [użytkownicy Firefoxa mogą posłużyć się skrótem [Ctrl] + [L] - niestety nie wiem, jak to wyglada w innych przeglądarkach, bo nie korzystam ;]] i potwierdzamy [Enter]em nasz niedziałający link. Ku naszemu zdziwieniu zamiast kolejnej “ślepej uliczki” - błędu niepowodzenia - pojawia się inny, bardziej przyjazny komunikat. Tytuł strony nie zmienił się, ale treść i owszem:

Zamierzasz wylogować się z [nazwa bloga]

Czy naprawdę chcesz się wylogować?

Zauważamy istotny postęp i fakt, że słowo “wylogować” w drugiej linijce jest tym samym linkiem wylogowującym… ale z inną wartością parametru nonce! Wygląda na to, że coś musi jednak przeszkadzać Wordpressowi w aktualizowaniu aktualnej wartości tego identyfikatora sesji, niestety nie mogę się tym razem bardziej zagłębić, tak więc tymczasowo trzeba się trochę pomęczyć.

Podsumowanie.

Cóż, jak to bywa w życiu - idealnego rozwiązania, przynajmniej na razie, nie ma. Na forach internetowych niektórzy próbują sugerować, że głównym powodem tego problemu jest jakaś feralna wtyczka, ale moim zdaniem nie ma to nic wspólnego, ponieważ kod produkujący linki zarówno do logowania jak i wylogowania z serwisu opiera się na oryginalnych funkcjach skryptu WordPressa, nie ma tu więc nigdzie miejsca na interakcję z dodatkami. Nie można jednak wykluczyć, że któryś z pluginów lub szablonów na własną rękę “zarządza” wartością nonce’a, wtedy faktycznie byłby to problem, tyle, że nie widzę sensu takiego działania - oczywiście poza celową “destrukcją” pewnych funkcjonalności - tylko, że takie rzeczy są zwykle szybko odkrywane przez użytkowników, vide nie tak dawna sprawa z trojanem w szablonie bloga. Dziękuję za lekturę i do zobaczenia w następnym wpisie!