How do I secure cookies in HAProxy 2.2+ using an `http-response` line? - haproxy

I'm upgrading from HAProxy 1.8 to 2.2 and the command reqirep has been deprecated and removed. I used this previously to automatically add Secure to cookies that weren't previously secure. I want to use the new http-response syntax.
My old code looks like this:
rspirep ^(set-cookie:\ (?:(?!(\ Secure|ASPXAUTH=)).)*)$ \1;\ Secure
This adds ; Secure to any cookie header that doesn't contain Secure or ASPXAUTH=.
I'd like to do the same thing with one of the modern http-response commands.
Here's my initial translation:
http-request replace-header Set-Cookie (.*) %[src];\ Secure if { hdr_reg(Set-Cookie) -i (?!(\ Secure|ASPXAUTH=)) }
# Replace the "Set-Cookie" header
# That contains any value
# With the initial value with "; Secure" appended to the end
# If the cookie doesn't contain " Secure" or "ASPXAUTH=", ignoring case
Is this the right approach? Have you done this successfully?

We ended up with this as a solution. It's not perfect because it will only look for Secure modifier on the end of the Set-Cookie line but it works for what we need.
http-response replace-header Set-Cookie ^((?:.(?!\ [Ss]ecure))*)$ \1;\ Secure

Related

HAProxy set authorization header from cookie

I have a backend that I don't control that works using magic links. If I use the magic link, I don't have to log on. I want to share the magic link externally without exposing the actual key as the key changes from time to time and I was hoping to use haproxy as a reverse proxy. I don't want the link to be open to the entire internet and would like to use basic auth as well. The problem I am facing is that the backend overwrites the Authorization header (it's required for the magic link to work) and I get stuck in a loop and need to log on every time
My workaround:
On first request I request the basic auth (works)
Then I write it to a cookie (this part works)
On each subsequent request, if the cookie exists, I read the cookie and set the Authorization header to the cookie value (this part does not work)
Then I run http_auth which in my mind should now work since I have overwritten the header
But it does not work. Any suggestions?
userlist auth-list
user myuser insecure-password mypass
frontend myfrontend
bind *:80
mode http
acl is-path path -i -m beg /publiclink
acl has_cookie req.hdr(X-MyAuth) -m found
http-request set-header Authorization %[req.hdr(X-MyAuth)] if has_cookie
http-request auth unless { http_auth(auth-list) }
http-request set-var(txn.myhostheader) req.hdr(Authorization) if { http_auth(auth-list) !has_cookie }
default_backend node
backend node
mode http
server dcnode1 192.168.0.1:8000 check
http-response set-header set-cookie "X-MyAuth=%[var(txn.myhostheader)]; Path=/" if { var(txn.myhostheader) -m found }
http-request replace-path /publiclink1(.*) /magiclink\1
http-request set-header Authorization "Key magiclink"
My answer is related to this point :
On each subsequent request, if the cookie exists, I read the cookie and set the Authorization header to the cookie value (this part does not work)
In your backend, you set the Set-Cookie: X-MyAuth=... header :
backend node
http-response set-header set-cookie "X-MyAuth=%[var(txn.myhostheader)]; Path=/" if { var(txn.myhostheader) -m found }
So the next request contains a Cookie header like this one : Cookie: .* X-MyAuth=.*.
But in your frontend, you use the X-MyAuth header (which probably does not exist) :
frontend myfrontend
acl has_cookie req.hdr(X-MyAuth) -m found
http-request set-header Authorization %[req.hdr(X-MyAuth)] if has_cookie
You may use the X-MyAuth cookie value like this :
frontend myfrontend
acl has_cookie cook(X-MyAuth) -m found
http-request set-header Authorization %[cook(X-MyAuth)] if has_cookie

Can't remove just one Set-Cookie header in HAProxy 2.2

A response from our web server might set a few cookies:
Set-Cookie: JSESSIONID=123;Secure
Set-Cookie: JSESSIONIDSSO=234;Secure
In HAProxy, we want to remove one of these. With 1.7, we could do:
rspidel ^Set-Cookie:\ JSESSIONIDSSO=
But we are upgrading to HAProxy 2.2, where rspidel has been removed. The replacement (http-response del-header) does not handle regex. How can I remove just the one Set-Cookie header?
Response edited because I misunderstood the question
I believe you are looking for http-response replace-header
http-response replace-header <name> <regex-match> <replace-fmt>
[ { if | unless } <condition> ]
This works like "http-request replace-header" except that it works on the
server's response instead of the client's request.
Example:
http-response replace-header Set-Cookie (C=[^;]*);(.*) \1;ip=%bi;\2
# applied to:
Set-Cookie: C=1; expires=Tue, 14-Jun-2016 01:40:45 GMT
# outputs:
Set-Cookie: C=1;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT
# assuming the backend IP is 192.168.1.20.
Documentation here
You can possibly do something like this:
http-response replace-header Set-Cookie (JSESSIONIDSSO=.*) \2
Although, that would leave you with an empty Set-Cookie header.
Another option, would be to replace the value JSESSIONIDSSO with something else. i.e.
http-response replace-header Set-Cookie (JSESSIONIDSSO=[^;]*);(.*) None=None;\2

Remove not needed cookies from the back end request on haproxy

My back-end website is a very small IOT application. Sometimes when a request is send to the back-end server it returns a 404 because the header is to big. This is caused by the cookies send to the server.
Is it possible to send only the needed cookie to the back-end server by rewriting the header on the Haproxy ?
I’m looking for something that rewrites the header for cookies from
sesion=xyz; othercookie=123
to
sesion=xyz
You can use http-request replace-header or http-request replace-value to manipulate the Cookie header for the values you need. This is available in haproxy since version 1.5.
Example from the haproxy documentation:
http-request replace-header Cookie foo=([^;]);(.) foo=\1;ip=%bi;\2
applied to:
Cookie: foo=foobar; expires=Tue, 14-Jun-2016 01:40:45 GMT;
outputs:
Cookie: foo=foobar;ip=192.168.1.20; expires=Tue, 14-Jun-2016 01:40:45 GMT;
assuming the backend IP is 192.168.1.20
haproxy http-request documentation

Setting a unique http request id with haproxy's http-request set-header

So I have some existing code that sets a unique request ID in our front-end load balancer:
unique-id-format %{+X}o\ %Ts_%ci_%cp_%fi_%fp_%rt_%pid
unique-id-header X-Request-Id
log-format %ci\ %r\ %ST\ %B\ %Tr\ %Tt\ %s\ %ID\ %hr
This works as expected -- X-Request-Id is created as expected, logged and passed to the backend. No problems. However, I'd like to make this request ID generation conditional. No problem -- I should just be able to use http-request set-header instead of unique-id-header:
unique-id-format %{+X}o\ %Ts_%ci_%cp_%fi_%fp_%rt_%pid
http-request set-header X-Request-Id %ID
log-format %ci\ %r\ %ST\ %B\ %Tr\ %Tt\ %s\ %ID\ %hr
(These are all in a front_end section). Maddeningly, however %ID seems to evaluate to empty when used this way. I can use a hardcoded value instead of using %ID and it works. I can also use another log field (like %Ts) and it works. It does not, however, work with %ID. Any clues would be helpful -- thanks in advance.
EDIT: Version is 1.6.11
I had the exact same issue in that I wanted to conditionally set the header if not present and %ID wasn't working as you'd expect. I found solutions suggesting to use %[unique-id] but it turns out that's only in version 1.7+. I have subsequently upgraded to 1.7 and now it works perfectly.
unique-id-format %{+X}o\ %pid%ci%cp%fi%fp%Ts%ms%rt
acl cid_exists req.hdr(X-Correlation-ID) -m found
http-request set-header X-Correlation-ID %[unique-id] unless cid_exists
http-request capture hdr(X-Correlation-ID) len 64
log-format "%ci:%cp [%tr] %ft %b/%s %Th/%Ti/%TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %{+Q}r %[capture.req.hdr(0)]"
The captured X-Correlation-ID header contains either a preexisting CID or one that this loadbalancer has created itself if missing.
The unique-id HTTP sample is referenced here.

How to fix an improper request in HAProxy

We have several (100+) clients in the field with a bug in the HTTP request. The request was previously working when directly routed to our Windows Server, but now with it fails with HAProxy v1.7 in front of it.
Here is an example request:
GET /index.aspx HTTP/1.1 \nHost: host\n\n
There is an extra space after the HTTP version before the \n.
Here is a snapshot of the relevant config.
frontend http_port_80
bind :80
mode http
reqrep (.)\ HTTP/1.1\ (.*) \1\ HTTP/1.1\2
option forwardfor
option accept-invalid-http-request
stats enable
use_backend cert_update if is_updater
use_backend getConsoleHTTP if is_getconsole
default_backend schedule_server
I have tried rewriting the request to remove the extra space and set the option accept-invalid-http-request to address the issue, but we still receive the same error.
{
type: haproxy,
timestamp: 1506545591,
termination_state: PR-,
http_status:400,
http_request:,
http_version:,
remote_addr:192.168.1.1,
bytes_read:187,
upstream_addr:-,
backend_name:http_port_80,
retries:0,
bytes_uploaded:92,
upstream_response_time:-1,
upstream_connect_time:-1,
session_duration:2382,
termination_state:PR
}
Does anyone have any ideas of how to fix the malformed request prior to haproxy rejecting it?