- From: Kari Hurtta <hurtta-ietf@elmme-mailer.org>
- Date: Mon, 20 May 2019 07:28:51 +0300 (EEST)
- To: HTTP Working Group <ietf-http-wg@w3.org>
- CC: Mike West <mkwst@google.com>, Ilari Liusvaara <ilariliusvaara@welho.com>, Kari Hurtta <hurtta-ietf@elmme-mailer.org>
HTTP State Tokens https://tools.ietf.org/html/draft-west-http-state-tokens-00 Ilari Liusvaara: > - The request signing mechansims looks like one that would break if > there is some CDN or reverse proxy in the path that adds a header > or a few (sometimes with some non-standard one in the mix). Or is it > expected that all CDNs or reverse proxies on path for application > using this mechanism can rewrite the MAC? On my post "Signature" ( <20190504134512.38AF24F94E@welho-filter4.welho.com> https://lists.w3.org/Archives/Public/ietf-http-wg/2019AprJun/0112.html ) I suggested to exclude certain listed header fields and header fields listed in the Connection header field. But that is not enough. It is better that middleman does not rewrite signature. Considering my "Typical request for origin" --------------------------------------------- [ browser ] ⇓ https [ TLS termination and load balancing ] ⇓ http ⇓ http [ cache ] [ cache ] ⇓ http ⇓ http [ ----- reapplying TLS --------- ] ⇓ https [ TLS termination and load balancing ] ⇓ http ⇓ http [ origin web server ] [ origin web server ] ---------------------- In here many places can add X-Frowarded-For X-Forwarded-Proto Forwarded (RFC 7239) X-Forwarded-Host X-Forwarded-Port Via CDN-Loop (RFC 8586) header fields to request. And perhaps some others. Therefore the list of signed header field's names need to be added to Sec-Http-State request header field. Using is CBOR was justified with: 3.2. CBOR representation of exchange response headers https://tools.ietf.org/html/draft-yasskin-http-origin-signed-responses-05#section-3.2 | To sign an exchange's response headers, they need to be serialized | into a byte string. Since intermediaries and distributors | (Appendix A.2) might rearrange, add, or just reserialize headers, we | can't use the literal bytes of the headers as this serialization. When the list of signed header field's names are on Sec-Http-State request header field usage of CBOR is NOT justified. Order of header fields is given on the list of signed header field's names on Sec-Http-State request header field. This gives both spelling (lowercase or not) and order of header fields. There is nothing what using of CBOR adds. Other details need to be specified anyway. For example: | o The byte string ':status' to the byte string containing the | response's 3-digit status code, and | | o For each response header field, the header field's lowercase name | as a byte string to the header field's value as a byte string. These was not given by CBOR. There is some requirements: The list of signed header field's name must not include names of header fields where header field name occurs several times on request. The list of signed header field's names must not include names of header fields which occur on Connection header field. Also following header field's names must not be included to the list of signed header field's names: * Connection * Any header field name starting with Proxy- * Keep-Alive * Trailer * Transfer-Encoding * Upgrade * Forwarded * Any header field name starting with X-Frowarded- * Via * CDN-Loop If the list of signed header field's names on Sec-Http-State request header field includes non-existing header field, this header field is just skipped when calculating signature. These header field names effectively works as "don't add" list, because adding of them to request on transit changes signature. If he list of signed header field's names on Sec-Http-State request header field includes header fields which have more than one occurrence, FAIL calculating of signature. So 5.2. Generate a request's signature https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-5.2 ⇒ -------- || indicates catenation 0 indicates octet 0 (ASCII NUL). Note that redirection causes Sec-Http-State request header field and signature to be recalculated. This operates with request, which is httpRequest on 4.5. HTTP-network-or-cache fetch on Fetch standard. Given a request, a base64-encoded token value, and a key: 1. Generate decimal nonce value for request ( this may be implemented by storing nonce value to HTTP State Token for request's URL and incrementing that nonce. 2. Store generated nonce value as "nonce" for return triple. 3. Let "serialized-request" to be ":method:" || request's method || 0 || ":token:" || base64-encoded token value || 0 || ":url:" || request's current URL || 0 || :nonce:" || request's decimal nonce value || 0 4. Let "signed list" to be header field names from request's header list, excluding o header fields mentioned on Connection: header field o header fields which have more than one occurrence on request's header list o Connection o Any header field name starting with Proxy- o Keep-Alive o Trailer o Transfer-Encoding o Upgrade o Forwarded o Any header field name starting with X-Frowarded- o Via o CDN-Loop [TBD some other?] 5. [TBD: Add possible "don't add" header field names to "signed list". ] 6. For each "field name" in "signed list" 1. Retrieve "header value" of ""field name" from request's header list 2. If "header value" not found, skip next substeps 3. If more that one "header value" found, fail this algorithm 4. Append "field name" value || ":" || "header value" value || 0 to "serialized-request" Note that "serialized-request" uses field name spelling from "signed list" and not header field name spelling from request's header list. Specially, when checking signature, order and spelling of header field names from "signed-fields" is used. 7. Let "signed-fields" to be values from "signed list" with comma as separator. 8. Store "signed-fields" as "signed-fields" for return triple. 9. Let "sig" to be result of computing HMAC-SHA256 [RFC2104] over "serialized-request". 10. Store "sig" as "sig" for return triple. 11. Return triple ( "sig", "signed-fields", "nonce" ). ----- If there is retries on 4.6. HTTP-network fetch https://fetch.spec.whatwg.org/#http-network-fetch these use same "Sec-Http-State" header field and therefore same nonce on every retry. If server gets second request with same nonce value, it may 1. If request is identical (including request body) than original request with same nonce, server MAY return cached copy of response from original request with same nonce. Response MAY include update "Age" header field. Server MUST NOT execute request with have same nonce. [TBD: Should re-execution of request to be allowed, if request do not have side effects? ] 2. Otherwise server MAY return response with status 4xx "Duplicated nonce value". If server selects to not keep track used nonce values (per HTTP State Token key), server MAY process request as new. Note: Keeping track used nonce values is hard. Therefore server may elect to ignore nonce (except for signature validation). TBD: Should nonce value generation to be defined more rigorously, and then allow server return 4xx "Duplicated or bad nonce value" when nonce value is far off from next expected nonce value? If nonce is defined to be stored on HTTP State Token for origin and incremented from here, this also makes middleman hard to do own requests, because all request need change nonce and therefore recalculate signature. 5.1. Attach HTTP State Tokens to a request https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-5.1 | 9. If "request-token"'s "key" is not null, then insert a member | into "header-value" whose key is "sig", and whose value is the | result of executing Section 5.2 on request, "serialized-value", | and "request-token"'s "key". ⇒ -------- 9. If "request-token"'s "key" is not null, then 9.1 Execute Section 5.2 on request, "serialized-value", and "request-token"'s "key". Result have triple ( "sig", "signed-fields", "nonce" ) 9.2 Insert a member into "header-value" whose key is "sig", whose value is "sig" from triple (using byte sequence (sh-binary, [draft-ietf-httpbis-header-structure-10], Section 3.10) syntax). 9.3 Insert a member into "header-value" whose key is "signed-fields", whose value is "signed-fields" from triple (using string syntax, [draft-ietf-httpbis-header-structure-10], Section 3.8). 9.4 Insert a member into "header-value" whose key is "nonce", whose value is "nonce" from triple (using integer syntax, [draft-ietf-httpbis-header-structure-10], Section 3.6). -------- 4.1. The 'Sec-Http-State' HTTP Header Field https://tools.ietf.org/html/draft-west-http-state-tokens-00#section-4.1 | The dictionary MAY contain: Add ⇒ -------- o Exactly one member whose key is "nonce" , and whose value is integer ([draft-ietf-httpbis-header-structure-10], Section 3.6). o Exactly one member whose key is "signed-fields", and whose value is string ( [draft-ietf-httpbis-header-structure-10], Section 3.6). ---------
Received on Monday, 20 May 2019 04:29:26 UTC