You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2018/02/28 17:00:39 UTC

[trafficserver] branch master updated: Return 400 if there is whitespace after the field name and before the colon

This is an automated email from the ASF dual-hosted git repository.

bcall pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 08512de  Return 400 if there is whitespace after the field name and before the colon
08512de is described below

commit 08512deb11a610ae7084ce678b19bd637e30b3e1
Author: Bryan Call <bc...@apache.org>
AuthorDate: Fri Feb 23 14:48:53 2018 -0800

    Return 400 if there is whitespace after the field name and before the
    colon
---
 proxy/hdrs/HdrTest.cc                    |  2 +-
 proxy/hdrs/MIME.cc                       | 11 ++++-
 tests/gold_tests/headers/syntax.200.gold |  6 +++
 tests/gold_tests/headers/syntax.400.gold |  4 ++
 tests/gold_tests/headers/syntax.test.py  | 84 ++++++++++++++++++++++++++++++++
 5 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/proxy/hdrs/HdrTest.cc b/proxy/hdrs/HdrTest.cc
index eaa98e7..c355b00 100644
--- a/proxy/hdrs/HdrTest.cc
+++ b/proxy/hdrs/HdrTest.cc
@@ -496,7 +496,7 @@ HdrTest::test_mime()
     "continuation: part1\r\n"
     " part2\r\n"
     "scooby: doo\r\n"
-    "scooby : doo\r\n"
+    " scooby: doo\r\n"
     "bar: foo\r\n"
     "\r\n",
   };
diff --git a/proxy/hdrs/MIME.cc b/proxy/hdrs/MIME.cc
index 8dfc155..1d87e41 100644
--- a/proxy/hdrs/MIME.cc
+++ b/proxy/hdrs/MIME.cc
@@ -2619,8 +2619,15 @@ mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char
       continue; // toss away garbage line
     }
     field_name_last = colon - 1;
-    while ((field_name_last >= field_name_first) && is_ws(*field_name_last)) {
-      --field_name_last;
+    // RFC7230 section 3.2.4:
+    // No whitespace is allowed between the header field-name and colon.  In
+    // the past, differences in the handling of such whitespace have led to
+    // security vulnerabilities in request routing and response handling.  A
+    // server MUST reject any received request message that contains
+    // whitespace between a header field-name and colon with a response code
+    // of 400 (Bad Request).
+    if ((field_name_last >= field_name_first) && is_ws(*field_name_last)) {
+      return PARSE_RESULT_ERROR;
     }
 
     // find value first
diff --git a/tests/gold_tests/headers/syntax.200.gold b/tests/gold_tests/headers/syntax.200.gold
new file mode 100644
index 0000000..3b224e6
--- /dev/null
+++ b/tests/gold_tests/headers/syntax.200.gold
@@ -0,0 +1,6 @@
+HTTP/1.1 200 OK
+Date: ``
+Age: 0
+Transfer-Encoding: chunked
+Connection: keep-alive
+Server: ``
diff --git a/tests/gold_tests/headers/syntax.400.gold b/tests/gold_tests/headers/syntax.400.gold
new file mode 100644
index 0000000..b2502a6
--- /dev/null
+++ b/tests/gold_tests/headers/syntax.400.gold
@@ -0,0 +1,4 @@
+HTTP/1.1 400 Invalid HTTP Request
+Date: ``
+Connection: keep-alive
+Server: ``
diff --git a/tests/gold_tests/headers/syntax.test.py b/tests/gold_tests/headers/syntax.test.py
new file mode 100644
index 0000000..e38b97e
--- /dev/null
+++ b/tests/gold_tests/headers/syntax.test.py
@@ -0,0 +1,84 @@
+'''
+Test whitespace between field name and colon in the header
+'''
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import os
+Test.Summary = '''
+Test whitespace between field name and colon in the header
+'''
+
+# Needs Curl
+Test.SkipUnless(
+    Condition.HasProgram("curl", "Curl need to be installed on system for this test to work")
+)
+Test.ContinueOnFail = True
+
+# Define default ATS
+ts = Test.MakeATSProcess("ts", select_ports=False)
+server = Test.MakeOriginServer("server")
+
+#**testname is required**
+testName = ""
+request_header = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
+server.addResponse("sessionlog.json", request_header, response_header)
+
+# ATS Configuration
+ts.addSSLfile("../remap/ssl/server.pem")
+ts.addSSLfile("../remap/ssl/server.key")
+
+ts.Variables.ssl_port = 4443
+ts.Disk.records_config.update({
+    'proxy.config.diags.debug.enabled': 1,
+    'proxy.config.diags.debug.tags': 'ssl',
+    'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.http.server_ports': '{0} {1}:ssl'.format(ts.Variables.port, ts.Variables.ssl_port),
+})
+
+ts.Disk.remap_config.AddLine(
+    'map http://www.example.com http://127.0.0.1:{0}'.format(server.Variables.Port)
+)
+
+ts.Disk.ssl_multicert_config.AddLine(
+    'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+)
+
+# Test 1 - 200 Response
+tr = Test.AddTestRun()
+tr.Processes.Default.StartBefore(server)
+tr.Processes.Default.StartBefore(Test.Processes.ts)
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=When.PortOpen(ts.Variables.ssl_port))
+tr.Processes.Default.Command = 'curl -s -D - -v --ipv4 --http1.1 -H " foo: bar"  -H "Host: www.example.com" http://localhost:8080/'
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Streams.stdout = "syntax.200.gold"
+tr.StillRunningAfter = ts
+
+# Test 2 - 400 Response
+tr = Test.AddTestRun()
+tr.Processes.Default.Command = 'curl -s -D - -v --ipv4 --http1.1 -H "foo : bar"  -H "Host: www.example.com" http://localhost:8080/'
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Streams.stdout = "syntax.400.gold"
+tr.StillRunningAfter = ts
+
+# Test 3 - 400 Response
+tr = Test.AddTestRun()
+tr.Processes.Default.Command = 'curl -s -D - -v --ipv4 --http1.1 -H "foo  : bar"  -H "Host: www.example.com" http://localhost:8080/'
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Streams.stdout = "syntax.400.gold"
+tr.StillRunningAfter = ts

-- 
To stop receiving notification emails like this one, please contact
bcall@apache.org.