Системная информация:
Действия по воспроизведению:
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://gist.github.com/andyone/b2a883e8c3795a6ad393a715ff7a41df
Со мной тоже бывает. Использует ЗШ, но не ОМЗ.
$ zsh --version
zsh 5.3.1 (x86_64-pc-linux-gnu)
$ asciinema --version
asciinema 1.4.0
Я обнаружил, что если я изменю URL-адрес API с HTTPS на HTTP, все будет работать нормально.
Вчера я изменил конфигурацию балансировщика нагрузки, так что это может быть связано.
Мне удалось воспроизвести это в Centos 7 Vagrant VM. Я думаю, это как-то связано с балансировщиком нагрузки Brightbox (с завершением SSL, автоматическим сертификатом Let's Encrypt), который мы используем со вчерашнего дня.
@andyone @ThiefMaster можешь попробовать сейчас? Возможно, я решил это.
все еще получаю 400
Я думаю, что это проблема, связанная с OpenSSL. Отправка данных с помощью curl - это нормально, потому что curl использует NSS (службы сетевой безопасности) для работы с SSL / TLS.
с балансировщиком нагрузки Brightbox
Это решение на базе nginx?
@andyone Я думаю, что балансировщик нагрузки Brightbox использует Haproxy.
Я могу постоянно воспроизводить это. Я создал Vagrantfile и инструкции: https://github.com/sickill/bb-lb-400
@andyone проблема, похоже, не в этой конкретной строке в вашей записи, а в общем размере загруженного файла json.
Я создал прокси https://ascii.kaos.io на основе webkaos (он улучшил nginx с помощью BoringSSL) с этой конфигурацией . Мои записи и записи @ThiefMaster успешно загружены через этот прокси.
Вот что я знаю на данный момент:
HTTP-запросы проходят через балансировщик нагрузки Brightbox, но HTTPS-запросы дают 400 Bad Request
для запроса, размер тела которого превышает 4 КБ.
Интересно, что мы получаем 400 для HTTPS под CentOS. HTTPS под macOS работает нормально. (HTTP везде работает нормально).
Я посмотрел глубже, попытался выяснить, в чем разница. Я использовал tcpdump для просмотра запросов как в CentOS, так и в macOS (HTTP, предполагалось, что сам запрос отформатирован так же, как и в HTTPS).
Единственная разница, похоже, состоит в 2 пустых строках перед телом в macOS и 1 пустой строке в CentOS (вероятно, из-за немного другой версии urllib, которая поставляется с Python 3 в этих ОС):
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>
macOS:
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 по этому поводу, надеюсь, они смогут объяснить, что происходит.
Обновите размер буфера 8192 на стороне Brightbox: с этим номером он работает у меня под CentOS, но все еще не работает для @ThiefMaster .
Упс, извини.
Прежде чем я пропустил трафик через Brightbox LB, я отключил SSL в Nginx, и все работало нормально в течение многих лет. Если он работает с прокси @andyone , основанным на Nginx, то это может указывать на то, что Nginx более «снисходителен» к форматированию запросов, в то время как Haproxy более строг, и клиент asciinema неправильно форматирует запрос (для стандартов Haproxy) под Python 3.4 (и его urllib, который старше версии 3.6.1, которую я использую на Mac).
Я могу проверить это позже с помощью Haproxy, но моя версия построена с использованием LibreSSL вместо OpenSSL.
Моя текущая теория такова:
Одной новой строки перед заголовками и телом недостаточно, чтобы LB завершил чтение заголовков (он ожидает 2 новые строки), и он продолжает читать все данные под ним как заголовки, считая байты, которые в конечном итоге превышают максимальный размер для заголовков. Если LB имеет некоторую переменную, например bytes_read
(байты читаются из сокета), он проверяет ее значение после завершения чтения заголовков, а затем снова после чтения тела. Если вы загружаете файл размером <4 КБ, он никогда не превышает ограничение в 4 КБ для заголовков, а если вы загружаете> 4 КБ, оно превышает его.
(и это происходит только по HTTPS)
Понятия не имею, так ли это, просто думаю вслух 😀
Обновлен исходный код, поэтому он добавляет дополнительную новую строку, проверяется в CentOS и по-прежнему не работает. Итак, приведенная выше теория неверна.
Это работает под CentOS с HTTPS:
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
Так, может быть, SSL lib, используемый Python, отличается от curl, и проблема кроется где-то в SSL-мире?
Я думаю так. Python использует OpenSSL, curl использует NSS.
@andyone сертификат для ascii.kaos.io не Let's Encrypt?
RapidSSL SHA256withRSA
Обычно я бы сказал, что в CentOS отсутствует корневой сертификат для Let's Encrypt (или что-то в этом роде 😊), но выполняется SSL-соединение, и ошибка находится на уровне протокола HTTP (400 Bad Request), поэтому ... 👐
Если корневой сертификат для 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 Это прокси на HA-Proxy 1.7.5 с LibreSSL 2.5.0 - 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, и здесь все в порядке.
Я снова tcpdumped запрос как на CentOS, так и на macOS (опять же через 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
).
дамп-centos-hex.txt
дамп-centos.pcap.txt
дамп-mac-hex.txt
дамп-mac.pcap.txt
Кажется, что в обеих ОС для новых строк используется CRLF, и между заголовками и телом есть одна пустая строка.
Слева CentOS, справа macOS:
@sickill Config обновлен. 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
Если конфигурация haproxy @andyone теперь очень близка к BB, и мы все еще не можем воспроизвести проблему, имеет ли смысл попробовать сертификат Let's Encrypt? Это одно из различий между https://ascii-ha.kaos.io и https://asciinema.org.
Это одно из различий между https://ascii-ha.kaos.io и https://asciinema.org.
Нет. BB LB можно построить с помощью OpenSSL (я использую LibreSSL).
Я попробую добавить сертификат Let's Encrypt для https://ascii-ha.kaos.io.
Готово - https://ascii.kaos.re
HA-Proxy 1.7.5 (с LibreSSL 2.5.0) + сертификат Let's Encrypt (создан 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. Я использую балансировщик нагрузки Brightbox с бэкэндом веб-сервера netcat, поэтому я могу видеть необработанный текст запроса. Он всегда проходит - не может вызвать неверный ответ на запрос.
Если это отклоняется балансировщиком нагрузки, мне не нужен реальный экземпляр приложения на бэкэнде, поскольку он никогда не должен заходить так далеко - поэтому мы должны иметь возможность воспроизвести это с помощью curl и без приложения.
Я пробовал curl на ubuntu и centos7, и в частности с openssl (обратите внимание, что вы можете указать команду --engine для curl, чтобы выбрать, какую библиотеку sslib использовать. Двоичные файлы curl centos7 созданы для большинства параметров)
@johnl, спасибо, что
Имеет смысл использовать netcat в качестве бэкэнда для тестирования 👍
Эквивалент curl для asciinema upload over-4k.json
примерно такой:
curl -v -X POST -u test:uuid4 https://asciinema.org/api/asciicasts -F [email protected]
(замените uuid4
результатом python3 -c 'import uuid; print(uuid.uuid4())'
)
И это действительно работает с curl ...
Я сравнил tcpdump из asciinema upload
и приведенный выше curl, и на уровне протокола HTTP нет ничего подозрительного для меня. Однако некоторые кадры TCP отображаются в разных местах (может быть, больше / меньше данных отправляется / помещается в каждый пакет TCP).
Я записал HTTP-запрос (на http://asciinema.org) с помощью tcpflow в CentOS 7 VM:
sudo tcpflow -p -C -i eth0 port 80 >tcpflow-req.txt
Затем в другой оболочке (в той же виртуальной машине) выполнялось:
ASCIINEMA_API_URL=http://asciinema.org asciinema upload /vagrant/over-4k.json
Я отрезал от него ответ, оставив только запрос. Вот что отправляется побайтно: tcpflow-req.txt
Я воспроизвел этот захваченный HTTP-запрос на asciinema. 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 @johnl
@sickill Можете ли вы проверить тот же запрос с https://ascii.kaos.re?
@andyone только что проверил. (cat tcpflow-req.txt; cat) | openssl s_client -connect ascii.kaos.re:443
- успешно загружено.
Я здесь больше покопался. curl на centos7 использует nss, но wget использует openssl. Я могу успешно отправить запрос с помощью curl или wget. Я даже могу отправить с помощью инструмента python httpie (под python 3).
но он не может отправить его в openssl s_client через stdin
но ему удается отправить его в openssl s_client, вставив в него запрос, а не используя stdin!
Теперь я почти уверен, что это потому, что что-то отправляет запросы с окончанием строки LF, а не с требуемым окончанием строки CRLF, но я не совсем уверен, что именно. Я думаю, что "openssl s_client" - плохой инструмент для тестирования и затрудняет понимание того, что происходит.
Но мне еще предстоит воспроизвести это с помощью надлежащего http-клиента, независимо от того, используется ли nss или openssl (curl на ubuntu использует openssl и тоже отлично работает, поэтому дважды подтвердил это). Кто-нибудь еще справится с этим?
Я только что провел небольшое тестирование и могу подтвердить, что эта проблема сохраняется с длиной содержимого 4520, но не с тем же запросом, разделенным на 1000 символов ( Content-Length
скорректировано в соответствии с внесенными изменениями).
CRLF присутствуют во всех моих тестах, и xxd
подтверждает, что они отправляются по каналу.
Я также мог протестировать с помощью OpenBSD nc
(который поддерживает TLS).
Из документации :
tune.bufsize
Устанавливает размер буфера равным этому размеру (в байтах). Более низкие значения позволяют больше
сеансы сосуществуют в одном и том же объеме ОЗУ, а более высокие значения позволяют некоторым
приложения с очень большими файлами cookie для работы. Значение по умолчанию - 16384 и
можно изменить во время сборки. Настоятельно рекомендуется не изменять это
от значения по умолчанию, так как очень низкие значения нарушат работу некоторых служб, таких как
статистика и значения, превышающие размер по умолчанию, увеличивают использование памяти,
возможно, из-за нехватки памяти в системе. Хотя бы глобальный maxconn
параметр должен быть уменьшен во столько же раз, как этот.
Если HTTP-запрос больше, чем (tune.bufsize - tune.maxrewrite), haproxy будет
вернуть ошибку HTTP 400 (неверный запрос). Аналогично, если ответ HTTP больше
чем этот размер, haproxy вернет HTTP 502 (Bad Gateway).
В отличие от nginx, который не хранит весь запрос в памяти, а передает его на лету (AFAIK) или, по крайней мере, буферизует его во временный файл.
Существует опция no option http-buffer-request
, которая, если у меня есть это право, отключает именно это поведение (написано для option http-buffer-request
, без no
):
Иногда желательно дождаться тела HTTP-запроса перед
принятие решения. Это то, что делает "balance url_param" для
пример. Первый вариант использования - это буферизация запросов от медленных клиентов перед
подключение к серверу. Другой вариант использования состоит в том, чтобы использовать маршрутизацию
решение, основанное на содержании тела запроса. Эта опция помещена в
интерфейс или серверная часть заставляют обработку 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. Мы использовали для прерывания SSL в нашем собственном Nginx, и это работало нормально. Поскольку я перешел на BB LB, эта проблема возникает (у некоторых). Вы испытываете это в CentOS или другой системе?
Честно говоря, у меня не было проблем с предыдущим решением на основе Nginx. Срок действия SSL-сертификата истек, поэтому я решил использовать Let's Encrypt. Поскольку сертификаты LE недолговечны, лучше всего ими управлять автоматически, и Brightbox LB делает это за меня. Я просто хотел сэкономить время на настройке LE, и BB LB показался самым простым решением (поскольку asciinema.org спонсируется Brightbox и работает на их великолепной инфраструктуре). Теперь я думаю, что самостоятельная настройка LE в Nginx, вероятно, займет 1/10 того времени, которое я уже потратил на устранение этой проблемы 😞😞😞
Ах. Я не заметил тонкости того, кому и какие биты принадлежат. Удалось ли вам получить диагнозы от BB по этой проблеме?
И в ответ на ваш вопрос: моя коробка - это виртуальная машина CentOS 6.
Я также только что столкнулся с проблемой неправильного запроса, используя asciinema 1.2.0 (версия от ubuntu 16.04 lts).
Приведенный выше метод curl сработал, спасибо.
Я только что обнаружил, что тот же самый файл выдает неверный запрос на моем компьютере Gentoo [1], но не на моем компьютере OpenBSD [2].
OpenBSD загружает это нормально.
Я думаю, что необходимо дальнейшее исследование разницы между этими клиентами.
Блок Gentoo поддерживает следующие цели Python для каждой сборки:
PYTHON_TARGETS="python3_4 -python3_5"
В настоящее время я не могу легко протестировать python3.5, но, возможно, это уже помогает.
Изменить : я добавил версии OpenSSL, полностью забыл о них.
OpenSSL 1.0.2l 25 мая 2017 г.
asciinema 1.3.0
Я только что вернулся к предыдущей конфигурации (отключение SSL в Nginx). Дайте мне знать, работает ли это для вас сейчас @andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann
@sickill Я только на 85% уверен, что это тот же файл, который раньше не удался, но если это так, вы его исправили.
@sickill Теперь для меня работает как шарм. 👍
Да, у меня тоже работает (с asciinema upload
). Спасибо!
Самый полезный комментарий
Я только что вернулся к предыдущей конфигурации (отключение SSL в Nginx). Дайте мне знать, работает ли это для вас сейчас @andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann