Re: JSON headers

--------
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