Subject: Design Issue: Overlong Frames

From: James M Snell <[email-masked]>
Date: Thu, 9 May 2013 10:26:16 -0700

In going through a number of issues relating to frame sizes, I note
that the spec currently does not deal with the issue of "overlong" or
padded frames. That is, what happens if a frame contains more data
than what is explicitly called for in it's definition.

For instance, the GOAWAY frame currently defines it's payload as a
32-bit error code. What happens if that frame contains more than
32-bits? .. e.g.

  00 40 07 00 00 00 00 00
  0A BC DE FF FF FF FF FF

An implementation that is not being careful could completely miss the
extra junk bytes here. For GOAWAY it's obviously not too much of a
concern, but the risk for abuse exists for all frames that define a
specific structure for the payload data.

Recommendation: Adding a short statement that a PROTOCOL_ERROR MUST be
returned if a frame contains more bytes than what is expressly
specified in the frame definition.

- James

---

From: Martin Thomson <[email-masked]>
Date: Fri, 10 May 2013 10:36:41 -0700

> specified in the frame definition.

That would prevent extension unnecessarily.  And it doesn't do
anything to improve security.

When you want to harden security, you need to consider what equivalent
options are available to an attacker.  If I wanted to send you more
data, then I will use DATA frames.  Unless you can find a way to
curtail DATA I see no reason to clamp down here.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 10 May 2013 12:00:20 -0700

On 10 May 2013 11:29, James M Snell <[email-masked]> wrote:
> On Fri, May 10, 2013 at 10:36 AM, Martin Thomson
> <[email-masked]> wrote:
> How does it prevent extension? If someone wants to extend an existing
> frame to include new data, it can define a new frame type.

I can't extend GOAWAY.  Who knows, maybe I might want to be more
specific about the streams that will be processed prior to session
end.

> In my experience, it's generally better to limit the exploitation options ;-)

It doesn't limit options in any meaningful way.  This would be
analogous to double-deadlocking the front door while leaving the
adjacent windows wide open.  I know that the extension argument isn't
especially strong, for a range of reasons, but I see no point in
over-engineering this aspect.

---

From: James M Snell <[email-masked]>
Date: Fri, 10 May 2013 11:29:16 -0700

- James

---

From: James M Snell <[email-masked]>
Date: Fri, 10 May 2013 12:40:33 -0700

> specific about the streams that will be processed prior to session

If there are non-theoretical reasons for why one may wish to extend a frame
like goaway, then extensibility should be expressly included in the design
as part of the format.

- James

---

From: William Chan (陈智昌) <[email-masked]>
Date: Fri, 10 May 2013 16:56:20 -0300

Non-theoretical reason for extending GOAWAY: adding debug strings
explaining an error in more detail.

No comment on extensibility mechanisms.

On Fri, May 10, 2013 at 4:40 PM, James M Snell <[email-masked]> wrote:

> If there are non-theoretical reasons for why one may wish to extend a
> frame like goaway, then extensibility should be expressly included in the
> design as part of the format.
>
> - James
>

---

From: James M Snell <[email-masked]>
Date: Fri, 10 May 2013 13:03:55 -0700

If that's a real possibility, then we can easily add an optional length
prefixed text field to the goaway frame definition.
On May 10, 2013 12:56 PM, "William Chan (陈智昌)" <[email-masked]>

---

From: James M Snell <[email-masked]>
Date: Fri, 10 May 2013 14:36:33 -0700

FWIW, one possible attack vector this would help mitigate is "frame smuggling"..

For example, suppose an attacker is sending a request through a proxy
that is designed to filter out certain kinds of bad requests. The
attacker determines that while the proxy properly examines both the
size and type of a frame, it ignores extraneous bytes in known frame
types and simply passes those thru. The origin server, on the other
hand, only looks at the frame type and does not properly deal with
frame length. So, to get its bad message through the proxy that would
normally filter it out ...

1. The attacker first sends an apparently innocent initial HEADERS
frame to initialize a stream...
2. Then sends a manipulated RST_STREAM frame that includes the error
code and the complete smuggled frame as additional payload.
3. The proxy sees the RST_STREAM, checks the error code and just
passes that through, ignoring the smuggled frame as "extraneous"
4. The origin receives the RST_STREAM and parses out only the error
code bits without paying proper attention to the frame size (that is,
it stops reading the frame once it parses the error code, mistakenly
thinking that that's all there is)
5. The origin then moves on to receive the next frame which ends up
being the smuggled bad frame that the proxy allowed through.

The solution is simple: require endpoints to always process the full
reported frame size when processing frames, and for those frames that
we know absolutely shouldn't contain extra bytes, disallow them from
doing so.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 10 May 2013 15:21:15 -0700

On 10 May 2013 14:36, James M Snell <[email-masked]> wrote:
> types and simply passes those thru.

There is your problem right there.  A proxy that wants to prevent this
sort of covert activity needs to look for unknown frame types, unknown
headers, unknown message bodies AND unknown frame parameters.

It should also look for all of the other covert channels in HTTP, of
which there are a wondrously large number available.  It would be a
sorry smuggler who had to resort to message timing for their covert
channel in this protocol.

---

From: James M Snell <[email-masked]>
Date: Fri, 10 May 2013 16:29:00 -0700

See: [1] and [2] for pull requests with suggested spec text dealing
with this issue:

[1] https://github.com/http2/http2-spec/pull/92 (re: frame sizes)
[2] https://github.com/http2/http2-spec/pull/93 (re: security considerations)