Re: h2 padding

On Wed, Sep 3, 2014 at 1:12 PM, Roy T. Fielding <fielding@gbiv.com> wrote:
> On Sep 2, 2014, at 11:07 PM, Brian Smith wrote:
>> Consider an implementation that sends every frame in its own TCP
>> packet, perhaps with a 1 minute delay between frames. Such an
>> implementation would conform to Roy's suggestion, but it would
>> partially or completely defeat the purpose of the padding.
>
> Perhaps it will help if we clarify the assumptions here.  The first is
> that the application is adding padding for a reason and not simply because
> it is cool.  The second is that the rate at which they send data is under
> their control, along with how that data is arranged in h2 padded form.

In order for padding to be a useful security feature, it must provide
end-to-end protection. That is, when the origin server sends
data||padding, that data||padding needs to be preserved and processed
as a single unit through all hops (i.e. by any/all proxies). But,
draft 14 doesn't say that. Therefore, the assumption that "how that
data is arranged in h2 padded form" is under the applications' control
is violated with in draft 14.

> Deliberately sending h2 padding in a form that defeats its purpose is not
> a design consideration.

I agree. But, *accidentally* defeating the purpose of padding *is* a
valid, and important, design consideration. My points are (1) the
current draft doesn't give enough advice about how to process padding
in a way that makes it useful, and (2) separating the padding into its
own frame makes such accidental defeat of the purpose of padding more
likely.

>> To make the
>> change that Roy suggested safe(r), there would have to be the
>> additional restriction that a padding frame and the frame it is
>> associated with are not split this way. This seems like a difficult
>> thing to formulate. More importantly, it seems extremely error-prone
>> and thus it would be a counterproductive change in terms of security.
>
> No.  There is no need to require that cars be unable to change lanes
> just because some driver might be drunk at the wheel. Absolute security is
> not a design goal.  It is sufficient to design a protocol that can be used
> for a given purpose when that purpose is understood.

In general, it is unreasonable to expect implementations to correctly
implement this security feature when the way to correctly implement it
is unspecified. The correct processing of padding, in particular, is
extremely non-obvious.

>> Note that the current draft doesn't prohibit an implementation from
>> sending the padding part of a DATA frame in one packet and the actual
>> data part in a separate packet, with our without delays between them.
>> Similarly, it seems like a proxy is allowed to split a DATA frame into
>> two DATA frames and/or coalesce them together. The draft needs to be
>> updated to prohibit any such special processing of the padding
>> distinctly from the actual data. Regardless, this should be easier to
>> formulate for the current single-frame situation than it would be with
>> Roy's separate-frame proposal.
>
> Not at all.  And, no, the draft does not need to forbid bad implementations
> of padding.  Warning against them is okay.

Then the resulting padding mechanism would not be useful to anybody.
If you can't rely on a specification-compliant implementation to
preserve the security properties of your padding, then you can't rely
on padding solving the security problems it was intended to solve, and
you need to find an alternative. But, if everybody needs to find an
alternative to HTTP/2 padding because its security properties are
unreliable, then there's no reason to specify padding in HTTP/2, and
it should just be removed from the spec.

>> It would also be more difficult to reformulate the requirement "All
>> implementations MUST be capable of receiving and minimally processing
>> frames up to 2^14 octets in length, plus the 9 octet frame header
>> (Section 4.1)" to work with a separate padding frame. (I hope the
>> reason is obvious; if not, I can explain more.)
>
> No, it makes no difference whatsoever.  If the requirement was that they
> only be able to process exactly 2^14 octets and you assume that an attacker
> can inject 2^14 octets into the data without being detected, then something
> might break somewhere.  However, there is nothing to suggest that the
> break would have anything to do with a frame boundary.

Currently, implementations are allowed to break up the data stream
into TLS records and/or TCP packets or whatever, in whatever way they
want. So, we have to assume some implementations will choose to split
the data stream at the frame boundary.

>  For both the
> current spec and any suggested changes, padding only works if both
> the data and padding are written to the network in the same way, without
> any difference at the padding boundaries, and they are both subject to
> flow control in the same way.

That is exactly my point. Since the padding and the data the padding
is protecting need to be treated as a single unit, and we have to
assume that at least some implementations will split the data stream
at the frame boundary, then it is safer and less error-prone to keep
the padding together with the data in one frame.

> An application with enough control over
> h2 to generate h2 padding will also be capable of managing the amount
> of data placed in each h2 frame.

Again, the data||padding sequence needs to be preserved end-to-end in
order for padding to be useful to any endpoint. We could try to figure
out if it is true that every endpoint has the level of control you are
assuming over its own networking stack, but it is obvious that the
endpoint cannot control what intermediaries do. That is why the
specification needs to minimize the risk that intermediaries will mess
up the padding, and that is why the current less-error-prone
padding-within-data-frame mechanism is better than padding in a
separate frame.

> I think you are assuming there is some magic boundary between frames
> other than the length delimitation.  There is none.  An application can
> write two frames just as easily as it can write one frame with optional
> pad length and optional padding at the end.  The only difference is
> where the overhead occurs.

Again, the data||padding must be preserved intact end-to-end in order
for it to be useful for an endpoint. What each individual endpoint is
capable of doing is not the issue; the issue is what intermediaries
are allowed to do.

> If I thought that anyone would use padding on a regular basis, then
> I would make the pad-length part of a fixed frame header that everyone
> has to send.  My suggestion to use separate padding frames is partly
> because I don't think it will be used at all, or at least only under
> very specific circumstances that can justify the overhead.

I support the first part of your proposal, to remove the padding from
data frames. But, I am firmly against the second part of your
proposal, which is to add a new frame for padding, because the
specification of the secure and efficient use of separate padding
frames would be much more complicated, and that complication would
make the padding mechanism more error-prone.

Cheers,
Brian

Received on Wednesday, 3 September 2014 22:32:12 UTC