Opened 5 years ago
Closed 5 years ago
#1934 closed defect (duplicate)
Unpredictable behaviour using proxy_cookie_path to add SameSite cookie attribute
Reported by: | Owned by: | ||
---|---|---|---|
Priority: | critical | Milestone: | |
Component: | documentation | Version: | 1.17.x |
Keywords: | Cc: | ||
uname -a: | Linux tszcwpp001 2.6.32-754.25.1.el6.x86_64 #1 SMP Wed Nov 20 15:07:26 EST 2019 x86_64 x86_64 x86_64 GNU/Linux | ||
nginx -V: |
nginx version: nginx/1.17.6
built by gcc 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) built with LibreSSL 3.0.2 TLS SNI support enabled configure arguments: --prefix=/home/erandall/build/nginx-build/install/nginx-1.17.6 --with-pcre=/home/erandall/build/nginx-build/compile/pcre-8.43 --with-pcre-jit --with-zlib=/home/erandall/build/nginx-build/compile/zlib-1.2.11 --with-openssl=/home/erandall/build/nginx-build/compile/libressl-3.0.2 --with-http_ssl_module --with-http_v2_module --with-http_auth_request_module --with-http_slice_module --without-http_autoindex_module --without-http_browser_module --without-http_empty_gif_module --without-http_fastcgi_module --without-http_geo_module --without-http_grpc_module --without-http_memcached_module --without-http_mirror_module --without-http_scgi_module --without-http_split_clients_module --without-http_ssi_module --without-http_upstream_hash_module --without-http_upstream_ip_hash_module --without-http_upstream_least_conn_module --without-http_upstream_zone_module --without-http_userid_module --without-http_uwsgi_module --with-threads --with-file-aio |
Description
Use-Case:
We are attempting to use alter cookie attibutes for the Chrome browser, in view of the upcoming SameSite
changes per https://www.chromium.org/updates/same-site
Configuration
The nginx is configured as a proxy in front of apache-tomcat. SSL is terminated on Nginx. Session cookies are set by Tomcat. For architectural reasons we need to add the SameSite=None
attribute at the nginx proxy layer for Chrome users.
Hence we have a configuration consisting of (heavily abbreviated):
http { map $http_user_agent $samesite_attr { "~*chrome" '; SameSite=None'; } upstream local_tomcat { server 127.0.0.1:8080 fail_timeout=0; keepalive 100; } server { listen 9443 ssl http2; location / { proxy_pass http://local_tomcat; proxy_cookie_path ~/(.*) "/$1$samesite_attr"; } } }
Expected behaviour
When the backend tomcat returns a set_cookie
header and the user-agent string contains 'Chrome', we expected to see ; SameSite=None
appended on the cookie attribute list.
(The cookie already contains the Secure
attribute btw.)
Observed behaviour
Initially users on Chrome started to report website availability issues and 'gateway timeout' errors. Using a plugin to alter the Chrome user-agent string to impersonate IE10 reverted to normal working behaviour.
Further investigation using 'Curl' showed that, after Tomcat processing completes, sometimes the HTTP/2 response became corrupted. Downgrading to http1.1 allowed us to observe the Set-Cookie header - this sometimes contained a fragment of the User-Agent string interspersed within the value.
Examples:
1) Using HTTP/2 and user-agent: chrome
:
Response:
* Connection state changed (MAX_CONCURRENT_STREAMS updated)! * http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [set-cookie], value: [JSESSION_blk-idp02=8991A33D964779B87765BE4CD56A2FF3; Path=/; SameSite=None] * HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1) * Closing connection 0 * TLSv1.2 (OUT), TLS alert, Client hello (1): } [2 bytes data] curl: (92) HTTP/2 stream 1 was not closed cleanly: PROTOCOL_ERROR (err 1)
2) Using HTTP/1.1 and a longer user-agent string incorporating the word chrome
:
Tomcat set-cookie:
JSESSION_blk-idp02=6CD6436F1944BD877C73AE0EDAF301FB; Path=/userplatform; Secure; HttpOnly
Response:
< set-cookie: JSESSION_blk-idp02=6CD6436F1944BD877C73AE0EDAF301FB; Path=/ ; SameSite=Noneuserplatform; Secure; HttpOnly
We tried a number of different tactics to work-around the problem:
- using two maps (to distance the user-agent string from the $samesite_attr value);
- Removing the regex on
proxy_cookie_path
, instead hard-coding the cookie paths used by the application;
Unfortunately these were unsuccessful.
This leaves us concluding that there's an underlying issue with the proxy_cookie_path directive not being thread/memory safe.
Change History (3)
comment:1 by , 5 years ago
comment:2 by , 5 years ago
Tested also using nginx-1.17.8 built using the same options + pcre-8.44:
nginx version: nginx/1.17.8 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) built with LibreSSL 3.0.2 TLS SNI support enabled configure arguments: --prefix=/apps/nginx-build/install/nginx-1.17.8 --with-pcre=/apps/nginx-build/compile/pcre-8.44 --with-pcre-jit --with-zlib=/apps/nginx-build/compile/zlib-1.2.11 --with-openssl=/apps/nginx-build/compile/libressl-3.0.2 --with-http_ssl_module --with-http_v2_module --with-http_auth_request_module --with-http_slice_module --without-http_autoindex_module --without-http_browser_module --without-http_empty_gif_module --without-http_fastcgi_module --without-http_geo_module --without-http_grpc_module --without-http_memcached_module --without-http_mirror_module --without-http_scgi_module --without-http_split_clients_module --without-http_ssi_module --without-http_upstream_hash_module --without-http_upstream_ip_hash_module --without-http_upstream_least_conn_module --without-http_upstream_zone_module --without-http_userid_module --without-http_uwsgi_module --with-threads --with-file-aio
Using the following configuration:
map $http_user_agent $rfc6265bis_ua { "~*chrome" 'true'; } map $rfc6265bis_ua $samesite_attr { 'true' '; SameSite=None'; } proxy_cookie_path '/' '/ $samesite_attr'; proxy_cookie_path '/userplatform' '/userplatform $samesite_attr';
Getting this corruption on the set-cookie:
$ UA="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36" $ curl -S -s -H "user-agent: $UA" -v -o /dev/null https://devcwpp002.bfm.com:9502/userplatform/signOn ... < set-cookie: JSESSION_blk-idp02=DAA2915DC8B992CEA820F84985462191; Path=/ ; SameSite=Noneuserplatform; Secure; HttpOnly
comment:3 by , 5 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
This looks like a variant of #564, but with proxy_cookie_path
instead of rewrite
. Further, it ends up with corrupted result since $1
refers to the capture from proxy_cookie_path
when calculating resulting string length, and becomes empty when evaluating actual data.
A workaround would be to use named captures instead, for example:
proxy_cookie_path ~/(?<foo>.*) "/$foo$samesite_attr";
As for the configuration in comment:2, the result seems perfectly correct: since /
matches cookie path /userplatform
returned, /
in it is replaced with the / $samesite_attr
, resulting in Path=/ ; SameSite=Noneuserplatform
, exactly as shown in your tests.
Closing this as a duplicate of #564.
Component should be 'nginx-core' not 'documentation'