Re: haproxy 1.7.5 segfault on cookie/header parsing.
Hi Jean, I finally found it by carefully unrolling the execution based on your core. It's a regression introduced in 1.7 while fixing a problem of missing cookies in logs when doing a tarpit... I could finally reproduce it and fix it with the attached patch. Thanks a lot for all the details you provided! Willy >From 6a0bca9e7862984b0edf8fc1e1edc54295a7a5e2 Mon Sep 17 00:00:00 2001 From: Willy TarreauDate: Sun, 11 Jun 2017 17:56:27 +0200 Subject: BUG/MAJOR: http: call manage_client_side_cookies() before erasing the buffer Jean Lubatti reported a crash on haproxy using a config involving cookies and tarpit rules. It just happens that since 1.7-dev3 with commit 83a2c3d ("BUG/MINOR : allow to log cookie for tarpit and denied request"), function manage_client_side_cookies() was called after erasing the request buffer in case of a tarpit action. The problem is that this function must absolutely not be called with an empty buffer since it moves parts of it. A typical reproducer consists in sending : "GET / HTTP/1.1\r\nCookie: S=1\r\n\r\n" On such a config : listen crash bind :8001 mode http reqitarpit . cookie S insert indirect server s1 127.0.0.1:8000 cookie 1 The fix simply consists in moving the call to the function before the call to buffer_erase(). Many thanks to Jean for testing instrumented code and providing a usable core. This fix must be backported to all stable versions since the fix introducing this bug was backported as well. --- src/proto_http.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/proto_http.c b/src/proto_http.c index 357401f..a72f302 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -4462,6 +4462,11 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s return 1; tarpit: + /* Allow cookie logging +*/ + if (s->be->cookie_name || sess->fe->capture_name) + manage_client_side_cookies(s, req); + /* When a connection is tarpitted, we use the tarpit timeout, * which may be the same as the connect timeout if unspecified. * If unset, then set it to zero because we really want it to @@ -4474,11 +4479,6 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s */ channel_dont_connect(req); - /* Allow cookie logging -*/ - if (s->be->cookie_name || sess->fe->capture_name) - manage_client_side_cookies(s, req); - txn->status = http_err_codes[deny_status]; req->analysers &= AN_REQ_FLT_END; /* remove switching rules etc... */ -- 1.7.12.1
Re: haproxy 1.7.5 segfault on cookie/header parsing.
Hi Jean, On Sun, May 28, 2017 at 10:15:28AM +, Jean LUBATTI wrote: > There was a tcp-request inspect-delay of 2s in the configuration when running > the repro, so it should be fine. OK. However, I totally fail to reproduce the problem here using your config, the build options I found in your executable, and the captured requests, they are properly handled and passed. And since the crash happens inside memmove(), the memory is displaced everywhere and the internal structures are not much analyzable. Could you please try again with the attached patch ? It's supposed to provoke a segfault before the bogus call to memmove(), resulting in a "clean" core. Thanks, Willy diff --git a/src/buffer.c b/src/buffer.c index 4f8f647..70a01dd 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -87,6 +87,9 @@ int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int return 0; /* no space left before wrapping data */ /* first, protect the end of the buffer */ + if (bi_end(b) < end) + *(volatile int *)0 = 0; + memmove(end + delta, end, bi_end(b) - end); /* now, copy str over pos */
Re: haproxy 1.7.5 segfault on cookie/header parsing.
There was a tcp-request inspect-delay of 2s in the configuration when running the repro, so it should be fine. Sent from my iPhone > On 28 May 2017, at 11:41, Willy Tarreauwrote: > > Hi Jean, > >> On Sun, May 28, 2017 at 09:15:56AM +, Jean LUBATTI wrote: >> Hi Willy, >> >> I just tried the line "tcp-request content capture req.hdrs_bin len 2000" >> in the config but I get: >> >> [ALERT] 147/073131 (13352) : parsing [/etc/haproxy/haproxy.cfg:42] : >> 'tcp-request content capture' : unknown fetch method 'req.hdrs_bin' >> [ALERT] 147/073131 (13352) : Error(s) found in configuration file : >> /etc/haproxy/haproxy.cfg >> [ALERT] 147/073131 (13352) : Fatal errors found in configuration. >> Errors found in configuration file, check it with 'haproxy check'. > > Sorry, this one is only in 1.8-dev. > >> I changed it to : >> >> tcp-request content capture req.payload(0,2000) len 2000 >> >> but I don't think it works (at least not when inspecting the core on >> s->req). > > Ah, I forgot to mention you need to allow a delay for the request to arrive, > you need to add this : > >tcp-request inspect-delay 10s > > (for example) > >> Here is the output of haproxy running under gdb when the attack happens: >> >> 01d7:ft_appmarket_preprod_services_ingenico_com_443.clireq[0027:]: >> GET /wp-content/uploads/ HTTP/1.1 >> 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: >> Host: 185.139.245.111 >> 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: >> User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:40.0) Gecko/20100101 >> Firefox/40.0 >> 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: >> Cookie: SERVERID=ppmktplportals01fe >> 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: >> Accept-Encoding: gzip >> 01d8:ft_appmarket_preprod_services_ingenico_com_443.clireq[0028:]: >> GET /wp-content/uploads/2015/ HTTP/1.1 >> 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: >> Host: 185.139.245.111 >> 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: >> User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:40.0) Gecko/20100101 >> Firefox/40.0 >> 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: >> Cookie: SERVERID=ppmktplportals01fe >> 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: >> Accept-Encoding: gzip >> 01d7:appmarket_preprod_services_ingenico_com_8443.srvrep[0027:0029]: >> HTTP/1.1 404 Not Found >> 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: >> Server: Apache-Coyote/1.1 >> 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: >> Content-Length: 0 >> 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: >> Date: Sun, 28 May 2017 09:03:04 GMT >> 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: >> Connection: close >> 01d8:appmarket_preprod_services_ingenico_com_8443.srvrep[0028:002a]: >> HTTP/1.1 404 Not Found >> 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: >> Server: Apache-Coyote/1.1 >> 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: >> Content-Length: 0 >> 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: >> Date: Sun, 28 May 2017 09:03:04 GMT >> 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: >> Connection: close >> 01d9:ft_appmarket_preprod_services_ingenico_com_443.clireq[0025:]: >> GET /language/en-GB/en-GB.xml HTTP/1.1 >> 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: >> Host: 185.139.245.111 >> 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: >> User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:40.0) Gecko/20100101 >> Firefox/40.0 >> 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: >> Cookie: SERVERID=ppmktplportals01fe >> 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: >> Accept-Encoding: gzip >> >> Program received signal SIGSEGV, Segmentation fault. >> _wordcopy_fwd_dest_aligned (dstp=14712784, srcp=14712832, >> len=2305843009213203548) at wordcopy.c:196 >> 196 a0 = ((op_t *) srcp)[0]; >> (gdb) >> >> Attaching to the mail the core and the binary. > > Thanks for all this, I think I should be able to reproduce it with all this, > otherwise I'll recontact you :-) > > Thanks! > Willy This email and its content belong to Ingenico Group. The enclosed information is confidential and may not be disclosed to any unauthorized person. If you have received it by mistake do not forward it and delete it from your system. Cet email et son contenu sont la propriété du Groupe Ingenico. L’information qu’il contient est confidentielle et ne peut être communiquée à des
Re: haproxy 1.7.5 segfault on cookie/header parsing.
Hi Jean, On Sun, May 28, 2017 at 09:15:56AM +, Jean LUBATTI wrote: > Hi Willy, > > I just tried the line "tcp-request content capture req.hdrs_bin len 2000" in > the config but I get: > > [ALERT] 147/073131 (13352) : parsing [/etc/haproxy/haproxy.cfg:42] : > 'tcp-request content capture' : unknown fetch method 'req.hdrs_bin' > [ALERT] 147/073131 (13352) : Error(s) found in configuration file : > /etc/haproxy/haproxy.cfg > [ALERT] 147/073131 (13352) : Fatal errors found in configuration. > Errors found in configuration file, check it with 'haproxy check'. Sorry, this one is only in 1.8-dev. > I changed it to : > > tcp-request content capture req.payload(0,2000) len 2000 > > but I don't think it works (at least not when inspecting the core on s->req). Ah, I forgot to mention you need to allow a delay for the request to arrive, you need to add this : tcp-request inspect-delay 10s (for example) > Here is the output of haproxy running under gdb when the attack happens: > > 01d7:ft_appmarket_preprod_services_ingenico_com_443.clireq[0027:]: > GET /wp-content/uploads/ HTTP/1.1 > 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: > Host: 185.139.245.111 > 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: > User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:40.0) Gecko/20100101 > Firefox/40.0 > 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: > Cookie: SERVERID=ppmktplportals01fe > 01d7:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0027:]: > Accept-Encoding: gzip > 01d8:ft_appmarket_preprod_services_ingenico_com_443.clireq[0028:]: > GET /wp-content/uploads/2015/ HTTP/1.1 > 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: > Host: 185.139.245.111 > 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: > User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:40.0) Gecko/20100101 > Firefox/40.0 > 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: > Cookie: SERVERID=ppmktplportals01fe > 01d8:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0028:]: > Accept-Encoding: gzip > 01d7:appmarket_preprod_services_ingenico_com_8443.srvrep[0027:0029]: > HTTP/1.1 404 Not Found > 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: > Server: Apache-Coyote/1.1 > 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: > Content-Length: 0 > 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: > Date: Sun, 28 May 2017 09:03:04 GMT > 01d7:appmarket_preprod_services_ingenico_com_8443.srvhdr[0027:0029]: > Connection: close > 01d8:appmarket_preprod_services_ingenico_com_8443.srvrep[0028:002a]: > HTTP/1.1 404 Not Found > 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: > Server: Apache-Coyote/1.1 > 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: > Content-Length: 0 > 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: > Date: Sun, 28 May 2017 09:03:04 GMT > 01d8:appmarket_preprod_services_ingenico_com_8443.srvhdr[0028:002a]: > Connection: close > 01d9:ft_appmarket_preprod_services_ingenico_com_443.clireq[0025:]: > GET /language/en-GB/en-GB.xml HTTP/1.1 > 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: > Host: 185.139.245.111 > 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: > User-Agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:40.0) Gecko/20100101 > Firefox/40.0 > 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: > Cookie: SERVERID=ppmktplportals01fe > 01d9:ft_appmarket_preprod_services_ingenico_com_443.clihdr[0025:]: > Accept-Encoding: gzip > > Program received signal SIGSEGV, Segmentation fault. > _wordcopy_fwd_dest_aligned (dstp=14712784, srcp=14712832, > len=2305843009213203548) at wordcopy.c:196 > 196 a0 = ((op_t *) srcp)[0]; > (gdb) > > Attaching to the mail the core and the binary. Thanks for all this, I think I should be able to reproduce it with all this, otherwise I'll recontact you :-) Thanks! Willy
Re: haproxy 1.7.5 segfault on cookie/header parsing.
Hello Jean, On Fri, May 26, 2017 at 01:00:17PM +, Jean LUBATTI wrote: > Hello, > > When using a vulnerability scanner on haproxy 1.7.5, we discovered a scenario > under which the haproxy segfaults. > > Unfortunately, this is a "bundled" scanner whith no access to the exact > requests, and the haproxy terminates the SSL for https, so not easy to > capture the actual traffic, but we managed to gather a core of haproxy. You could run haproxy with "-d", it will dump to stdout/stderr each header line it receives. I even think we could get a complete capture of the whole request like this : tcp-request content capture req.hdrs_bin len 2000 It will then appear in the core in s->req_cap. > This happens only when using the cookie SERVERID for session stickiness: We've had similar issues a very long time ago, I hoped they were fixed :-/ > The backtrace is as follow: > > I believe the scanner injects a screwed up header and/or cookie. The result > appears to be the incorrect memmove of the last header line : > > (gdb) bt full > #0 _wordcopy_fwd_dest_aligned (dstp=14237664, srcp=14237696, > len=2305843009213653720) at wordcopy.c:196 > a0 = > a1 = > a2 = 0 > a3 = 0 > sh_1 = 40 > sh_2 = 24 > #1 0x003727a838be in memmove (dest=0xd4575d, src=, > len=18446744073709551439) at memmove.c:73 > dstp = > srcp = > #2 0x00411217 in buffer_replace2 (b=0xd456b0, pos=0xd4575d > "Accept-Encoding: gzip\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n", > end=, str=0x0, len=0) at src/buffer.c:90 > delta = -21 > #3 0x0045de02 in manage_client_side_cookies (s=0xcfa800, > req=0xcfa810) at src/proto_http.c:7976 > delta = > cur_hdr = 0xcfac6c > val = > txn = > sess = 0xc1c930 > preserve_hdr = 0 > cur_idx = 3 > old_idx = 2 > hdr_beg = 0xd4575d "Accept-Encoding: > gzip\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n" > hdr_end = 0xd45770 "ip\r\n\r\n.32.31\r\nConnection: > close\r\n\r\nre\r\n\r\n" > hdr_next = 0xd45772 "\r\n\r\n.32.31\r\nConnection: > close\r\n\r\nre\r\n\r\n" > del_from = 0xd45763 "-Encoding: gzip\r\n\r\n.32.31\r\nConnection: > close\r\n\r\nre\r\n\r\n" > prev = > att_beg = > att_end = > equal = > val_beg = > val_end = > next = > #4 0x00460a86 in http_process_req_common (s=0xcfa800, req=0xcfa810, > an_bit=256, px=0x86a650) at src/proto_http.c:4474 > sess = 0xc1c930 > txn = 0xcfab50 > msg = 0xcfabb0 > rule = > wl = > verdict = > deny_status = 2 > #5 0x00486d0e in process_stream (t=0xb8fa70) at src/stream.c:1798 > max_loops = 199 > ana_list = 2304 > ana_back = 2304 > flags = 2 > srv = > s = 0xcfa800 > sess = 0xc1c930 > rqf_last = > rpf_last = 2147745792 > rq_prod_last = > rq_cons_last = > rp_cons_last = 7 > rp_prod_last = 0 > req_ana_back = > req = 0xcfa810 > res = 0xcfa850 > si_f = 0xcfaa38 > si_b = 0xcfaa60 > #6 0x00415ac0 in process_runnable_tasks () at src/task.c:238 > t = > max_processed = > #7 0x00407028 in run_poll_loop () at src/haproxy.c:1724 > next = > #8 0x0040a308 in main (argc=, argv= optimized out>) at src/haproxy.c:2105 > err = > retry = > limit = {rlim_cur = 4091, rlim_max = 4091} > errmsg = > "\000\347K\000\000\000\000\000\b\300n\000\000\000\000\000\020\340\377\377\377\177\000\000\000\300n\000\000\000\000\000\006\000\000\000\000\000\000\000H\341\377\377\377\177\000\000\200\341\377\377\377\177\000\000XpA\000\000\000\000\000\000\300n\000\000\000\000\000\226\070K\000\000\000\000\000\340\070\370/7\000\000\000\340\067K\000\000\000\000\000\000\000\000" > > > Basically, the memove in #1 is called with len=18446744073709551439 from > buffer_replace2, which is a negative value. > > I am not sure exactly in which case this is possible (last line of the header > incorrect or something), but bi_end(b) is < to end, so the unsigned size_t > expected by memmove is incorrect. For sure there's a bug there. However I'd be very interested in understanding in which case it can happen, as it will reveal the root cause of this bug. We know that this part is tricky and I'd rather be sure we don't miss a single case. > I recompiled haproxy with the patch below and now it survives the > vulnerability scanner, but it might not be at the proper place of the code > (maybe the logic fault is better addressed above in > manage_client_side_cookies... ): This obviously confirms that it's where it dies, but it doesn't explain what the problem really is. Would you happen to have an exploitable core with the associated executable ? I
haproxy 1.7.5 segfault on cookie/header parsing.
Hello, When using a vulnerability scanner on haproxy 1.7.5, we discovered a scenario under which the haproxy segfaults. Unfortunately, this is a "bundled" scanner whith no access to the exact requests, and the haproxy terminates the SSL for https, so not easy to capture the actual traffic, but we managed to gather a core of haproxy. This happens only when using the cookie SERVERID for session stickiness: The backtrace is as follow: I believe the scanner injects a screwed up header and/or cookie. The result appears to be the incorrect memmove of the last header line : (gdb) bt full #0 _wordcopy_fwd_dest_aligned (dstp=14237664, srcp=14237696, len=2305843009213653720) at wordcopy.c:196 a0 = a1 = a2 = 0 a3 = 0 sh_1 = 40 sh_2 = 24 #1 0x003727a838be in memmove (dest=0xd4575d, src=, len=18446744073709551439) at memmove.c:73 dstp = srcp = #2 0x00411217 in buffer_replace2 (b=0xd456b0, pos=0xd4575d "Accept-Encoding: gzip\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n", end=, str=0x0, len=0) at src/buffer.c:90 delta = -21 #3 0x0045de02 in manage_client_side_cookies (s=0xcfa800, req=0xcfa810) at src/proto_http.c:7976 delta = cur_hdr = 0xcfac6c val = txn = sess = 0xc1c930 preserve_hdr = 0 cur_idx = 3 old_idx = 2 hdr_beg = 0xd4575d "Accept-Encoding: gzip\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n" hdr_end = 0xd45770 "ip\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n" hdr_next = 0xd45772 "\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n" del_from = 0xd45763 "-Encoding: gzip\r\n\r\n.32.31\r\nConnection: close\r\n\r\nre\r\n\r\n" prev = att_beg = att_end = equal = val_beg = val_end = next = #4 0x00460a86 in http_process_req_common (s=0xcfa800, req=0xcfa810, an_bit=256, px=0x86a650) at src/proto_http.c:4474 sess = 0xc1c930 txn = 0xcfab50 msg = 0xcfabb0 rule = wl = verdict = deny_status = 2 #5 0x00486d0e in process_stream (t=0xb8fa70) at src/stream.c:1798 max_loops = 199 ana_list = 2304 ana_back = 2304 flags = 2 srv = s = 0xcfa800 sess = 0xc1c930 rqf_last = rpf_last = 2147745792 rq_prod_last = rq_cons_last = rp_cons_last = 7 rp_prod_last = 0 req_ana_back = req = 0xcfa810 res = 0xcfa850 si_f = 0xcfaa38 si_b = 0xcfaa60 #6 0x00415ac0 in process_runnable_tasks () at src/task.c:238 t = max_processed = #7 0x00407028 in run_poll_loop () at src/haproxy.c:1724 next = #8 0x0040a308 in main (argc=, argv=) at src/haproxy.c:2105 err = retry = limit = {rlim_cur = 4091, rlim_max = 4091} errmsg = "\000\347K\000\000\000\000\000\b\300n\000\000\000\000\000\020\340\377\377\377\177\000\000\000\300n\000\000\000\000\000\006\000\000\000\000\000\000\000H\341\377\377\377\177\000\000\200\341\377\377\377\177\000\000XpA\000\000\000\000\000\000\300n\000\000\000\000\000\226\070K\000\000\000\000\000\340\070\370/7\000\000\000\340\067K\000\000\000\000\000\000\000\000" Basically, the memove in #1 is called with len=18446744073709551439 from buffer_replace2, which is a negative value. I am not sure exactly in which case this is possible (last line of the header incorrect or something), but bi_end(b) is < to end, so the unsigned size_t expected by memmove is incorrect. I recompiled haproxy with the patch below and now it survives the vulnerability scanner, but it might not be at the proper place of the code (maybe the logic fault is better addressed above in manage_client_side_cookies... ): diff -uNr haproxy-1.7.5/src/buffer.c haproxy-1.7.5p/src/buffer.c --- haproxy-1.7.5/src/buffer.c 2017-04-03 10:28:32.0 +0200 +++ haproxy-1.7.5p/src/buffer.c 2017-05-26 13:04:58.225311000 +0200 @@ -87,7 +87,8 @@ return 0; /* no space left before wrapping data */ /* first, protect the end of the buffer */ - memmove(end + delta, end, bi_end(b) - end); + if ( bi_end(b) > end ) + memmove(end + delta, end, bi_end(b) - end); /* now, copy str over pos */ if (len) the configuration is as follows: frontend ft_X_443 bind 185.139.245.111:443 ssl crt /etc/haproxy/ssl/X.pem ciphers AES256+EECDH:AES256+EDH bind-process 2 3 4 mode http option http-buffer-request http-response set-header Strict-Transport-Security "max-age=1600; includeSubDomains; preload;" http-request del-header Origin stick-table type ip size 1m expire 1m store gpc0,conn_rate(1s) tcp-request connection track-sc1