Skip to content

Commit ada9752

Browse files
danobiSolidWallOfCode
authored andcommitted
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.
1 parent d64434e commit ada9752

2 files changed

Lines changed: 68 additions & 2 deletions

File tree

proxy/hdrs/HTTP.cc

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
#include "ts/ink_defs.h"
2525
#include "ts/ink_platform.h"
26-
#include "ts/TsBuffer.h"
2726
#include "ts/ink_inet.h"
2827
#include <assert.h>
2928
#include <stdio.h>
@@ -161,6 +160,15 @@ is_digit(char c)
161160
return ((c <= '9') && (c >= '0'));
162161
}
163162

163+
// test to see if a character is a valid character for a host in a URI according to
164+
// RFC 3986 and RFC 1034
165+
inline static int
166+
is_host_char(char c)
167+
{
168+
return (ParseRules::is_alnum(c) || (c == '-') || (c == '.') || (c == '[') || (c == ']') || (c == '_') || (c == ':') ||
169+
(c == '~') || (c == '%'));
170+
}
171+
164172
/***********************************************************************
165173
* *
166174
* M A I N C O D E *
@@ -1107,6 +1115,18 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
11071115
return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
11081116
}
11091117

1118+
// Checks if `addr` is a valid FQDN string
1119+
bool
1120+
validate_host_name(ts::ConstBuffer addr)
1121+
{
1122+
while (addr) {
1123+
if (!(is_host_char(*addr)))
1124+
return false;
1125+
++addr;
1126+
}
1127+
return true;
1128+
}
1129+
11101130
MIMEParseResult
11111131
validate_hdr_host(HTTPHdrImpl *hh)
11121132
{
@@ -1124,9 +1144,11 @@ validate_hdr_host(HTTPHdrImpl *hh)
11241144
if (port.size() > 5)
11251145
return PARSE_ERROR;
11261146
int port_i = ink_atoi(port.data(), port.size());
1127-
if (port.size() > 5 || port_i >= 65536 || port_i <= 0)
1147+
if (port_i >= 65536 || port_i <= 0)
11281148
return PARSE_ERROR;
11291149
}
1150+
if (!validate_host_name(addr))
1151+
return PARSE_ERROR;
11301152
while (rest && PARSE_DONE == ret) {
11311153
if (!ParseRules::is_ws(*rest))
11321154
return PARSE_ERROR;
@@ -2188,3 +2210,45 @@ HTTPInfo::push_frag_offset(FragOffset offset)
21882210

21892211
m_alt->m_frag_offsets[m_alt->m_frag_offset_count++] = offset;
21902212
}
2213+
2214+
2215+
/*-------------------------------------------------------------------------
2216+
* Regression tests
2217+
-------------------------------------------------------------------------*/
2218+
#if TS_HAS_TESTS
2219+
#include "ts/TestBox.h"
2220+
2221+
const static struct {
2222+
const char *const text;
2223+
bool valid;
2224+
} http_validate_hdr_field_test_case[] = {{"yahoo", true},
2225+
{"yahoo.com", true},
2226+
{"yahoo.wow.com", true},
2227+
{"yahoo.wow.much.amaze.com", true},
2228+
{"209.131.52.50", true},
2229+
{"192.168.0.1", true},
2230+
{"localhost", true},
2231+
{"3ffe:1900:4545:3:200:f8ff:fe21:67cf", true},
2232+
{"fe80:0:0:0:200:f8ff:fe21:67cf", true},
2233+
{"fe80::200:f8ff:fe21:67cf", true},
2234+
{"<svg onload=alert(1)>", false}, // Sample host header XSS attack
2235+
{"jlads;f8-9349*(D&F*D(234jD*(FSD*(VKLJ#(*$@()#$)))))", false},
2236+
{"\"\t\n", false},
2237+
{"!@#$%^ &*(*&^%$#@#$%^&*(*&^%$#))", false},
2238+
{":):(:O!!!!!!", false}};
2239+
2240+
REGRESSION_TEST(VALIDATE_HDR_FIELD)(RegressionTest *t, int /* level ATS_UNUSED */, int *pstatus)
2241+
{
2242+
TestBox box(t, pstatus);
2243+
box = REGRESSION_TEST_PASSED;
2244+
2245+
for (unsigned int i = 0; i < sizeof(http_validate_hdr_field_test_case) / sizeof(http_validate_hdr_field_test_case[0]); ++i) {
2246+
const char *const txt = http_validate_hdr_field_test_case[i].text;
2247+
ts::ConstBuffer tmp = ts::ConstBuffer(txt, strlen(txt));
2248+
box.check(validate_host_name(tmp) == http_validate_hdr_field_test_case[i].valid,
2249+
"Validation of FQDN (host) header: \"%s\", expected %s, but not", txt,
2250+
(http_validate_hdr_field_test_case[i].valid ? "true" : "false"));
2251+
}
2252+
}
2253+
2254+
#endif // TS_HAS_TESTS

proxy/hdrs/HTTP.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "ts/INK_MD5.h"
3030
#include "MIME.h"
3131
#include "URL.h"
32+
#include "ts/TsBuffer.h"
3233

3334
#include "ts/ink_apidefs.h"
3435

@@ -454,6 +455,7 @@ void http_parser_clear(HTTPParser *parser);
454455
MIMEParseResult http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
455456
bool must_copy_strings, bool eof);
456457
MIMEParseResult validate_hdr_host(HTTPHdrImpl *hh);
458+
bool validate_host_name(ts::ConstBuffer addr);
457459
MIMEParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const char **start, const char *end,
458460
bool must_copy_strings, bool eof);
459461

0 commit comments

Comments
 (0)