You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2015/12/21 20:45:03 UTC

[12/16] trafficserver git commit: TS-4043: Prevent bogus FQDN characters in host header This close #356.

TS-4043: Prevent bogus FQDN characters in host header
This close #356.

Validate the host header string to prevent malformed hostnames from being let in.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/ada9752e
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/ada9752e
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/ada9752e

Branch: refs/heads/6.1.x
Commit: ada9752e7224abc7f8a231d57d32f84163726b3c
Parents: d64434e
Author: Daniel Xu <dl...@yahoo.com>
Authored: Mon Nov 23 20:35:41 2015 +0000
Committer: Alan M. Carroll <am...@apache.org>
Committed: Fri Dec 18 16:36:48 2015 -0600

----------------------------------------------------------------------
 proxy/hdrs/HTTP.cc | 68 +++++++++++++++++++++++++++++++++++++++++++++++--
 proxy/hdrs/HTTP.h  |  2 ++
 2 files changed, 68 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ada9752e/proxy/hdrs/HTTP.cc
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HTTP.cc b/proxy/hdrs/HTTP.cc
index 46bc135..2e852fd 100644
--- a/proxy/hdrs/HTTP.cc
+++ b/proxy/hdrs/HTTP.cc
@@ -23,7 +23,6 @@
 
 #include "ts/ink_defs.h"
 #include "ts/ink_platform.h"
-#include "ts/TsBuffer.h"
 #include "ts/ink_inet.h"
 #include <assert.h>
 #include <stdio.h>
@@ -161,6 +160,15 @@ is_digit(char c)
   return ((c <= '9') && (c >= '0'));
 }
 
+// test to see if a character is a valid character for a host in a URI according to
+// RFC 3986 and RFC 1034
+inline static int
+is_host_char(char c)
+{
+  return (ParseRules::is_alnum(c) || (c == '-') || (c == '.') || (c == '[') || (c == ']') || (c == '_') || (c == ':') ||
+          (c == '~') || (c == '%'));
+}
+
 /***********************************************************************
  *                                                                     *
  *                         M A I N    C O D E                          *
@@ -1107,6 +1115,18 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
   return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
 }
 
+// Checks if `addr` is a valid FQDN string
+bool
+validate_host_name(ts::ConstBuffer addr)
+{
+  while (addr) {
+    if (!(is_host_char(*addr)))
+      return false;
+    ++addr;
+  }
+  return true;
+}
+
 MIMEParseResult
 validate_hdr_host(HTTPHdrImpl *hh)
 {
@@ -1124,9 +1144,11 @@ validate_hdr_host(HTTPHdrImpl *hh)
           if (port.size() > 5)
             return PARSE_ERROR;
           int port_i = ink_atoi(port.data(), port.size());
-          if (port.size() > 5 || port_i >= 65536 || port_i <= 0)
+          if (port_i >= 65536 || port_i <= 0)
             return PARSE_ERROR;
         }
+        if (!validate_host_name(addr))
+          return PARSE_ERROR;
         while (rest && PARSE_DONE == ret) {
           if (!ParseRules::is_ws(*rest))
             return PARSE_ERROR;
@@ -2188,3 +2210,45 @@ HTTPInfo::push_frag_offset(FragOffset offset)
 
   m_alt->m_frag_offsets[m_alt->m_frag_offset_count++] = offset;
 }
+
+
+/*-------------------------------------------------------------------------
+ * Regression tests
+  -------------------------------------------------------------------------*/
+#if TS_HAS_TESTS
+#include "ts/TestBox.h"
+
+const static struct {
+  const char *const text;
+  bool valid;
+} http_validate_hdr_field_test_case[] = {{"yahoo", true},
+                                         {"yahoo.com", true},
+                                         {"yahoo.wow.com", true},
+                                         {"yahoo.wow.much.amaze.com", true},
+                                         {"209.131.52.50", true},
+                                         {"192.168.0.1", true},
+                                         {"localhost", true},
+                                         {"3ffe:1900:4545:3:200:f8ff:fe21:67cf", true},
+                                         {"fe80:0:0:0:200:f8ff:fe21:67cf", true},
+                                         {"fe80::200:f8ff:fe21:67cf", true},
+                                         {"<svg onload=alert(1)>", false}, // Sample host header XSS attack
+                                         {"jlads;f8-9349*(D&F*D(234jD*(FSD*(VKLJ#(*$@()#$)))))", false},
+                                         {"\"\t\n", false},
+                                         {"!@#$%^ &*(*&^%$#@#$%^&*(*&^%$#))", false},
+                                         {":):(:O!!!!!!", false}};
+
+REGRESSION_TEST(VALIDATE_HDR_FIELD)(RegressionTest *t, int /* level ATS_UNUSED */, int *pstatus)
+{
+  TestBox box(t, pstatus);
+  box = REGRESSION_TEST_PASSED;
+
+  for (unsigned int i = 0; i < sizeof(http_validate_hdr_field_test_case) / sizeof(http_validate_hdr_field_test_case[0]); ++i) {
+    const char *const txt = http_validate_hdr_field_test_case[i].text;
+    ts::ConstBuffer tmp = ts::ConstBuffer(txt, strlen(txt));
+    box.check(validate_host_name(tmp) == http_validate_hdr_field_test_case[i].valid,
+              "Validation of FQDN (host) header: \"%s\", expected %s, but not", txt,
+              (http_validate_hdr_field_test_case[i].valid ? "true" : "false"));
+  }
+}
+
+#endif // TS_HAS_TESTS

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ada9752e/proxy/hdrs/HTTP.h
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HTTP.h b/proxy/hdrs/HTTP.h
index 7d91687..de8499f 100644
--- a/proxy/hdrs/HTTP.h
+++ b/proxy/hdrs/HTTP.h
@@ -29,6 +29,7 @@
 #include "ts/INK_MD5.h"
 #include "MIME.h"
 #include "URL.h"
+#include "ts/TsBuffer.h"
 
 #include "ts/ink_apidefs.h"
 
@@ -454,6 +455,7 @@ void http_parser_clear(HTTPParser *parser);
 MIMEParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
                                       bool must_copy_strings, bool eof);
 MIMEParseResult validate_hdr_host(HTTPHdrImpl *hh);
+bool validate_host_name(ts::ConstBuffer addr);
 MIMEParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
                                        bool must_copy_strings, bool eof);