You are viewing a plain text version of this content. The canonical link for it is here.
Posted to bugs@httpd.apache.org by bu...@apache.org on 2019/12/19 09:19:13 UTC

[Bug 63434] Multiple Cookie headers combined to one comma-separated header line

https://bz.apache.org/bugzilla/show_bug.cgi?id=63434

--- Comment #7 from rgagnon24@gmail.com ---
I can confirm I've seen this behavior as well.  The problem stems from bad
clients under HTTP/1.1.

HTTP/2 allows for multiple "Cookie" headers, but the problem shows really when
a HTTP/1.1 user-agent incorrectly sends multiple Cookie headers.

Apache is compressing them with ", " into one header.  This leads to an
improper single Cookie value that some language like PHP (or others) will then
not be able to properly parse (as commas are allowed characters within the
value of a cookie), and because cookie parsers in most interpreters are going
to "split" the key-value pairs out of the single Cookie: value by looking for a
semi-colon to split on, and then creating the key-value pairs from those.

So RFC6265 (https://tools.ietf.org/html/rfc6265#page-7) shows how servers can
send multiple "Set-Cookie" headers (to support proxies like load balancers, etc
injecting their own cookies), but as the OP stated, 5.4 states the user agent
MUST NOT attach more than one Cookie header field" (which is correct for
HTTP/1.1)

The compression routine in apache is technically not at fault (sort of) because
it is combining multiple headers as other RFCs allow, but the issue it would be
nice if (for the Cookie header) that httpd could play nice with a bad
user-agent, and fix the multiple "Cookie" header mistake the UA makes, so that
the parser behind httpd can properly see the values.

Scenario 1: Similar example to the OP, imagine a bad UA sends back:

Cookie: foo1=hello, world
Cookie: foo2=How are you, sam?

Current httpd would compress this into:

Cookie: foo1=hello, world, foo2=How are you, sam?

Then some processor looking at the COOKIE value, would only see a single cookie
with the key "foo1" and a value of "hello, world, foo2=How are you, sam?" 

If the processor were to try and split on the ", " that the
apr_table_compress() inserted, it would not properly be able to parse the
string because the parts would be:

foo1=hello
world
foo2=How are you
sam?

However, if the "Cookie" header were given special-case treatment (as would be
needed under an HTTP/2 transaction anyhow, then the routine would create:

Cookie: foo1=hello, world;foo2=How are you, sam?

Which, current processors will properly split with semicolon delimiting that
they expect in the Cookie value.

In the case of PHP, the current problem with the apr_table_compress() in regard
to Cookie is that the resulting $_COOKIE array in that language will miss
seeing Cookies that should be present, which can lead to broken SESSION's as
the session-id used is stored in the Cookie header---like any other language.

We've seen this with incompatible UA's communicating with server banks behind
load balancers especially.

Scenario 2: UA connects to a server through a proxy like a load balancer that
adds its own cookie for state tracking, and a server that adds the cookie value
"PHPSESSID" for session tracking.

When the server initiates the response back to the UA, it will add something
like:

Set-Cookie: PHPSESSID=XXXXXXXXXXXX; path=/

On the way through the proxy, the proxy (like and F5 load balancer) adds its
own cookie:

Set-Cookie: BIGipServer~XXXXX~XXXX=XXXXX; expires=Some date; path=/; Httponly

Now, the poor broken HTTP/1.1 User-agent (which is supposed to combine those 2
headers into one, but does not), sends back:

Cookie: PHPSESSID=XXXXXXXXXXXX
Cookie: BIGipServer~XXXXX~XXXX=XXXXX

apr_table_compress() now proceeds to combine those into one header before PHP
gets it:

Cookie: PHPSESSID=XXXXXXXXXXXX, BIGipServer~XXXXX~XXXX=XXXXX

When PHP now looks to find it's session data, it can't find it because the
value for "PHPSESSID" now appears as "XXXXXXXXXXXX,
BIGipServer~XXXXX~XXXX=XXXXX"

Worse yet, if the bad user-agent sends the headers in a different order, PHP
won't even find a value at all for "PHPSESSID" because there will be no Cookie
that starts like that... for example:

Cookie: BIGipServer~XXXXX~XXXX=XXXXX
Cookie: PHPSESSID=XXXXXXXXXXXX

Would become:

Cookie: BIGipServer~XXXXX~XXXX=XXXXX, PHPSESSID=XXXXXXXXXXXX

And the only thing then present in $_COOKIE would be the key
"BIGipServer~XXXXX~XXXX" with the value "XXXXX, PHPSESSID=XXXXXXXXXXXX"

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: bugs-unsubscribe@httpd.apache.org
For additional commands, e-mail: bugs-help@httpd.apache.org