Make the URL filter a bit more lenient
authorAlexander Ebert <ebert@woltlab.com>
Thu, 13 Jun 2024 12:25:25 +0000 (14:25 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Thu, 13 Jun 2024 12:25:25 +0000 (14:25 +0200)
See https://www.woltlab.com/community/thread/305951-link-umwandlung-funktioniert-nicht-wenn-protokoll-im-text-steht/

wcfsetup/install/files/lib/system/html/output/node/HtmlOutputNodeA.class.php

index e33f93706c1c82bbaff275af825cc17b000901b0..47eaf3d6eddb0ca8e600aef1d369350cc81e55e3 100644 (file)
@@ -160,10 +160,38 @@ class HtmlOutputNodeA extends AbstractHtmlOutputNode
      */
     private function isSuspiciousValue(string $value, UriInterface $href): bool
     {
-        if (!\preg_match(FileUtil::LINK_REGEX, $value)) {
+        $regexMatches = \preg_match(FileUtil::LINK_REGEX, $value, $matches);
+        if (!$regexMatches) {
             return false;
         }
 
+        // The match can occur somewhere inside the value, therefore we need to
+        // verify that the value contains substantially more than just the link.
+        $testValue = StringUtil::trim($value);
+        $position = \mb_strpos($testValue, $matches[0]);
+        if ($position !== false) {
+            $testValue = \mb_substr($testValue, 0, $position) . \mb_substr($testValue, $position + \mb_strlen($matches[0]));
+            if ($testValue !== '') {
+                // Allow the value if the remaining string contains characters
+                // equal or greather than 10% of the length of the URL itself.
+                //
+                // The motivation behind this is to prevent a bad actor from
+                // sneaking in a few padding characters to masquerade the URL
+                // which could still look like part of the URL to the untrained
+                // eye.
+                //
+                // The minimum required characters is set to 10 to avoid short
+                // URLs being used to bypass this check.
+                $threshold = \max(
+                    \mb_strlen($matches[0]) * 0.1,
+                    10,
+                );
+                if (\mb_strlen($testValue) >= $threshold) {
+                    return false;
+                }
+            }
+        }
+
         try {
             $value = new Uri($value);
         } catch (MalformedUriException) {