长 Cookies 导致的 cloudflare Error 520


Cloudflare 520 是 CF 自定义的错误,根据官方文档描述,可能的原因如下:

  • Origin web server application crashes
  • Cloudflare IPs not allowed at your origin
  • Headers exceeding 16 KB (typically due to too many cookies)
  • An empty response from the origin web server that lacks an HTTP status code or response body
  • Missing response headers or origin web server not returning proper HTTP error responses.
    • upstream prematurely closed connection while reading response header from upstream is a common error we may notice in our logs. This indicates the origin web server was having issues which caused Cloudflare to generate 520 errors.

我4k多的cookies就引发了 520,而且出问题的是在 iOS Chrome里,没法直接调试,抓包看到 Cookies 的长度,试验了一下删减,不到4k的时候没问题。只能尝试用 cURL 去调用源服务器。结果发现,源服务器

*   Trying 127.0.0.1:443...
* TCP_NODELAY set
* Connected to xxx.xx (127.0.0.1) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: O=CloudFlare, Inc.; OU=CloudFlare Origin CA; CN=CloudFlare Origin Certificate
*  start date: Dec  9 15:19:00 2021 GMT
*  expire date: Dec  5 15:19:00 2036 GMT
*  issuer: C=US; O=CloudFlare, Inc.; OU=CloudFlare Origin SSL Certificate Authority; L=San Francisco; ST=California
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x559c87f16890)
> GET / HTTP/2
...
...
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* TLSv1.3 (IN), TLS alert, close notify (256):
* Empty reply from server
* Closing connection 0
curl: (52) Empty reply from server

没有响应。

源服务器是 Ubuntu 20.04,nginx 版本

# nginx -V
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled

最开始按nginx 文档里的可能的选项,试验了下边的几项

    client_header_buffer_size 32k;
    large_client_header_buffers 8 32k;
    ssl_buffer_size 32k;

都一样。

观察了一下请求,再开了个虚拟机,做了个最小化的nginx 配置。

server {
    #listen 443 ssl http2 backlog=20480;
    listen 443 ssl http2;
    #listen 443 ssl ;
    listen 80;

    ssl_certificate      /etc/nginx/cert/rst.im/server.crt;
    ssl_certificate_key  /etc/nginx/cert/rst.im/server.key;


    client_header_buffer_size 32k;
    large_client_header_buffers 8 32k;
    ssl_buffer_size 32k;

    root /tmp/web/;
    index index.html index.htm index.php;
    server_name rst.im *.rst.im;

    location ~ /\.(ht|git) {
        deny all;
    }
}

试验了如下方案:

  • http:成功
  • https + http 1.1:成功
  • https + http 2.0:复现

翻过来去看 http2 模块的文档,发现了 http2_max_field_size,默认大小4k,但是写了 1.19.7 之后被废弃。然而 ubuntu 20.04 的 nginx 比这个老。加上配置,

http2_max_field_size 16k;

问题解决。


Leave a Reply

Your email address will not be published. Required fields are marked *