]> granicus.if.org Git - php/commitdiff
Fix #77423: parse_url() will deliver a wrong host to user PHP-7.2
authorChristoph M. Becker <cmbecker69@gmx.de>
Wed, 13 May 2020 07:36:52 +0000 (09:36 +0200)
committerStanislav Malyshev <stas@php.net>
Sat, 2 Jan 2021 04:08:01 +0000 (20:08 -0800)
To avoid that `parse_url()` returns an erroneous host, which would be
valid for `FILTER_VALIDATE_URL`, we make sure that only userinfo which
is valid according to RFC 3986 is treated as such.

For consistency with the existing url parsing code, we use ctype
functions, although that is not necessarily correct.

ext/standard/tests/strings/url_t.phpt
ext/standard/tests/url/bug77423.phpt [new file with mode: 0644]
ext/standard/tests/url/parse_url_basic_001.phpt
ext/standard/tests/url/parse_url_basic_003.phpt
ext/standard/tests/url/parse_url_basic_005.phpt
ext/standard/tests/url/parse_url_unterminated.phpt
ext/standard/url.c

index 79ff3bc4a8e3df2ba8307627aeed3143d5ff21c3..f564f59f0632226b386265eaa250b83fef730a53 100644 (file)
@@ -575,15 +575,13 @@ $sample_urls = array (
   string(16) "some_page_ref123"
 }
 
---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) {
+--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) {
   ["scheme"]=>
   string(4) "http"
   ["host"]=>
-  string(11) "www.php.net"
+  string(26) "secret@hideout@www.php.net"
   ["port"]=>
   int(80)
-  ["user"]=>
-  string(14) "secret@hideout"
   ["path"]=>
   string(10) "/index.php"
   ["query"]=>
diff --git a/ext/standard/tests/url/bug77423.phpt b/ext/standard/tests/url/bug77423.phpt
new file mode 100644 (file)
index 0000000..be03fe9
--- /dev/null
@@ -0,0 +1,30 @@
+--TEST--
+Bug #77423 (parse_url() will deliver a wrong host to user)
+--FILE--
+<?php
+$urls = array(
+    "http://php.net\@aliyun.com/aaa.do",
+    "https://example.com\uFF03@bing.com",
+);
+foreach ($urls as $url) {
+    var_dump(filter_var($url, FILTER_VALIDATE_URL));
+    var_dump(parse_url($url));
+}
+?>
+--EXPECT--
+bool(false)
+array(3) {
+  ["scheme"]=>
+  string(4) "http"
+  ["host"]=>
+  string(19) "php.net\@aliyun.com"
+  ["path"]=>
+  string(7) "/aaa.do"
+}
+bool(false)
+array(2) {
+  ["scheme"]=>
+  string(5) "https"
+  ["host"]=>
+  string(26) "example.com\uFF03@bing.com"
+}
index 4606849c57817fd33c44077f7093c488b9240e07..51010991326cdd68e281e6bd5c4645b11dd12a58 100644 (file)
@@ -506,15 +506,13 @@ echo "Done";
   string(16) "some_page_ref123"
 }
 
---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) {
+--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) {
   ["scheme"]=>
   string(4) "http"
   ["host"]=>
-  string(11) "www.php.net"
+  string(26) "secret@hideout@www.php.net"
   ["port"]=>
   int(80)
-  ["user"]=>
-  string(14) "secret@hideout"
   ["path"]=>
   string(10) "/index.php"
   ["query"]=>
index 3d5a4a344afdaebe9c37990a1e3a4fe938d239ba..7968fd3f09fdabb6e8f321d921e57b83d2f06a93 100644 (file)
@@ -68,7 +68,7 @@ echo "Done";
 --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(11) "www.php.net"
 --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(11) "www.php.net"
 --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(11) "www.php.net"
---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(11) "www.php.net"
+--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(26) "secret@hideout@www.php.net"
 --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(11) "www.php.net"
 --> nntp://news.php.net   : string(12) "news.php.net"
 --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz   : string(11) "ftp.gnu.org"
index aefb33964bc425c674091e8f0a09bd80b3a20fac..ba778bf9035db920f8a1ef578fff77e256237d74 100644 (file)
@@ -68,7 +68,7 @@ echo "Done";
 --> http://secret:@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(6) "secret"
 --> http://:hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(0) ""
 --> http://secret:hideout@www.php.net/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(6) "secret"
---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(14) "secret@hideout"
+--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : NULL
 --> http://secret:hid:out@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123   : string(6) "secret"
 --> nntp://news.php.net   : NULL
 --> ftp://ftp.gnu.org/gnu/glic/glibc.tar.gz   : NULL
index 912b6a5641e82cdb564b622a31c0cd2e9ef95a24..875d93a109483d624c0294cd6e20502b7265b8ec 100644 (file)
@@ -508,15 +508,13 @@ echo "Done";
   string(16) "some_page_ref123"
 }
 
---> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(7) {
+--> http://secret@hideout@www.php.net:80/index.php?test=1&test2=char&test3=mixesCI#some_page_ref123: array(6) {
   ["scheme"]=>
   string(4) "http"
   ["host"]=>
-  string(11) "www.php.net"
+  string(26) "secret@hideout@www.php.net"
   ["port"]=>
   int(80)
-  ["user"]=>
-  string(14) "secret@hideout"
   ["path"]=>
   string(10) "/index.php"
   ["query"]=>
index 1dd073e2bb423652821f351135b9582d76e175d5..8d155bb9846c97701dee5ac54c7e0bbcc6c84366 100644 (file)
@@ -92,6 +92,22 @@ PHPAPI php_url *php_url_parse(char const *str)
        return php_url_parse_ex(str, strlen(str));
 }
 
+static int is_userinfo_valid(const char *str, size_t len)
+{
+       char *valid = "-._~!$&'()*+,;=:";
+       char *p = str;
+       while (p - str < len) {
+               if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
+                       p++;
+               } else if (*p == '%' && p - str <= len - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
+                       p += 3;
+               } else {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
 /* {{{ php_url_parse
  */
 PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
@@ -235,13 +251,18 @@ PHPAPI php_url *php_url_parse_ex(char const *str, size_t length)
                        ret->pass = estrndup(pp, (p-pp));
                        php_replace_controlchars_ex(ret->pass, (p-pp));
                } else {
+                       if (!is_userinfo_valid(s, p-s)) {
+                               goto check_port;
+                       }
                        ret->user = estrndup(s, (p-s));
                        php_replace_controlchars_ex(ret->user, (p-s));
+
                }
 
                s = p + 1;
        }
 
+check_port:
        /* check for port */
        if (s < ue && *s == '[' && *(e-1) == ']') {
                /* Short circuit portscan,