- From: Poul-Henning Kamp <phk@phk.freebsd.dk>
- Date: Sun, 10 Jul 2016 22:20:18 +0000
- To: Julian Reschke <julian.reschke@gmx.de>
- cc: Yanick Rochon <yanick.rochon@gmail.com>, Phil Hunt <phil.hunt@oracle.com>, HTTP Working Group <ietf-http-wg@w3.org>
-------- In message <176d58df-debf-e660-edf7-7d686c926ef6@gmx.de>, Julian Reschke writes : >It seems you are confusing several issues here: multiple header field >instances in the HTTP message, and duplicate member names in a JSON >object. These are completely orthogonal issues. Uhm, no? They only become orthogonal if whoever specifies the JSON header takes great care to make that happen. Allowing split headers forces all headers to be defined as JSON lists, which means we're knee-capping header-designers from the get go. Take this RFC7231 example: Accept: text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c If we allow split headers for JSON, this can only be defined as JSON list, in order that it can also be sent as: Accept: <JSON for "text/plain; q=0.5"> Accept: <JSON for "text/html"> Accept: <JSON for "text/x-dvi; q=0.8"> Accept: <JSON for "text/x-c"> But that leaves it to the application writer to spot and detect and handle this degenerate case from a lazy sender: Accept: <JSON for "text/plain; q=0.5"> Accept: <JSON for "text/html"> Accept: <JSON for "text/x-dvi; q=0.8"> Accept: <JSON for "text/x-c"> Accept: <JSON for "text/plain; q=0.0"> It's even more complicated for a proxy sender which wants to modify the text/plain priority: It needs to spot both copies and change them both (or delete one of them). (It seems to me that there is a class of smuggling attacks where the proxy sees q=0.5 and the server q=0.0, which RFC7231 does not seem address at all?) If we instead, as I propose, require that JSON headers *never* be split, then it becomes both possible and rather obviously smarter to define this header as a JSON object, keyed by the media type: Accept: { \ "text/plain": <JSON for "q=0.5">, \ "text/html": <JSON for no parameter>, \ "text-xdvi": <JSON for "q=0.8">, \ "text/x-c": <JSON for no parameter> \ } A sender wishing to modify the priority, just sets the corresponding JSON object using the native languages JSON facility: req.accept["text/plain"] = <JSON for "q=0"> The receiver can then simply load the JSON as JSON, and the application does not have to explicitly check for duplicate media types, but can simply look up "text/plain" in the JSON object. So what happens if the sender sends bad JSON anyway ? Accept: { \ "text/plain": <JSON for "q=0.5">, \ "text/html": <JSON for no parameter>, \ "text-xdvi": <JSON for "q=0.8">, \ "text/x-c": <JSON for no parameter> \ "text/plain": <JSON for "q=0.0">, \ } Well, RFC7159 says: 4. Objects [...]The names within an object SHOULD be unique. An object whose names are all unique is interoperable in the sense that all software implementations receiving that object will agree on the name-value mappings. When the names within an object are not unique, the behavior of software that receives such an object is unpredictable. Many implementations report the last name/value pair only. Other implementations report an error or fail to parse the object, and some implementations report all of the name/value pairs, including duplicates. In other words: Don't do that. What really happens is this: We just opened another door to the exact same smuggling attack as I mentioned above. But this time we can shut them all with one single line of text: "Duplicate keys in JSON objects SHALL cause and be treated as connection failure." So all in all, split JSON headers would be a really bad idea. -- Poul-Henning Kamp | UNIX since Zilog Zeus 3.20 phk@FreeBSD.ORG | TCP/IP since RFC 956 FreeBSD committer | BSD since 4.3-tahoe Never attribute to malice what can adequately be explained by incompetence.
Received on Sunday, 10 July 2016 22:20:46 UTC