Never index authorization and small cookie header field
nghttp2 library now use Literal Header Field never Indexed for "authorization" header field and small "cookie" header field, regardless of nghttp2_nv.flags.
This commit is contained in:
parent
53bcafb39f
commit
82e2c5bd22
101
lib/nghttp2_hd.c
101
lib/nghttp2_hd.c
|
@ -639,38 +639,36 @@ static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) {
|
|||
return rv;
|
||||
}
|
||||
|
||||
static uint8_t pack_first_byte(int inc_indexing, int no_index) {
|
||||
if (inc_indexing) {
|
||||
static uint8_t pack_first_byte(int indexing_mode) {
|
||||
switch (indexing_mode) {
|
||||
case NGHTTP2_HD_WITH_INDEXING:
|
||||
return 0x40u;
|
||||
}
|
||||
|
||||
if (no_index) {
|
||||
case NGHTTP2_HD_WITHOUT_INDEXING:
|
||||
return 0;
|
||||
case NGHTTP2_HD_NEVER_INDEXING:
|
||||
return 0x10u;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
|
||||
const nghttp2_nv *nv, int inc_indexing) {
|
||||
const nghttp2_nv *nv, int indexing_mode) {
|
||||
int rv;
|
||||
uint8_t *bufp;
|
||||
size_t blocklen;
|
||||
uint8_t sb[16];
|
||||
size_t prefixlen;
|
||||
int no_index;
|
||||
|
||||
no_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0;
|
||||
|
||||
if (inc_indexing) {
|
||||
if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
|
||||
prefixlen = 6;
|
||||
} else {
|
||||
prefixlen = 4;
|
||||
}
|
||||
|
||||
DEBUGF(fprintf(stderr, "deflatehd: emit indname index=%zu, valuelen=%zu, "
|
||||
"indexing=%d, no_index=%d\n",
|
||||
idx, nv->valuelen, inc_indexing, no_index));
|
||||
"indexing_mode=%d\n",
|
||||
idx, nv->valuelen, indexing_mode));
|
||||
|
||||
blocklen = count_encoded_length(idx + 1, prefixlen);
|
||||
|
||||
|
@ -680,7 +678,7 @@ static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
|
|||
|
||||
bufp = sb;
|
||||
|
||||
*bufp = pack_first_byte(inc_indexing, no_index);
|
||||
*bufp = pack_first_byte(indexing_mode);
|
||||
|
||||
encode_length(bufp, idx + 1, prefixlen);
|
||||
|
||||
|
@ -698,17 +696,14 @@ static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
|
|||
}
|
||||
|
||||
static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
|
||||
int inc_indexing) {
|
||||
int indexing_mode) {
|
||||
int rv;
|
||||
int no_index;
|
||||
|
||||
no_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) != 0;
|
||||
|
||||
DEBUGF(fprintf(stderr, "deflatehd: emit newname namelen=%zu, valuelen=%zu, "
|
||||
"indexing=%d, no_index=%d\n",
|
||||
nv->namelen, nv->valuelen, inc_indexing, no_index));
|
||||
"indexing_mode=%d\n",
|
||||
nv->namelen, nv->valuelen, indexing_mode));
|
||||
|
||||
rv = nghttp2_bufs_addb(bufs, pack_first_byte(inc_indexing, no_index));
|
||||
rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -820,15 +815,14 @@ typedef struct {
|
|||
|
||||
static search_result search_hd_table(nghttp2_hd_context *context,
|
||||
const nghttp2_nv *nv, uint32_t name_hash,
|
||||
uint32_t value_hash) {
|
||||
uint32_t value_hash, int indexing_mode) {
|
||||
ssize_t left = -1, right = (ssize_t)STATIC_TABLE_LENGTH;
|
||||
search_result res = {-1, 0};
|
||||
size_t i;
|
||||
int use_index = (nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) == 0;
|
||||
|
||||
/* Search dynamic table first, so that we can find recently used
|
||||
entry first */
|
||||
if (use_index) {
|
||||
if (indexing_mode != NGHTTP2_HD_NEVER_INDEXING) {
|
||||
for (i = 0; i < context->hd_table.len; ++i) {
|
||||
nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, i);
|
||||
if (ent->name_hash != name_hash || !name_eq(&ent->nv, nv)) {
|
||||
|
@ -867,8 +861,8 @@ static search_result search_hd_table(nghttp2_hd_context *context,
|
|||
if (res.index == -1) {
|
||||
res.index = (ssize_t)(static_table[i].index);
|
||||
}
|
||||
if (use_index && ent->value_hash == value_hash &&
|
||||
value_eq(&ent->nv, nv)) {
|
||||
if (indexing_mode != NGHTTP2_HD_NEVER_INDEXING &&
|
||||
ent->value_hash == value_hash && value_eq(&ent->nv, nv)) {
|
||||
res.index = (ssize_t)(static_table[i].index);
|
||||
res.name_value_match = 1;
|
||||
return res;
|
||||
|
@ -942,22 +936,17 @@ nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context,
|
|||
#define name_match(NV, NAME) \
|
||||
(nv->namelen == sizeof(NAME) - 1 && memeq(nv->name, NAME, sizeof(NAME) - 1))
|
||||
|
||||
static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater,
|
||||
static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater,
|
||||
const nghttp2_nv *nv) {
|
||||
if ((nv->flags & NGHTTP2_NV_FLAG_NO_INDEX) ||
|
||||
entry_room(nv->namelen, nv->valuelen) >
|
||||
deflater->ctx.hd_table_bufsize_max * 3 / 4) {
|
||||
return 0;
|
||||
if (entry_room(nv->namelen, nv->valuelen) >
|
||||
deflater->ctx.hd_table_bufsize_max * 3 / 4 ||
|
||||
name_match(nv, ":path") || name_match(nv, "content-length") ||
|
||||
name_match(nv, "set-cookie") || name_match(nv, "etag") ||
|
||||
name_match(nv, "if-modified-since") || name_match(nv, "if-none-match") ||
|
||||
name_match(nv, "location") || name_match(nv, "age")) {
|
||||
return NGHTTP2_HD_WITHOUT_INDEXING;
|
||||
}
|
||||
#ifdef NGHTTP2_XHD
|
||||
return !name_match(nv, NGHTTP2_XHD);
|
||||
#else /* !NGHTTP2_XHD */
|
||||
return !name_match(nv, ":path") && !name_match(nv, "content-length") &&
|
||||
!name_match(nv, "set-cookie") && !name_match(nv, "etag") &&
|
||||
!name_match(nv, "if-modified-since") &&
|
||||
!name_match(nv, "if-none-match") && !name_match(nv, "location") &&
|
||||
!name_match(nv, "age");
|
||||
#endif /* !NGHTTP2_XHD */
|
||||
return NGHTTP2_HD_WITH_INDEXING;
|
||||
}
|
||||
|
||||
static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
||||
|
@ -965,7 +954,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
|||
int rv;
|
||||
search_result res;
|
||||
ssize_t idx;
|
||||
int incidx = 0;
|
||||
int indexing_mode;
|
||||
uint32_t name_hash = hash(nv->name, nv->namelen);
|
||||
uint32_t value_hash = hash(nv->value, nv->valuelen);
|
||||
nghttp2_mem *mem;
|
||||
|
@ -974,7 +963,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
|||
|
||||
mem = deflater->ctx.mem;
|
||||
|
||||
res = search_hd_table(&deflater->ctx, nv, name_hash, value_hash);
|
||||
/* Don't index authorization header field since it may contain low
|
||||
entropy secret data (e.g., id/password). Also cookie header
|
||||
field with less than 20 bytes value is also never indexed. This
|
||||
is the same criteria used in Firefox codebase. */
|
||||
indexing_mode = name_match(nv, "authorization") ||
|
||||
(name_match(nv, "cookie") && nv->valuelen < 20) ||
|
||||
(nv->flags & NGHTTP2_NV_FLAG_NO_INDEX)
|
||||
? NGHTTP2_HD_NEVER_INDEXING
|
||||
: hd_deflate_decide_indexing(deflater, nv);
|
||||
|
||||
res =
|
||||
search_hd_table(&deflater->ctx, nv, name_hash, value_hash, indexing_mode);
|
||||
|
||||
idx = res.index;
|
||||
|
||||
|
@ -994,7 +994,7 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
|||
DEBUGF(fprintf(stderr, "deflatehd: name match index=%zd\n", res.index));
|
||||
}
|
||||
|
||||
if (hd_deflate_should_indexing(deflater, nv)) {
|
||||
if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
|
||||
nghttp2_hd_entry *new_ent;
|
||||
if (idx != -1 && idx < (ssize_t)NGHTTP2_STATIC_TABLE_LENGTH) {
|
||||
nghttp2_nv nv_indname;
|
||||
|
@ -1015,12 +1015,11 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
|||
nghttp2_hd_entry_free(new_ent, mem);
|
||||
nghttp2_mem_free(mem, new_ent);
|
||||
}
|
||||
incidx = 1;
|
||||
}
|
||||
if (idx == -1) {
|
||||
rv = emit_newname_block(bufs, nv, incidx);
|
||||
rv = emit_newname_block(bufs, nv, indexing_mode);
|
||||
} else {
|
||||
rv = emit_indname_block(bufs, idx, nv, incidx);
|
||||
rv = emit_indname_block(bufs, idx, nv, indexing_mode);
|
||||
}
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
|
@ -1917,14 +1916,14 @@ void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
|
|||
}
|
||||
|
||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
|
||||
nghttp2_nv *nv, int inc_indexing) {
|
||||
nghttp2_nv *nv, int indexing_mode) {
|
||||
|
||||
return emit_indname_block(bufs, idx, nv, inc_indexing);
|
||||
return emit_indname_block(bufs, idx, nv, indexing_mode);
|
||||
}
|
||||
|
||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int inc_indexing) {
|
||||
return emit_newname_block(bufs, nv, inc_indexing);
|
||||
int indexing_mode) {
|
||||
return emit_newname_block(bufs, nv, indexing_mode);
|
||||
}
|
||||
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
|
||||
|
|
|
@ -107,6 +107,12 @@ typedef enum {
|
|||
NGHTTP2_HD_STATE_READ_VALUE
|
||||
} nghttp2_hd_inflate_state;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_WITH_INDEXING,
|
||||
NGHTTP2_HD_WITHOUT_INDEXING,
|
||||
NGHTTP2_HD_NEVER_INDEXING
|
||||
} nghttp2_hd_indexing_mode;
|
||||
|
||||
typedef struct {
|
||||
/* dynamic header table */
|
||||
nghttp2_hd_ringbuf hd_table;
|
||||
|
@ -273,11 +279,11 @@ void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
|||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
||||
nghttp2_nv *nv, int inc_indexing);
|
||||
nghttp2_nv *nv, int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int inc_indexing);
|
||||
int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
||||
|
|
|
@ -2565,10 +2565,7 @@ int main(int argc, char **argv) {
|
|||
<< std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// To test "never index" repr, don't index authorization header
|
||||
// field unconditionally.
|
||||
auto no_index = util::strieq_l("authorization", header);
|
||||
config.headers.emplace_back(header, value, no_index);
|
||||
config.headers.emplace_back(header, value, false);
|
||||
util::inp_strlower(config.headers.back().name);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -140,9 +140,9 @@ void test_nghttp2_hd_deflate(void) {
|
|||
void test_nghttp2_hd_deflate_same_indexed_repr(void) {
|
||||
nghttp2_hd_deflater deflater;
|
||||
nghttp2_hd_inflater inflater;
|
||||
nghttp2_nv nva1[] = {MAKE_NV("cookie", "alpha"), MAKE_NV("cookie", "alpha")};
|
||||
nghttp2_nv nva2[] = {MAKE_NV("cookie", "alpha"), MAKE_NV("cookie", "alpha"),
|
||||
MAKE_NV("cookie", "alpha")};
|
||||
nghttp2_nv nva1[] = {MAKE_NV("host", "alpha"), MAKE_NV("host", "alpha")};
|
||||
nghttp2_nv nva2[] = {MAKE_NV("host", "alpha"), MAKE_NV("host", "alpha"),
|
||||
MAKE_NV("host", "alpha")};
|
||||
nghttp2_bufs bufs;
|
||||
ssize_t blocklen;
|
||||
nva_out out;
|
||||
|
@ -250,7 +250,8 @@ void test_nghttp2_hd_inflate_indname_noinc(void) {
|
|||
nghttp2_hd_inflate_init(&inflater, mem);
|
||||
|
||||
for (i = 0; i < ARRLEN(nv); ++i) {
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 57, &nv[i], 0));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 57, &nv[i],
|
||||
NGHTTP2_HD_WITHOUT_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
@ -283,7 +284,8 @@ void test_nghttp2_hd_inflate_indname_inc(void) {
|
|||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, mem);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 57, &nv, 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 57, &nv,
|
||||
NGHTTP2_HD_WITH_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
@ -325,10 +327,14 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void) {
|
|||
|
||||
nv.flags = NGHTTP2_NV_FLAG_NONE;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 14, &nv, 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 15, &nv, 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 16, &nv, 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 17, &nv, 1));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 14, &nv,
|
||||
NGHTTP2_HD_WITH_INDEXING));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 15, &nv,
|
||||
NGHTTP2_HD_WITH_INDEXING));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 16, &nv,
|
||||
NGHTTP2_HD_WITH_INDEXING));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&bufs, 17, &nv,
|
||||
NGHTTP2_HD_WITH_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
@ -372,7 +378,8 @@ void test_nghttp2_hd_inflate_newname_noinc(void) {
|
|||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, mem);
|
||||
for (i = 0; i < ARRLEN(nv); ++i) {
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv[i], 0));
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv[i],
|
||||
NGHTTP2_HD_WITHOUT_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
@ -405,7 +412,8 @@ void test_nghttp2_hd_inflate_newname_inc(void) {
|
|||
nva_out_init(&out);
|
||||
nghttp2_hd_inflate_init(&inflater, mem);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv, 1));
|
||||
CU_ASSERT(
|
||||
0 == nghttp2_hd_emit_newname_block(&bufs, &nv, NGHTTP2_HD_WITH_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
@ -450,7 +458,8 @@ void test_nghttp2_hd_inflate_clearall_inc(void) {
|
|||
|
||||
nghttp2_hd_inflate_init(&inflater, mem);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv, 1));
|
||||
CU_ASSERT(
|
||||
0 == nghttp2_hd_emit_newname_block(&bufs, &nv, NGHTTP2_HD_WITH_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
@ -477,7 +486,8 @@ void test_nghttp2_hd_inflate_clearall_inc(void) {
|
|||
header table */
|
||||
nv.valuelen = sizeof(value) - 2;
|
||||
|
||||
CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&bufs, &nv, 1));
|
||||
CU_ASSERT(
|
||||
0 == nghttp2_hd_emit_newname_block(&bufs, &nv, NGHTTP2_HD_WITH_INDEXING));
|
||||
|
||||
blocklen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
|
|
Loading…
Reference in New Issue