New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
QPACK security considerations #3575
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -61,6 +61,41 @@ normative: | |||||||||||||
org: Mozilla | ||||||||||||||
role: editor | ||||||||||||||
|
||||||||||||||
informative: | ||||||||||||||
|
||||||||||||||
CRIME: | ||||||||||||||
target: http://en.wikipedia.org/w/index.php?title=CRIME&oldid=660948120 | ||||||||||||||
title: "CRIME" | ||||||||||||||
author: | ||||||||||||||
- | ||||||||||||||
org: Wikipedia | ||||||||||||||
date: May, 2015 | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
HUFFMAN: | ||||||||||||||
target: http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=4051119 | ||||||||||||||
title: "A Method for the Construction of Minimum-Redundancy Codes" | ||||||||||||||
author: | ||||||||||||||
- | ||||||||||||||
ins: D. A. Huffman | ||||||||||||||
date: September, 1952 | ||||||||||||||
seriesinfo: | ||||||||||||||
Proceedings of the Institute of Radio Engineers, | ||||||||||||||
Volume 40, Number 9, pp. 1098-1101 | ||||||||||||||
|
||||||||||||||
PETAL: | ||||||||||||||
target: http://www.pdl.cmu.edu/PDL-FTP/associated/CMU-PDL-13-106.pdf | ||||||||||||||
title: "PETAL: Preset Encoding Table Information Leakage" | ||||||||||||||
author: | ||||||||||||||
- | ||||||||||||||
ins: J. Tan | ||||||||||||||
name: Jiaqi Tan | ||||||||||||||
- | ||||||||||||||
ins: J. Nahata | ||||||||||||||
name: Jayvardhan Nahata | ||||||||||||||
date: April, 2013 | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
--- abstract | ||||||||||||||
|
||||||||||||||
|
@@ -1144,7 +1179,193 @@ QPACK_DECODER_STREAM_ERROR (0x202): | |||||||||||||
|
||||||||||||||
# Security Considerations | ||||||||||||||
|
||||||||||||||
TBD. Also see Section 7.1 of [RFC7541]. | ||||||||||||||
<!-- lifted from HPACK with minimal modifications for QPACK --> | ||||||||||||||
This section describes potential areas of security concern with QPACK: | ||||||||||||||
|
||||||||||||||
* Use of compression as a length-based oracle for verifying guesses about | ||||||||||||||
secrets that are compressed into a shared compression context. | ||||||||||||||
* Denial of service resulting from exhausting processing or memory capacity at | ||||||||||||||
a decoder. | ||||||||||||||
|
||||||||||||||
## Probing Dynamic Table State | ||||||||||||||
|
||||||||||||||
QPACK reduces the length of header field encodings by exploiting the redundancy | ||||||||||||||
inherent in protocols like HTTP. The ultimate goal of this is to reduce the | ||||||||||||||
amount of data that is required to send HTTP requests or responses. | ||||||||||||||
|
||||||||||||||
The compression context used to encode header fields can be probed by an | ||||||||||||||
attacker who can both define header fields to be encoded and transmitted and | ||||||||||||||
observe the length of those fields once they are encoded. When an attacker can | ||||||||||||||
do both, they can adaptively modify requests in order to confirm guesses about | ||||||||||||||
the dynamic table state. If a guess is compressed into a shorter length, the | ||||||||||||||
attacker can observe the encoded length and infer that the guess was correct. | ||||||||||||||
|
||||||||||||||
This is possible even over the Transport Layer Security Protocol (TLS, see | ||||||||||||||
{{?RFC5246}}), because while TLS provides confidentiality protection for | ||||||||||||||
content, it only provides a limited amount of protection for the length of that | ||||||||||||||
content. | ||||||||||||||
|
||||||||||||||
Note: | ||||||||||||||
|
||||||||||||||
Padding schemes only provide limited protection against an attacker with these | ||||||||||||||
capabilities, potentially only forcing an increased number of guesses to learn | ||||||||||||||
the length associated with a given guess. Padding schemes also work directly | ||||||||||||||
against compression by increasing the number of bits that are transmitted. | ||||||||||||||
|
||||||||||||||
Attacks like CRIME [CRIME] demonstrated the existence of these general attacker | ||||||||||||||
capabilities. The specific attack exploited the fact that DEFLATE {{?RFC1951}} | ||||||||||||||
removes redundancy based on prefix matching. This permitted the attacker to | ||||||||||||||
confirm guesses a character at a time, reducing an exponential-time attack into | ||||||||||||||
a linear-time attack. | ||||||||||||||
|
||||||||||||||
## Applicability to QPACK and HTTP | ||||||||||||||
|
||||||||||||||
QPACK mitigates but does not completely prevent attacks modeled on CRIME [CRIME] | ||||||||||||||
by forcing a guess to match an entire header field value, rather than individual | ||||||||||||||
characters. An attacker can only learn whether a guess is correct or not, so is | ||||||||||||||
reduced to a brute force guess for the header field values. | ||||||||||||||
|
||||||||||||||
The viability of recovering specific header field values therefore depends on | ||||||||||||||
the entropy of values. As a result, values with high entropy are unlikely to be | ||||||||||||||
recovered successfully. However, values with low entropy remain vulnerable. | ||||||||||||||
|
||||||||||||||
Attacks of this nature are possible any time that two mutually distrustful | ||||||||||||||
entities control requests or responses that are placed onto a single HTTP/2 | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
connection. If the shared QPACK compressor permits one entity to add entries to | ||||||||||||||
the dynamic table, and the other to access those entries, then the state of the | ||||||||||||||
table can be learned. | ||||||||||||||
|
||||||||||||||
Having requests or responses from mutually distrustful entities occurs when an | ||||||||||||||
intermediary either: | ||||||||||||||
|
||||||||||||||
* sends requests from multiple clients on a single connection toward an origin | ||||||||||||||
server, or | ||||||||||||||
|
||||||||||||||
* takes responses from multiple origin servers and places them on a shared | ||||||||||||||
connection toward a client. | ||||||||||||||
|
||||||||||||||
Web browsers also need to assume that requests made on the same connection by | ||||||||||||||
different web origins {{?RFC6454}} are made by mutually distrustful entities. | ||||||||||||||
|
||||||||||||||
## Mitigation | ||||||||||||||
|
||||||||||||||
Users of HTTP that require confidentiality for header fields can use values with | ||||||||||||||
entropy sufficient to make guessing infeasible. However, this is impractical as | ||||||||||||||
a general solution because it forces all users of HTTP to take steps to mitigate | ||||||||||||||
attacks. It would impose new constraints on how HTTP is used. | ||||||||||||||
|
||||||||||||||
Rather than impose constraints on users of HTTP, an implementation of QPACK can | ||||||||||||||
instead constrain how compression is applied in order to limit the potential for | ||||||||||||||
dynamic table probing. | ||||||||||||||
|
||||||||||||||
An ideal solution segregates access to the dynamic table based on the entity | ||||||||||||||
that is constructing header fields. Header field values that are added to the | ||||||||||||||
table are attributed to an entity, and only the entity that created a particular | ||||||||||||||
value can extract that value. | ||||||||||||||
|
||||||||||||||
To improve compression performance of tqhis option, certain entries might be tagged as being public. For example, a web browser might make the values of the Accept-Encoding header field available in all requests. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
An encoder without good knowledge of the provenance of header fields might | ||||||||||||||
instead introduce a penalty for a header field with many different values, such | ||||||||||||||
that a large number of attempts to guess a header field value results in the | ||||||||||||||
header field no more being compared to the dynamic table entries in future | ||||||||||||||
messages, effectively preventing further guesses. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I had a little trouble with "no more". |
||||||||||||||
|
||||||||||||||
Note: | ||||||||||||||
|
||||||||||||||
Simply removing entries corresponding to the header field from the dynamic table | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
can be ineffectual if the attacker has a reliable way of causing values to be | ||||||||||||||
reinstalled. For example, a request to load an image in a web browser typically | ||||||||||||||
includes the Cookie header field (a potentially highly valued target for this | ||||||||||||||
sort of attack), and web sites can easily force an image to be loaded, thereby | ||||||||||||||
refreshing the entry in the dynamic table. | ||||||||||||||
|
||||||||||||||
This response might be made inversely proportional to the length of the header | ||||||||||||||
field value. Marking a header field as not using the dynamic table any more | ||||||||||||||
might occur for shorter values more quickly or with higher probability than for | ||||||||||||||
longer values. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
## Never Indexed Literals | ||||||||||||||
|
||||||||||||||
Implementations can also choose to protect sensitive header fields by not | ||||||||||||||
compressing them and instead encoding their value as literals. | ||||||||||||||
|
||||||||||||||
Refusing to insert a header field into the dynamic table is only | ||||||||||||||
effective if doing so is avoided on all hops. The never indexed literal bit (see | ||||||||||||||
{{literal-name-reference}}) can be used to signal to intermediaries that a | ||||||||||||||
particular value was intentionally sent as a literal. | ||||||||||||||
|
||||||||||||||
An intermediary MUST NOT re-encode a value that uses a literal representation | ||||||||||||||
with the 'N' bit set with another representation that would index it. If QPACK | ||||||||||||||
is used for re-encoding, a literal representation with the 'N' bit set MUST be | ||||||||||||||
used. If HPACK (see Section 6.2.3 of [RFC7541]) is used for re-encoding, the | ||||||||||||||
never indexed literal representation MUST be used. | ||||||||||||||
afrind marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
The choice to use a never indexed literal representation for a header field | ||||||||||||||
afrind marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
depends on several factors. Since QPACK doesn't protect against guessing an | ||||||||||||||
entire header field value, short or low-entropy values are more readily | ||||||||||||||
recovered by an adversary. Therefore, an encoder might choose not to index | ||||||||||||||
values with low entropy. | ||||||||||||||
|
||||||||||||||
An encoder might also choose not to index values for header fields that are | ||||||||||||||
considered to be highly valuable or sensitive to recovery, such as the Cookie or | ||||||||||||||
Authorization header fields. | ||||||||||||||
|
||||||||||||||
On the contrary, an encoder might prefer indexing values for header fields that | ||||||||||||||
have little or no value if they were exposed. For instance, a User-Agent header | ||||||||||||||
field does not commonly vary between requests and is sent to any server. In that | ||||||||||||||
case, confirmation that a particular User-Agent value has been used provides | ||||||||||||||
little value. | ||||||||||||||
|
||||||||||||||
Note that these criteria for deciding to use a never indexed literal | ||||||||||||||
representation will evolve over time as new attacks are discovered. | ||||||||||||||
|
||||||||||||||
##. Static Huffman Encoding | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
|
||||||||||||||
There is no currently known attack against a static Huffman encoding. A study | ||||||||||||||
has shown that using a static Huffman encoding table created an information | ||||||||||||||
leakage, however this same study concluded that an attacker could not take | ||||||||||||||
advantage of this information leakage to recover any meaningful amount of | ||||||||||||||
information (see [PETAL]). | ||||||||||||||
afrind marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
## Memory Consumption | ||||||||||||||
|
||||||||||||||
An attacker can try to cause an endpoint to exhaust its memory. QPACK is | ||||||||||||||
designed to limit both the peak and state amounts of memory allocated by an | ||||||||||||||
endpoint. | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error is in the HPACK RFC. Is it worth an errata? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll let you manage that :) You can be the author of an RFC erratum. The glory! |
||||||||||||||
|
||||||||||||||
The amount of memory used by the compressor is limited by the protocol using | ||||||||||||||
afrind marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
QPACK through the definition of the maximum size of the dynamic table, and the | ||||||||||||||
maximum number of blocking streams. In HTTP/3, these values are controlled by | ||||||||||||||
the decoder through the setting parameter QPACK_MAX_TABLE_CAPACITY and | ||||||||||||||
QPACK_BLOCKED_STREAMS, respectively (see Section | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
{{maximum-dynamic-table-capacity}} and {{blocked-streams}}). The limit on the | ||||||||||||||
size of the dynamic table takes into account both the size of the data stored in | ||||||||||||||
the dynamic table, plus a small allowance for overhead. The limit on the number | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "both" does not flow well with "plus". Either s/", plus"/" and"/, or remove "both". |
||||||||||||||
of blocked streams is only a proxy for the maximum amount of memory required by | ||||||||||||||
the decoder. The actual maximum amount of memory will depend on how much memory | ||||||||||||||
the decoder uses to track each blocked stream. | ||||||||||||||
|
||||||||||||||
A decoder can limit the amount of state memory used for the dynamic table by | ||||||||||||||
setting an appropriate value for the maximum size of the dynamic table. In | ||||||||||||||
HTTP/3, this is realized by setting an appropriate value for the | ||||||||||||||
QPACK_MAX_TABLE_CAPACITY parameter. An encoder can limit the amount of state | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: the doc is inconsistent about QPACK_MAX_TABLE_CAPACITY vs SETTINGS_QPACK_MAX_TABLE_CAPACITY. I don't know what the answer is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The text seems to consistently use SETTINGS_ variants, but the table omits it. I'll fix these to match the text, but SETTINGS_ seems redundant in the table. I'll resolve the inconsistency in another PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wfm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's an (unstated) norm to omit SETTINGS_ in cases where it's already blatantly obvious that we're discussing a setting. You'll find similar variance in 7540, 7541, and HTTP/3. |
||||||||||||||
memory it uses by signaling lower dynamic table size than the decoder allows | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
(see {{eviction}}). A decoder can limit the amount of state memory used for | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
blocked streams by setting an appropriate value for the maximum number of | ||||||||||||||
blocked streams. In HTTP/3, this is realized by setting an appropriate value | ||||||||||||||
for the QPACK_BLOCKED_STREAMS parameter. An encoder can limit the amount of | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: QPACK_BLOCKED_STREAMS vs. SETTINGS_QPACK_BLOCKED_STREAMS |
||||||||||||||
state memory by only using as many blocked streams as it wishes to support; no | ||||||||||||||
signaling to the decoder is requred. | ||||||||||||||
|
||||||||||||||
The amount of temporary memory consumed by an encoder or decoder can be limited | ||||||||||||||
by processing header fields sequentially. A decoder implementation does not need | ||||||||||||||
to retain a complete list of header fields while decoding a header block. An | ||||||||||||||
encoder implementation does not need to retain a complete list of header fields | ||||||||||||||
if while encoding a header block if it is using a single-pass encoder. Note | ||||||||||||||
afrind marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
that it might be necessary for an application to retain a complete | ||||||||||||||
header list for other reasons; even if QPACK does not force this to occur, | ||||||||||||||
application constraints might make this necessary. | ||||||||||||||
|
||||||||||||||
While the negotiated limit on the dynamic table size accounts for much of the | ||||||||||||||
memory that can be consumed by a QPACK implementation, data which cannot be | ||||||||||||||
|
@@ -1155,6 +1376,19 @@ to an excess of unsent data might include limiting the ability of the peer to | |||||||||||||
open new streams, reading only from the encoder stream, or closing the | ||||||||||||||
connection. | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
## Implementation Limits | ||||||||||||||
|
||||||||||||||
An implementation of QPACK needs to ensure that large values for integers, long | ||||||||||||||
encoding for integers, or long string literals do not create security | ||||||||||||||
weaknesses. | ||||||||||||||
|
||||||||||||||
An implementation has to set a limit for the values it accepts for integers, as | ||||||||||||||
well as for the encoded length (see {{prefixed-integers}}). In the same way, it | ||||||||||||||
has to set a limit to the length it accepts for string literals (see | ||||||||||||||
{{string-literals}}). | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we have a minimum size which MUST be supported; should that be mentioned here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @MikeBishop : I can't quite figure an elegant way to mention the minimum here. It is already mentioned in the referenced section. |
||||||||||||||
|
||||||||||||||
|
||||||||||||||
# IANA Considerations | ||||||||||||||
|
||||||||||||||
## Settings Registration | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.