Просмотр исходного кода

Reject userinfo and backslashes in a URL authority

parse_url took http://user@evil.com/ for the host "user@evil.com", where
parsers that honour userinfo, or read a backslash as '/', see evil.com.
userinfo is not supported, so reject both.
yhirose 4 дней назад
Родитель
Сommit
aaccde2122
2 измененных файлов с 14 добавлено и 5 удалено
  1. 6 0
      httplib.h
  2. 8 5
      test/test.cc

+ 6 - 0
httplib.h

@@ -889,6 +889,12 @@ inline bool parse_url(const std::string &url, UrlComponents &uc) {
   auto has_authority = has_authority_prefix || (!url.empty() && url[0] != '/' &&
                                                 url[0] != '?' && url[0] != '#');
   if (has_authority) {
+    // userinfo is not supported, and a backslash that some parsers take for
+    // '/' would leave them seeing another host than this one.
+    if (url.find_first_of("@\\", pos) < url.find_first_of("/?#", pos)) {
+      return false;
+    }
+
     if (pos < url.size() && url[pos] == '[') {
       auto close = url.find(']', pos);
       if (close == std::string::npos) { return false; }

+ 8 - 5
test/test.cc

@@ -19498,11 +19498,14 @@ TEST(ParseUrlTest, FragmentHandling) {
 }
 
 TEST(ParseUrlTest, UserinfoHandling) {
-  // Userinfo with @ but no colon — host includes @
-  detail::UrlComponents uc;
-  ASSERT_TRUE(detail::parse_url("http://user@host.com/path", uc));
-  EXPECT_EQ("user@host.com", uc.host);
-  EXPECT_EQ("/path", uc.path);
+  // userinfo is not supported. Parsers that honour it, or take a backslash for
+  // '/', would see evil.com where the host used to be the whole authority.
+  const char *urls[] = {"http://user@evil.com/", "http://user:pass@evil.com/",
+                        "http://evil.com\\@good.com/", "//user@evil.com/x"};
+  for (auto url : urls) {
+    detail::UrlComponents uc;
+    EXPECT_FALSE(detail::parse_url(url, uc)) << url;
+  }
 }
 
 TEST(ParseUrlTest, IPv6EdgeCases) {