Aktualizacja XenForo 2.2.17 (poprawka bezpieczeństwa)

dave

Członek ekipy
Witam,

W ubiegły piątek pojawiła się ważna aktualizacja bezpieczeństwa dla XenForo 2.2.x oznaczona 2.2.17. Wersje od 2.3.1 włącznie, nie wymagają tej poprawki.

Poprawka omawiana w tym wątku jest ważna i zalecana, ponieważ eliminuje lukę bezpieczeństwa, dzięki której można w bardzo zły sposób wykorzystać przekierowanie forum preparując konkretny adres URL.

Poprawkę można zainstalować za pomocą panelu administratora lub też ręcznie. Oto wskazówki:

1) Otwórz plik src/XF/App.php i wyszukaj następującą funkcję. Jej początek powinien wyglądać w taki sposób:

PHP:
    public function getDynamicRedirect($fallbackUrl = null, $useReferrer = true)

2) Odszukaj jej zakończenie, które wygląda tak:

PHP:
return $fallbackUrl;
    }

Usuń wszystko, co dotyczy powyższej funkcji, a więc początek, jej rozwinięcie, łącznie z zakończeniem, a następnie wklej następujący kod:

PHP:
    public function getDynamicRedirect($fallbackUrl = null, $useReferrer = true)
    {
        if ($fallbackUrl === null)
        {
            $fallbackUrl = $this->router()->buildLink('index');
        }

        $request = $this->request();
        $fallbackUrl = $request->convertToAbsoluteUri($fallbackUrl);

        $redirect = $request->filter('_xfRedirect', 'str');
        if (!$redirect && $useReferrer)
        {
            $redirect = $request->getServer('HTTP_X_AJAX_REFERER')
                ?: $request->getReferrer();
        }

        if (!$redirect || !preg_match('/./su', $redirect))
        {
            // no redirect provided
            return $fallbackUrl;
        }

        if (
            strpos($redirect, "\n") !== false ||
            strpos($redirect, "\r") !== false ||
            strpos($redirect, '@') !== false
        )
        {
            // redirect contained newlines or user/pass
            return $fallbackUrl;
        }

        $fullRedirect = $request->convertToAbsoluteUri($redirect);
        $redirectParts = @parse_url($fullRedirect);
        $redirectHost = $redirectParts['host'] ?? null;
        if (!$redirectHost)
        {
            // no redirect host
            return $fallbackUrl;
        }

        $requestParts = @parse_url($request->getFullBasePath());
        $requestHost = $requestParts['host'] ?? null;
        if ($redirectHost !== $requestHost)
        {
            // redirect host did not match request host
            return $fallbackUrl;
        }

        return $fullRedirect;
    }

Twórcy XenForo polecają również metodę diff-to-patch:

Diff:
Index: src/XF/App.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/XF/App.php b/src/XF/App.php
--- a/src/XF/App.php    (revision 7f4538e8ad4a572dcff3e0416b56906ec84a53eb)
+++ b/src/XF/App.php    (revision 5a8b3ebd97eae9bc82d4f6aac5f17012d27b0043)
@@ -2305,50 +2305,85 @@
         return '__' . $hash;
     }
 
+    /**
+     * @param string|null $fallbackUrl
+     * @param bool $useReferrer
+     *
+     * @return string
+     */
     public function getDynamicRedirect($fallbackUrl = null, $useReferrer = true)
     {
+        if ($fallbackUrl === null)
+        {
+            $fallbackUrl = $this->router()->buildLink('index');
+        }
+
         $request = $this->request();
+        $fallbackUrl = $request->convertToAbsoluteUri($fallbackUrl);
 
         $redirect = $request->filter('_xfRedirect', 'str');
         if (!$redirect && $useReferrer)
         {
-            $redirect = $request->getServer('HTTP_X_AJAX_REFERER');
-            if (!$redirect)
-            {
-                $redirect = $request->getReferrer();
-            }
+            $redirect = $request->getServer('HTTP_X_AJAX_REFERER')
+                ?: $request->getReferrer();
+        }
+
+        if (!$redirect || !preg_match('/./su', $redirect))
+        {
+            // no redirect provided
+            return $fallbackUrl;
         }
 
-        if ($redirect && preg_match('/./su', $redirect))
+        if (
+            strpos($redirect, "\n") !== false ||
+            strpos($redirect, "\r") !== false ||
+            strpos($redirect, '@') !== false
+        )
         {
-            if (strpos($redirect, "\n") === false && strpos($redirect, "\r") === false)
-            {
-                $fullBasePath = $request->getFullBasePath();
+            // redirect contained newlines or user/pass
+            return $fallbackUrl;
+        }
 
-                $fullRedirect = $request->convertToAbsoluteUri($redirect);
-                $redirectParts = @parse_url($fullRedirect);
-                if ($redirectParts && !empty($redirectParts['host']))
-                {
-                    $pageParts = @parse_url($fullBasePath);
+        $fullRedirect = $request->convertToAbsoluteUri($redirect);
+        $redirectParts = @parse_url($fullRedirect);
+        $redirectHost = $redirectParts['host'] ?? null;
+        if (!$redirectHost)
+        {
+            // no redirect host
+            return $fallbackUrl;
+        }
 
-                    if ($pageParts && !empty($pageParts['host']) && $pageParts['host'] == $redirectParts['host'])
-                    {
-                        return $fullRedirect;
-                    }
-                }
-            }
-        }
+        $requestParts = @parse_url($request->getFullBasePath());
+        $requestHost = $requestParts['host'] ?? null;
+        if ($redirectHost !== $requestHost)
+        {
+            // redirect host did not match request host
+            return $fallbackUrl;
+        }
+
+        return $fullRedirect;
+    }
 
-        if ($fallbackUrl === null)
+    /**
+     * @param string $notUrl
+     * @param string|null $fallbackUrl
+     * @param bool $useReferrer
+     *
+     * @return string
+     */
+    public function getDynamicRedirectIfNot(
+        $notUrl,
+        $fallbackUrl = null,
+        $useReferrer = true
+    )
+    {
+        if ($fallbackUrl === false)
         {
             $fallbackUrl = $this->router()->buildLink('index');
         }
-        return $fallbackUrl;
-    }
 
-    public function getDynamicRedirectIfNot($notUrl, $fallbackUrl = null, $useReferrer = true)
-    {
         $request = $this->request();
+        $fallbackUrl = $request->convertToAbsoluteUri($fallbackUrl);
 
         $redirect = $this->getDynamicRedirect($fallbackUrl, $useReferrer);
         $notUrl = $request->convertToAbsoluteUri($notUrl);
@@ -2356,17 +2391,10 @@
         if (strpos($redirect, $notUrl) === 0)
         {
             // the URL we can't redirect to is at the start
-            if ($fallbackUrl === false)
-            {
-                $fallbackUrl = $this->router()->buildLink('index');
-            }
+            return $fallbackUrl;
+        }
 
-            return $request->convertToAbsoluteUri($fallbackUrl);
-        }
-        else
-        {
-            return $redirect;
-        }
+        return $redirect;
     }
 
     public function applyExternalDataUrl($externalPath, $canonical = false)

Proszę pamiętać, że ręczne zastosowanie poprawki spowoduje, że pliki XenForo utracą kompatybilność z aktualnie używaną przez Ciebie wersją, kiedy funkcja "sprawdzanie spójności plików" zostanie uruchomiona. Fakt ten jest najzupełniej normalny. :)
 
Powrót
Góra