系统信息:
重现步骤:
asciinema upload asciicast.json
预期行为:
文件上传到asciinema.org
实际行为:
客户端打印错误消息:
Error: Invalid request: <html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>
附加信息:
如果使用zsh(在我的情况下为4.3.11 (x86_64-redhat-linux-gnu)
)并且安装了oh-my-zsh,则客户端会创建中断的记录。 如果禁用oh-my-zsh或将bash用作外壳,则客户端创建和上传记录不会有任何问题。
记录JSON: https :
也为我而发生。 使用ZSH,但不使用OMZ。
$ zsh --version
zsh 5.3.1 (x86_64-pc-linux-gnu)
$ asciinema --version
asciinema 1.4.0
我发现,如果我将API网址从HTTPS更改为HTTP,则一切正常。
我昨天更改了负载均衡器配置,因此可能与之相关。
我能够在Centos 7 Vagrant VM中重现它。 我认为这与我们从昨天开始使用的Brightbox负载平衡器(具有SSL终止功能,自动让我们加密证书)有关。
@andyone @ThiefMaster您现在可以尝试吗? 我可能已经解决了。
仍然得到400
我认为这是与OpenSSL相关的问题。 使用curl发送数据是可以的,因为curl使用NSS(网络安全服务)来使用SSL / TLS。
使用Brightbox负载平衡器
这是基于nginx的解决方案吗?
@andyone我认为Brightbox负载平衡器使用Haproxy。
我可以始终如一地重现这一点。 我创建了Vagrantfile和说明: https :
@andyone问题似乎不是录制中的特定行,而是上传的json文件的整体大小。
我使用此配置基于webkaos (使用BoringSSL改进了nginx)创建了一个代理https://ascii.kaos.io 。 我和@ThiefMaster录音已通过此代理成功上传。
到目前为止,这是我所知道的:
HTTP请求可以通过Brightbox负载平衡器正常运行,但是HTTPS可以提供400错误请求
对于请求,其中请求正文大于约4KB。
有趣的是,在CentOS下,我们的HTTPS获得400。 在macOS下使用HTTPS可以正常工作。 (HTTP在任何地方都可以正常工作)。
我看得更深,试图找出区别。 我使用tcpdump来查看CentOS和macOS上的请求(HTTP,假定请求本身的格式与HTTPS下的格式相同)。
唯一的区别似乎是在macOS上的正文之前有2个空行,在CentOS上有1个空行(可能是由于这些操作系统上的Python 3附带的urllib版本略有不同):
CentOS的:
POST /api/asciicasts HTTP/1.1
Accept-Encoding: identity
User-Agent: asciinema/1.4.0 CPython/3.4.5 Linux/3.10.0-514.16.1.el7.x86_64-x86_64-with-centos-7.3.1611-Core
Authorization: Basic <61 bytes of base64 encoded credentials>
Content-Length: 13582
Content-Type: multipart/form-data; boundary=c3f4e35afa4a4ce6b65b6420da09b46e
Connection: close
Host: asciinema.org
--c3f4e35afa4a4ce6b65b6420da09b46e
Content-Disposition: form-data; name="asciicast"; filename="asciicast.json"
Content-Type: application/json
<about 13 kb of json>
苹果系统:
POST /api/asciicasts HTTP/1.1
Accept-Encoding: identity
Content-Length: 13582
Host: asciinema.org
User-Agent: asciinema/1.4.0 CPython/3.6.1 Darwin/16.5.0-x86_64-i386-64bit
Content-Type: multipart/form-data; boundary=71d5b757e9d1451b9540dc286f74207d
Authorization: Basic <61 bytes of base64 encoded credentials>
Connection: close
--71d5b757e9d1451b9540dc286f74207d
Content-Disposition: form-data; name="asciicast"; filename="asciicast.json"
Content-Type: application/json
<about 13 kb of json>
为了了解它的影响,我暂时将LB上的“请求缓冲区大小”从4096(默认值)更改为8192(最大),然后突然在所有地方(所有操作系统,HTTPS)开始正常工作,是的!
我不是非常有信心这是最终的解决方案,因为对于4096的缓冲区大小,这是真的:
当我将“请求缓冲区大小”提高到8192时,主体大小和协议
没关系,一切正常。 我想知道是否通过颠簸
到8192我只是在买时间(减少受影响的人),或者这样
完全解决问题(如果是,那么为什么?)。
我就此事联系了Brightbox,希望他们能解释发生了什么。
在Brightbox侧更新re 8192缓冲区大小:使用此数字,它在CentOS下对我有效,但对于@ThiefMaster仍然不起作用。
抱歉,对不起。
在通过Brightbox LB传输流量之前,我在Nginx中终止了SSL,多年来一切正常。 如果它与基于Nginx的@andyone代理一起工作,则可能表明Nginx对请求格式更为“宽容”,而Haproxy更为严格,并且asciinema客户端在Python 3.4(及其Haperoxy标准)下错误地格式化了请求(对于Haproxy标准) urllib,该版本早于我在Mac上使用的3.6.1)。
我可以稍后使用Haproxy进行检查,但是我的版本是使用LibreSSL而不是OpenSSL构建的。
我目前的理论是这样的:
标头和正文之前的这一新行不足以使LB完成读取标头的工作(它需要2条新行),并且它将继续读取其下的所有数据作为标头,并计数字节,最终超过标头的最大大小。 如果LB具有bytes_read
类的变量(从套接字读取的字节),则在完成读取标头之后,然后在读取正文之后,再检查其值。 如果您上传<4kb文件,则该文件头永远不会超过4kb的限制;如果您上传> 4kb,则该文件会超过该限制。
(这仅在HTTPS下发生)
不知道是不是这样,只是大声思考😀
更新了源代码,因此它添加了额外的新行,在CentOS下进行了检查,但仍然失败。 所以以上理论是错误的。
在带有HTTPS的CentOS下可以使用:
curl -v -X POST -u $USER:api-token https://asciinema.org/api/asciicasts -F [email protected]
* About to connect() to asciinema.org port 443 (#0)
* Trying 109.107.38.233...
* Connected to asciinema.org (109.107.38.233) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=asciinema.org
* start date: Jun 07 09:12:00 2017 GMT
* expire date: Sep 05 09:12:00 2017 GMT
* common name: asciinema.org
* issuer: CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US
* Server auth using Basic with user 'vagrant'
> POST /api/asciicasts HTTP/1.1
> Authorization: Basic <...hidden...>
> User-Agent: curl/7.29.0
> Host: asciinema.org
> Accept: */*
> Content-Length: 5658
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=----------------------------6ca3f3de6469
因此,也许Python使用的SSL库与curl有所不同,问题出在SSL领域吗?
我想是这样。 Python使用OpenSSL,curl使用NSS。
@andyone ascii.kaos.io的证书不是“让我们加密吗?”
使用SSL的RapidSSL SHA256
通常,我会说CentOS缺少“让我们加密”(或类似😊)的根证书,但是正在建立SSL连接,并且错误出现在HTTP协议级别(400错误请求),所以...
如果缺少“ Let's Encrypt”的根证书,即使使用curl也不起作用。
我们的(Brightbox)负载平衡器确实确实使用了haproxy。 HTTP RFC和haproxy文档确实声明需要一个CRLF才能将标头与正文分开:
https://github.com/haproxy/haproxy/blob/master/doc/internals/http-parsing.txt
您是否可能仅在此处发送CR或LF,而不是完整的CRLF?
@sickill这是具有LibreSSL 2.5.0的HA-Proxy 1.7.5上-https://ascii-ha.kaos.io 。 我和@ThiefMaster录音,以及您存储库中的over-4k.json
通过此代理成功上传。
@andyone好的。 因此,您可以将tune.bufsize
(https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#3.2-tune.bufsize)更改为4096吗?
@johnl我检查了CRLF,这里一切正常。
我再次在CentOS和macOS上tcpdump了该请求(再次通过HTTP,假设HTTP有效负载与HTTPS相同)。
dump-centos.pcap.txt和dump-mac.pcap.txt包含tcpdump捕获( tcpdump -s 0 dst port 80 -w dump-centos.pcap.txt
)。
dump-centos-hex.txt和dump-mac-hex.txt包含十六进制格式的转储(通过hexdump -C
)。
dump-centos-hex.txt
dump-centos.pcap.txt
dump-mac-hex.txt
dump-mac.pcap.txt
在两个操作系统上似乎都有CRLF用于换行,并且标题和正文之间有一个空白行。
在左侧的CentOS上,在右侧的macOS上:
@sickill配置已更新。 over-4k.json
上传了
@andyone感谢您的更新。 似乎它没有添加X-Forwarded-Proto
标头(因为返回的记录URL是http://
)。 您可以添加http-request set-header X-Forwarded-Proto https if { ssl_fc }
吗?
这是我的配置:
frontend www-https
bind 207.154.241.251:443 ssl crt /etc/ssl/private/kaos.pem
reqadd X-Forwarded-Proto:\ https
default_backend www-backend
backend www-backend
server asciinema-backend asciinema.org:80
我应该在哪里添加这一行?
@andyone我认为它需要进入backend
部分(尽管我不是haproxy专家)。
@andyone顺便说一句,非常感谢您帮助调试此功能😍谢谢!
也不要忘记前进。 这应该使用ssl密码非常接近地复制设置:
tune.bufsize 4096
tune.ssl.default-dh-param 2048
tune.maxrewrite 40
frontend www-https
bind 207.154.241.251:443 ssl no-sslv3 crt /etc/ssl/private/kaos.pem ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
reqadd X-Forwarded-Proto:\ https
default_backend www-backend
backend www-backend
server asciinema-backend asciinema.org:80
mode http
option forwardfor
option httplog
我修改了配置,但是没有运气:
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend www-https
bind 207.154.241.251:443 ssl crt /etc/ssl/private/kaos.pem
reqadd X-Forwarded-Proto:\ https
default_backend www-backend
backend www-backend
http-request set-header X-Forwarded-Proto https
server asciinema-backend asciinema.org:80
客户端仍返回带有http://
。
我总是很乐意帮助改善有用的服务😉。
@johnl这是完整的配置,所有必需的选项都在defaults
和global
部分中设置:
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
tune.bufsize 4096
# SSL configuration
tune.ssl.default-dh-param 2048
ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
frontend www-https
bind 207.154.241.251:443 ssl crt /etc/ssl/private/kaos.pem
reqadd X-Forwarded-Proto:\ https
default_backend www-backend
backend www-backend
http-request set-header X-Forwarded-Proto https
server asciinema-backend asciinema.org:80
如果@andyone的haproxy配置现在非常接近BB,而我们仍然无法重现该问题,尝试使用“让我们加密”证书是否有意义? 这是https://ascii-ha.kaos.io和https://asciinema.org之间的区别之一
完成-https: //ascii.kaos.re
HA-Proxy 1.7.5(含LibreSSL 2.5.0)+加密证书(由Certbot创建)
配置:
tune.bufsize 4096
tune.ssl.default-dh-param 2048
tune.maxrewrite 40
frontend www-https
bind 207.154.241.251:443 ssl no-sslv3 crt /etc/ssl/private/ascii.kaos.re.pem ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
reqadd X-Forwarded-Proto:\ https
default_backend www-backend
backend www-backend
server asciinema-backend asciinema.org:80
mode http
option forwardfor
option httplog
看起来一切正常。 over-4k.json
成功上传。
我对此没有进一步的想法。 我正在考虑回滚到我自己的Nginx实例以进行负载平衡和SSL终止🤕
我正在尝试将其缩减为可以重现该问题的单个curl命令,但尚未解决该问题,任何人都可以帮忙吗?
我正在发布一个5k正文,其中包含使用curl的身份验证用户名/密码。 我正在使用netcat Web服务器后端连接Brightbox负载平衡器,因此可以看到原始请求文本。 它总是经过-无法使其触发错误的请求响应。
如果负载均衡器拒绝了此操作,则我不需要后端上的应用程序真实实例,因为它永远不会那么遥远-因此我们应该能够使用curl而不使用任何应用程序来重现该实例。
我已经尝试过在ubuntu和centos7上使用curl,特别是使用openssl(注意,您可以指定--engine命令来curl来选择要使用的sslib库。centos7 curl二进制文件是针对大多数选项构建的)
@johnl感谢您对此进行调查。
将netcat用作测试的后端很有意义👍
asciinema upload over-4k.json
curl等效值大致是这样的:
curl -v -X POST -u test:uuid4 https://asciinema.org/api/asciicasts -F [email protected]
(用uuid4
的结果替换python3 -c 'import uuid; print(uuid.uuid4())'
)
它确实可以卷曲...
我比较了asciinema upload
tcpdump和上面的卷曲,在HTTP协议级别上没有任何可疑的东西。 但是,某些tcp帧显示在不同的位置(可能在每个tcp数据包中发送/适配的数据更多/更少)。
我在CentOS 7 VM中使用tcpflow捕获了HTTP请求(到http://asciinema.org):
sudo tcpflow -p -C -i eth0 port 80 >tcpflow-req.txt
然后在另一个shell(在同一VM中)中运行:
ASCIINEMA_API_URL=http://asciinema.org asciinema upload /vagrant/over-4k.json
我切断了响应,只留下了请求。 这是逐字节发送的内容: tcpflow-req.txt
我针对asciinema重播了这个捕获的HTTP请求。 org:80和nc
:
bash-4.4$ (cat tcpflow-req.txt; cat) | nc asciinema.org 80
HTTP/1.1 201 Created
Server: nginx
Date: Mon, 12 Jun 2017 13:30:03 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 48
Connection: close
Status: 201 Created
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Location: http://asciinema.org/a/4lgbbik7li4ywzqrfak0e7eku
ETag: "9beb7ac6bb5981f06fdc71df3947d8b0"
Cache-Control: max-age=0, private, must-revalidate
X-Request-Id: 2a8a8c75-ed06-4741-9adb-e5d276032ded
X-Runtime: 0.360858
Vary: Accept-Encoding
Strict-Transport-Security: max-age=15768000
http://asciinema.org/a/4lgbbik7li4ywzqrfak0e7eku
都好。
现在,我已经通过SSL发送给了asciinema。 org:443 :
(cat tcpflow-req.txt; cat) | openssl s_client -connect asciinema.org:443
结果如下:
CONNECTED(00000003)
depth=1 /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/CN=asciinema.org
i:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
1 s:/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
i:/O=Digital Signature Trust Co./CN=DST Root CA X3
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFFDCCA/ygAwIBAgISBDhrp0YwV5NtleFOG+Zj61lQMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA2MDcwOTEyMDBaFw0x
NzA5MDUwOTEyMDBaMBgxFjAUBgNVBAMTDWFzY2lpbmVtYS5vcmcwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+/g237mVels4G9blsZlaeeiURbSp22eGO
T5OZ5As9NyuxSvRVEJrs4xk/RBEkCVgeZspSOmkRLwXG+FSMtjhbqIUt73AUKMdm
4DG+OwkVxjZatskL0wUWRcU7DmyW/Ls/OFJpPPcZ+pqu/v/ek99EiVNoAHJzXMXJ
ZsWy5KLE3fhkrlyMvdIkOkCK5zHOT95t0i8OmdaPIekPBa57VhvnDlUJsYyCF9GN
mP8Qg6OygexyULJGqBwiZ0BN2J6cYwChUlSvqFnkL4OzfixZ+mItuhl1b1vx/N5K
XMtPiM+nc/S+/liIWgtt7HIy9NmrOtSKbPTh3Bv/rfNdaiYx5CUHAgMBAAGjggIk
MIICIDAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNAMhQNNwl+/bJjml9hrrHYzBxbf
MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMw
YTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9y
ZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9y
Zy8wLwYDVR0RBCgwJoINYXNjaWluZW1hLm9yZ4IVc3RhZ2luZy5hc2NpaW5lbWEu
b3JnMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsrBgEEAYLfEwEBATCB1jAm
BggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUF
BwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBv
biBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRo
IHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5j
cnlwdC5vcmcvcmVwb3NpdG9yeS8wDQYJKoZIhvcNAQELBQADggEBABxmJxdQQCcy
FpCkiDrB+vonBUCLYSJtrFkmRdmj9W8/ADpC6M/EhYFOCgrO2cmhYfy1SxDAP5Hd
KIhd3p1F931MMXVcxYt2n6FiDJHN531qp6eBzjZsVIgHXS27PAV466IIMTydNQSe
reyDc9fi+q+ji1Gz89nI8lHIOlRt3dzVGT2J3oQidsm4ZuPNJFj4y8MUrbUAOOH6
YY4n395OKV7vWzl7VPKiCWx+zsv4bzr6IGUPlwqCN2e6cppPWE47ugnYsarINCHO
ie5lU4E2N0k2qVWe/+uYbwSUQ0nrEx8R078m6+6EjDkR4VLboLjuV5tGBgHsJLQB
CmLH6CmNCRE=
-----END CERTIFICATE-----
subject=/CN=asciinema.org
issuer=/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3
---
No client certificate CA names sent
---
SSL handshake has read 3436 bytes and written 456 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES128-SHA
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES128-SHA
Session-ID: AC26CBF8D3719B1DE709A9A8AEAB43D20B14C62085A74604338C512CEA4472C5
Session-ID-ctx:
Master-Key: 0C59B1A2B6802D35FAD26DEE139043A853F3E62787E9AA743A8CAFDA95744DB73AB42B511F37EA7D6BB398A352938551
Key-Arg : None
Start Time: 1497273777
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
HTTP/1.0 400 Bad request
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>
/ cc @约翰
@sickill您可以通过https://ascii.kaos.re检查相同的请求
@andyone刚刚检查。 这(cat tcpflow-req.txt; cat) | openssl s_client -connect ascii.kaos.re:443
-成功上传了吗?
我在这里做了更多的挖掘工作。 centos7上的curl使用nss,而wget使用openssl。 我可以使用curl或wget成功发送请求。 我什至可以使用python httpie工具(在python 3下)发送。
但它无法通过stdin将其发送到openssl s_client
但是通过将请求粘贴到openssl s_client而不是使用stdin,成功将其发送到openssl s_client!
我现在很确定这是因为某些东西正在发送带有LF行尾而不是必需的CRLF行尾的请求,但是我不确定是什么。 我认为“ openssl s_client”是一个不好的测试工具,并且很难确定发生了什么。
但是我还没有使用适当的http客户端,无论是使用nss还是openssl来重现此代码(ubuntu上的curl也使用openssl并且也可以正常工作,因此请再次确认)。 有人管理吗?
我刚刚进行了一些测试,可以确认内容长度为4520的问题仍然存在,但是相同的请求被1000个字符剥离( Content-Length
根据所做的更改进行
我的所有测试中都包含CRLF,并且xxd
确认它们已通过管道发送。
我还可以使用OpenBSD的nc
(支持TLS)进行测试。
从文档中:
tune.bufsize
将缓冲区大小设置为此大小(以字节为单位)。 较低的值允许更多
会话共存于相同数量的RAM中,更高的值允许一些
具有非常大的Cookie的应用程序。 默认值为16384,
可以在构建时更改。 强烈建议不要更改此设置
从默认值开始,因为非常低的值会破坏某些服务,例如
统计信息,并且值大于默认大小会增加内存使用量,
可能导致系统内存不足。 至少是全局的maxconn
参数的减小应与增加该参数的因素相同。
如果HTTP请求大于(tune.bufsize-tune.maxrewrite),则haproxy将
返回HTTP 400(错误请求)错误。 同样,如果HTTP响应较大
超过此大小后,haproxy将返回HTTP 502(错误网关)。
与nginx相比,nginx不会将整个请求保留在内存中,而是即时传递(AFAIK)或至少将其传递到一个临时文件中。
有no option http-buffer-request
Option ,如果我没弄错的话,它会完全禁用该行为(为option http-buffer-request
编写,没有no
):
有时最好先等待HTTP请求的内容,然后再执行
做出决定。 这是通过“ balance url_param”来完成的
例子。 第一个用例是在启动之前缓冲来自慢速客户端的请求
连接到服务器。 另一个用例是进行路由
根据请求主体的内容进行决策。 此选项放置在
前端或后端强制HTTP处理要等到整个
接收到正文,或者请求缓冲区已满,或者第一个块是
在分块编码的情况下完成。 它可能具有不希望出现的副作用
一些应用程序期望HTTP和HTTP之间的无缓冲传输会滥用HTTP
前端和后端,因此绝对不应该使用
默认。
我也刚刚打过。 令我惊讶的是,通过相同的内容通过HTTP而不是HTTPS进行测试,除非您的客户端和代理之间添加了很多额外的标头,否则缓冲区的大小不太可能出错。
但是在终止SSL连接的过程中可能存在一个错误,以至于它会稍微破坏标头。
如果是这样,则有一个选项可以降低HAProxy的安全性,但允许不兼容的HTTP流量通过。 参见https://stackoverflow.com/questions/39286346/extra-space-in-http-headers-gives-400-error-on-haproxy
虽然我不主张降低安全性作为最终解决方案,但是这可能允许您在调试服务时对其进行维护。
@peterbrittain目前asciinema.org使用Brightbox Cloud负载平衡器,因此我无法控制其Haproxy配置。 我们曾经在自己的Nginx中终止SSL,并且工作正常。 由于我切换到BB LB,因此会发生此问题(某些情况)。 您是否正在CentOS或其他系统上体验它?
坦白说,我以前的基于Nginx的解决方案没有任何问题。 我们拥有的SSL证书即将到期,所以我认为我会选择“让我们加密”。 由于LE证书的寿命很短,因此最好对其进行自动管理,而Brightbox LB会为我做到这一点。 我只是想节省设置LE的工作,而BB LB似乎是最简单的解决方案(因为asciinema.org由Brightbox赞助并在其强大的基础架构上运行)。 现在,我认为自己在Nginx中设置LE可能会花费我已经花费了很多时间解决该问题的时间的1/10😞😞😞
啊。 我没有发现谁拥有哪些位的微妙之处。 您是否有运气从BB获得此问题的诊断?
并回答您的问题:我的机器是CentOS 6 VM。
我还遇到了错误的请求问题,使用了asciinema 1.2.0(来自ubuntu 16.04 lts的版本)。
上面给出的curl hack起作用了,谢谢。
我刚刚发现,同一文件确实在我的Gentoo [1]框上产生了一个错误的请求,但在我的OpenBSD [2]框上却没有发出错误的请求。
OpenBSD上传就可以了。
我认为应该进一步调查这些客户之间的区别。
每个ebuild的Gentoo框都支持以下Python目标:
PYTHON_TARGETS="python3_4 -python3_5"
我目前无法轻松测试python3.5,但这也许已经有所帮助。
编辑:我添加了OpenSSL版本,完全忘记了那些。
OpenSSL 1.0.2l 2017年5月25日
腹水1.3.0
我刚刚切换回以前的配置(在Nginx中终止SSL)。 让我知道它现在是否对您有用@andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann
@sickill我只能确定它与之前失败的文件相同,但只有85%,如果已修复,则可以修复。
@sickill现在对我来说就像是一种魅力。 👍
是的,现在也为我工作(使用asciinema upload
)。 谢谢!
最有用的评论
我刚刚切换回以前的配置(在Nginx中终止SSL)。 让我知道它现在是否对您有用@andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann