Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 67 additions & 2 deletions proxy/hdrs/HTTP.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -1124,9 +1132,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_hdr_field(addr))
return PARSE_ERROR;
while (rest && PARSE_DONE == ret) {
if (!ParseRules::is_ws(*rest))
return PARSE_ERROR;
Expand All @@ -1140,6 +1150,19 @@ validate_hdr_host(HTTPHdrImpl *hh)
return ret;
}

// Checks if `addr` is a valid FQDN string
bool
validate_hdr_field(ts::ConstBuffer &addr)
{
bool ret = true;
while (addr) {
if (!(is_host_char(*addr)))
ret = false;
++addr;
}
return ret;
}

/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/

Expand Down Expand Up @@ -2188,3 +2211,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_hdr_field(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
2 changes: 2 additions & 0 deletions proxy/hdrs/HTTP.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "ts/INK_MD5.h"
#include "MIME.h"
#include "URL.h"
#include "ts/TsBuffer.h"

#include "ts/ink_apidefs.h"

Expand Down Expand Up @@ -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_hdr_field(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);

Expand Down