pshtt
pshtt copied to clipboard
Update HSTS check
This PR would update the hsts_check()
function's method of processing the HSTS header. Currently we do not closely conform to RFCs 7230 and 6797 with regard to valid header formats. This is specifically related to domains returning multiple Strict-Transport-Security
headers. This has allowed some domains to pass checks they might not otherwise because they are responding with an invalid HSTS header format.
This change would result in domains that previously passed some checks now failing them. However, if it is a result of them failing to conform to the RFC specification then I believe that is appropriate. This is still a lenient change because we use the first header instead of immediately failing if multiple headers are seen.
This is in part a result of the requests library assuming that a response with multiple header fields with the same field name conform to 7230-3.2.2. It concatenates them with a comma so in a server incorrectly outputting multiple Strict-Transport-Security
headers it combines them following the guidelines of 7230-3.2.2.
Example HTTP response (just Strict-Transport-Security
fields from curl output):
< Strict-Transport-Security: max-age=31536000
< Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
< Strict-Transport-Security: max-age=31536000
becomes
"max-age=31536000, max-age=31536000; includeSubDomains; preload, max-age=31536000"
The same domain run against the Qualys SSL Labs SSL Server Test:
Server sent invalid HSTS policy. See below for further information. Strict Transport Security (HSTS) | Invalid Server provided more than one HSTS header
Per RFC 7230 section 3.2.2:
A sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that header field is defined as a comma-separated list [i.e., #(values)] or the header field is a well-known exception (as noted below).
Per RFC 6797 section 6.1:
Strict-Transport-Security = "Strict-Transport-Security" ":"
[ directive ] *( ";" [ directive ] )
directive = directive-name [ "=" directive-value ]
directive-name = token
directive-value = token | quoted-string
where:
token = <token, defined in [RFC2616], Section 2.2>
quoted-string = <quoted-string, defined in [RFC2616], Section 2.2>