Subject: [Json] Nested JSON encoding style too likely to be insecure

From: "Manger, James" <[email-masked]>
Date: Tue, 23 Feb 2016 16:49:00 +1100

I'm a bit late to the party on the "On flat vs nested JSON encoding style" thread...

The nested style that Phillip was encouraging is:

{ "A" :
   { "field1" : "value1", "field2" : "value2", "field3" : "value3" } }

It looks like messages in this style (requests and responses) would always have a top-level JSON object with a single member identifying the type of message ("A" in this example). An app might get this member from an iterator over the object (eg in Java when using a Map to represent a JSON object: op = map.entrySet().iterator().next();).

But what happens if a message (maliciously) has two elements in the top-level object?

{ "READ" :
   { "field1" : "value1", "field2" : "value2", "field3" : "value3" },
  "DELETE":
   { "field1" : "value1", "field2" : "value2", "field3" : "value3" } }

A receiving app (expecting 1 element) could easily pick either "READ" or "DELETE" and ignore the other. If an authorization layer picks "READ" and allows the message through, then the backend picks "DELETE" and acts accordingly... ouch.

This nested style looks cute, but is probably too cute as "obvious" ways to implement it can easily be insecure.
If we want to ensure a message type to come before its content then we should use a JSON array: [type, content].
--
James Manger

---

From: Phillip Hallam-Baker <[email-masked]>
Date: Tue, 23 Feb 2016 00:54:17 -0500

On Tue, Feb 23, 2016 at 12:49 AM, Manger, James
<[email-masked]> wrote:
> I’m a bit late to the party on the “On flat vs nested JSON encoding style”
> thread…
>
>
>
> It looks like messages in this style (requests and responses) would always
> have a top-level JSON object with a single member identifying the type of
> message (“A” in this example). An app might get this member from an iterator
> over the object (eg in Java when using a Map to represent a JSON object: op
> = map.entrySet().iterator().next();).
>
>
>
> A receiving app (expecting 1 element) could easily pick either “READ” or
> “DELETE” and ignore the other. If an authorization layer picks “READ” and
> allows the message through, then the backend picks “DELETE” and acts
> accordingly… ouch.
>
>
>
> This nested style looks cute, but is probably too cute as “obvious” ways to
> implement it can easily be insecure.
>
> If we want to ensure a message type to come before its content then we
> should use a JSON array: [type, content].

You need to limit the toplevel to one element. That is fairly easy to do though.

---

From: "Manger, James" <[email-masked]>
Date: Tue, 23 Feb 2016 17:08:30 +1100

> You need to limit the toplevel to one element. That is fairly easy to do though.

Easy to do; but even easier not to do. Does your code already do this?
This is not the sort of check I want to rely on developers making. It is not obvious that the check is needed; certainly not from looking at a few sample messages.

Checking there is only 1 top-level element can't be done until you get to the end of the first element’s value — which seems to clash with your rationale for the nested style.

A JSON array still looks better.

--
James Manger

---

From: John Cowan <[email-masked]>
Date: Tue, 23 Feb 2016 07:08:44 -0500

> A JSON array still looks better.

I agree; but JSON validation is better yet.

-- 
John Cowan          http://www.ccil.org/~cowan        [email-masked]
De plichten van een docent zijn divers, die van het gehoor ook.
      --Edsger Dijkstra

---

From: Phillip Hallam-Baker <[email-masked]>
Date: Tue, 23 Feb 2016 08:21:11 -0500

> A JSON array still looks better.

Lets look at the 'attack' you are proposing here - a maliciously
formatted request. Does it really make sense?

This isn't the normal buffer overrun type malicious request, you are
postulating one of the requests is valid and the other isn't. How is
an attacker meant to inject the second attack?

---

From: John Cowan <[email-masked]>
Date: Tue, 23 Feb 2016 09:00:32 -0500

> an attacker meant to inject the second attack?

As I understand it, the idea is that there is a service which permits
anyone to read, but requires credentials of some kind in order to write.
There is a two-stage pipeline consisting of a validator and an execution
agent.  A hybrid (invalid) request containing both read and write
is sent by the black hat.  The validator by chance looks at the read
request and passes the hybrid through without checking any credentials.
The execution agent, however, by chance sees the write request and acts
on it, assuming that the validator has properly checked it.  Oops.

Obviously the problem is that the validator is too liberal in what
it accepts, and should ensure that the request is well-formed before
applying its rules.

-- 
John Cowan          http://www.ccil.org/~cowan        [email-masked]
Eric Raymond is the Margaret Mead of the Open Source movement.
          --Bruce Perens, a long time ago