mirror of https://git.kore.io/kore.git
better http header validation.
This commit is contained in:
parent
3312a2882f
commit
1447f6573f
123
src/http.c
123
src/http.c
|
@ -61,6 +61,58 @@ static struct {
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HTTP_MAP_LIMIT 127
|
||||||
|
|
||||||
|
/*
|
||||||
|
* token = 1*<any CHAR except CTLs or separators>
|
||||||
|
* separators = "(" | ")" | "<" | ">" | "@"
|
||||||
|
* | "," | ";" | ":" | "\" | <">
|
||||||
|
* | "/" | "[" | "]" | "?" | "="
|
||||||
|
* | "{" | "}" | SP | HT
|
||||||
|
*/
|
||||||
|
static const char http_token[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, '!' , 0x00, '#' , '$' , '%' , '&' , '\'',
|
||||||
|
0x00, 0x00, '*' , '+' , 0x00, '-' , '.' , 0x00,
|
||||||
|
'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
|
||||||
|
'8' , '9' , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' ,
|
||||||
|
'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' ,
|
||||||
|
'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' ,
|
||||||
|
'X' , 'Y' , 'Z' , 0x00, 0x00, 0x00, '^' , '_' ,
|
||||||
|
'`' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' ,
|
||||||
|
'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' ,
|
||||||
|
'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' ,
|
||||||
|
'x' , 'y' , 'z' , 0x00, '|' , 0x00, '~' ,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* field-content = <the OCTETs making up the field-value
|
||||||
|
* and consisting of either *TEXT or combinations
|
||||||
|
* of token, separators, and quoted-string>
|
||||||
|
*/
|
||||||
|
static const char http_field_content[] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
' ' , '!' , '"' , '#' , '$' , '%' , '&' , '\'',
|
||||||
|
'(' , ')' , '*' , '+' , ',' , '-' , '.' , '/' ,
|
||||||
|
'0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' ,
|
||||||
|
'8' , '9' , ':' , ';' , '<' , '=' , '>' , '?' ,
|
||||||
|
'@' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' ,
|
||||||
|
'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 'O' ,
|
||||||
|
'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' ,
|
||||||
|
'X' , 'Y' , 'Z' , '[' , '\\', ']' , '^' , '_' ,
|
||||||
|
'`' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' ,
|
||||||
|
'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' ,
|
||||||
|
'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' ,
|
||||||
|
'x' , 'y' , 'z' , '{' , '|' , '}' , '~' ,
|
||||||
|
};
|
||||||
|
|
||||||
static int http_body_recv(struct netbuf *);
|
static int http_body_recv(struct netbuf *);
|
||||||
static void http_error_response(struct connection *, int);
|
static void http_error_response(struct connection *, int);
|
||||||
static void http_write_response_cookie(struct http_cookie *);
|
static void http_write_response_cookie(struct http_cookie *);
|
||||||
|
@ -77,6 +129,7 @@ static int multipart_parse_headers(struct http_request *,
|
||||||
struct kore_buf *, struct kore_buf *,
|
struct kore_buf *, struct kore_buf *,
|
||||||
const char *, const int);
|
const char *, const int);
|
||||||
|
|
||||||
|
static char *http_validate_header(char *);
|
||||||
static struct http_request *http_request_new(struct connection *,
|
static struct http_request *http_request_new(struct connection *,
|
||||||
const char *, const char *, char *,
|
const char *, const char *, char *,
|
||||||
const char *);
|
const char *);
|
||||||
|
@ -584,6 +637,7 @@ http_request_cookie(struct http_request *req, const char *cookie, char **out)
|
||||||
int
|
int
|
||||||
http_header_recv(struct netbuf *nb)
|
http_header_recv(struct netbuf *nb)
|
||||||
{
|
{
|
||||||
|
struct connection *c;
|
||||||
size_t len;
|
size_t len;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
struct http_header *hdr;
|
struct http_header *hdr;
|
||||||
|
@ -592,10 +646,10 @@ http_header_recv(struct netbuf *nb)
|
||||||
u_int64_t bytes_left;
|
u_int64_t bytes_left;
|
||||||
u_int8_t *end_headers;
|
u_int8_t *end_headers;
|
||||||
int h, i, v, skip, l;
|
int h, i, v, skip, l;
|
||||||
char *request[4], *host, *hbuf;
|
char *headers[HTTP_REQ_HEADER_MAX];
|
||||||
char *p, *headers[HTTP_REQ_HEADER_MAX];
|
char *value, *host, *request[4], *hbuf;
|
||||||
struct connection *c = (struct connection *)nb->owner;
|
|
||||||
|
|
||||||
|
c = nb->owner;
|
||||||
kore_debug("http_header_recv(%p)", nb);
|
kore_debug("http_header_recv(%p)", nb);
|
||||||
|
|
||||||
if (nb->b_len < 4)
|
if (nb->b_len < 4)
|
||||||
|
@ -633,19 +687,16 @@ http_header_recv(struct netbuf *nb)
|
||||||
if (strncasecmp(headers[i], "host", 4))
|
if (strncasecmp(headers[i], "host", 4))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((host = strchr(headers[i], ':')) == NULL) {
|
if ((host = http_validate_header(headers[i])) == NULL) {
|
||||||
http_error_response(c, 400);
|
http_error_response(c, 400);
|
||||||
return (KORE_RESULT_OK);
|
return (KORE_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
*(host)++ = '\0';
|
|
||||||
|
|
||||||
if (*host == '\0') {
|
if (*host == '\0') {
|
||||||
http_error_response(c, 400);
|
http_error_response(c, 400);
|
||||||
return (KORE_RESULT_OK);
|
return (KORE_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
host++;
|
|
||||||
skip = i;
|
skip = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -668,18 +719,21 @@ http_header_recv(struct netbuf *nb)
|
||||||
if (i == skip)
|
if (i == skip)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
p = strchr(headers[i], ':');
|
if ((value = http_validate_header(headers[i])) == NULL) {
|
||||||
if (p == NULL) {
|
req->flags |= HTTP_REQUEST_DELETE;
|
||||||
kore_debug("malformed header: '%s'", headers[i]);
|
http_error_response(c, 400);
|
||||||
continue;
|
return (KORE_RESULT_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*value == '\0') {
|
||||||
|
req->flags |= HTTP_REQUEST_DELETE;
|
||||||
|
http_error_response(c, 400);
|
||||||
|
return (KORE_RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
*(p++) = '\0';
|
|
||||||
if (*p == ' ')
|
|
||||||
p++;
|
|
||||||
hdr = kore_pool_get(&http_header_pool);
|
hdr = kore_pool_get(&http_header_pool);
|
||||||
hdr->header = headers[i];
|
hdr->header = headers[i];
|
||||||
hdr->value = p;
|
hdr->value = value;
|
||||||
TAILQ_INSERT_TAIL(&(req->req_headers), hdr, list);
|
TAILQ_INSERT_TAIL(&(req->req_headers), hdr, list);
|
||||||
|
|
||||||
if (req->agent == NULL &&
|
if (req->agent == NULL &&
|
||||||
|
@ -2083,3 +2137,42 @@ http_media_type(const char *path)
|
||||||
|
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
http_validate_header(char *header)
|
||||||
|
{
|
||||||
|
u_int8_t idx;
|
||||||
|
char *p, *value;
|
||||||
|
|
||||||
|
for (p = header; *p != '\0'; p++) {
|
||||||
|
idx = *p;
|
||||||
|
if (idx > HTTP_MAP_LIMIT)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (*p == ':') {
|
||||||
|
*(p)++ = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (http_token[idx] == 0x00)
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isspace(*(unsigned char *)p))
|
||||||
|
p++;
|
||||||
|
|
||||||
|
if (*p == '\0')
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
value = p;
|
||||||
|
while (*p != '\0') {
|
||||||
|
idx = *p;
|
||||||
|
if (idx > HTTP_MAP_LIMIT)
|
||||||
|
return (NULL);
|
||||||
|
if (http_field_content[idx] == 0x00)
|
||||||
|
return (NULL);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (value);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue