Asciinema: Solicitud incorrecta para cargas de grabaciones> 4kb en CentOS (Python 3.4)

Creado en 7 jun. 2017  ·  58Comentarios  ·  Fuente: asciinema/asciinema

Informe de error

Información del sistema:

  • Versión utilizada: 1.4.0 (1.1.1 también tiene el mismo problema)
  • SO: CentOS Linux versión 7.3.1611
  • Versión de Python: Python 3.4.5
  • Instalar herramientas: yum (del repositorio EPEL)

Pasos para reproducir:

  1. asciinema upload asciicast.json

Comportamiento esperado:

Archivo subido a asciinema.org

Comportamiento real:

Mensaje de error de impresión del cliente:

Error: Invalid request: <html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>

Información adicional:

El cliente crea una grabación rota si se usa zsh ( 4.3.11 (x86_64-redhat-linux-gnu) en mi caso) y oh-my-zsh está instalado. Si oh-my-zsh está desactivado o bash se usa como shell, el cliente crea y carga la grabación sin ningún problema.

Grabación de JSON: https://gist.github.com/andyone/b2a883e8c3795a6ad393a715ff7a41df

compatibility help wanted hosting

Comentario más útil

Acabo de volver a la configuración anterior (terminando SSL en Nginx). Déjame saber si te funciona ahora @andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann

Todos 58 comentarios

A mí también me pasa. Usando ZSH pero no OMZ.

$ zsh --version
zsh 5.3.1 (x86_64-pc-linux-gnu)
$ asciinema --version
asciinema 1.4.0

tmpw6byrbv8-asciinema.json

Descubrí que si cambio la URL de la API de HTTPS a HTTP, todo funciona bien.

Ayer cambié la configuración del equilibrador de carga, por lo que esto puede estar relacionado.

Pude reproducir esto en Centos 7 Vagrant VM. Creo que esto tiene algo que ver con el balanceador de carga de Brightbox (con terminación SSL, certificado automático Let's Encrypt) que usamos desde ayer.

@andyone @ThiefMaster ¿puedes probar ahora? Puede que lo haya resuelto.

todavía obteniendo un 400

Creo que es un problema relacionado con OpenSSL. Enviar datos con curl está bien porque curl usa NSS (Servicios de seguridad de red) para trabajar con SSL / TLS.

con balanceador de carga Brightbox

¿Es una solución basada en nginx?

@andyone Creo que el balanceador de carga de Brightbox usa Haproxy.

Puedo reproducir esto de manera consistente. Creé Vagrantfile e instrucciones: https://github.com/sickill/bb-lb-400

@andyone, el problema no parece ser esta línea específica en su grabación, sino el tamaño general del archivo json cargado.

Creé un proxy https://ascii.kaos.io basado en webkaos (es nginx mejorado con BoringSSL) con esta configuración . Mis grabaciones y @ThiefMaster se cargaron correctamente a través de este proxy.

Esto es lo que sé hasta ahora:

Las solicitudes HTTP van bien a través del balanceador de carga de Brightbox, pero las HTTPS dan 400 solicitudes incorrectas
para la solicitud donde el cuerpo de la solicitud es más grande que aproximadamente 4 KB.

Lo interesante es que obtenemos 400 para HTTPS en CentOS. HTTPS en macOS funciona bien. (HTTP funciona bien en todas partes).

Miré más profundamente, traté de averiguar dónde estaba la diferencia. Usé tcpdump para ver las solicitudes tanto en CentOS como en macOS (HTTP, asumimos que la solicitud en sí tiene el mismo formato que en HTTPS).

La única diferencia parece ser 2 líneas vacías antes del cuerpo en macOS, 1 línea vacía en CentOS (probablemente debido a una versión ligeramente diferente de urllib que viene con Python 3 en estos sistemas operativos):

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>

Mac OS:

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>

Para ver cómo afecta las cosas, cambié temporalmente "Tamaño de búfer de solicitud" en LB de 4096 (predeterminado) a 8192 (máximo) y de repente comenzó a funcionar bien en todas partes (todos los sistemas operativos, HTTPS), ¡yay!

No estoy muy seguro de que esta sea la solución definitiva porque con un tamaño de búfer de 4096 esto es cierto:

  • Puedo hacer una solicitud POST con un cuerpo de 3 MB sin problemas
    HTTPS en macOS
  • Por lo tanto, supongo que este tamaño de búfer es para encabezados y no para el cuerpo de la solicitud (esto fue confirmado por John de Brightbox)
  • Puedo hacer una solicitud POST con <4KB body sin problemas
    HTTPS en CentOS
  • NO puedo realizar una solicitud POST con un cuerpo de> 4KB a través de HTTPS en CentOS
  • Lo anterior contradice mi suposición sobre la aplicación del búfer solo para encabezados ...
  • Los encabezados de solicitud son pequeños (~ 330 bytes) en todos los casos

Cuando elevo "solicitar tamaño de búfer" a 8192, el tamaño del cuerpo y el protocolo
no importa y todo funciona bien. Me pregunto si al chocar
a 8192 Solo estoy ganando tiempo (hacer que menos personas se vean afectadas) o esto
resuelve el problema por completo (si es así, ¿por qué?).

Me comuniqué con Brightbox sobre esto, espero que puedan explicar lo que está sucediendo.

Actualice el tamaño del búfer de 8192 en el lado de Brightbox: con este número me funciona en CentOS, pero todavía no funciona para @ThiefMaster .

Ops, lo siento.

Antes de pasar el tráfico a través de Brightbox LB, terminé SSL en Nginx y todo funcionó bien durante años. Si funciona con el proxy de @andyone basado en Nginx, entonces puede sugerir que Nginx es más "indulgente" con el formato de solicitud, mientras que Haproxy es más estricto, y el cliente asciinema formatea la solicitud incorrectamente (para los estándares de Haproxy) bajo Python 3.4 (y su urllib, que es anterior al 3.6.1 que uso en mac).

Puedo comprobarlo más tarde con Haproxy, pero mi versión está construida con LibreSSL en lugar de OpenSSL.

Mi teoría actual es esta:

Esta única línea nueva antes de los encabezados y el cuerpo no es suficiente para que LB termine de leer los encabezados (espera 2 líneas nuevas), y sigue leyendo todos los datos debajo de ella como encabezados, contando bytes, que eventualmente exceden el tamaño máximo de los encabezados. Si LB tiene alguna variable como bytes_read (bytes leídos del socket), verifica su valor después de terminar de leer los encabezados y luego nuevamente después de leer el cuerpo. Si carga un archivo <4kb, nunca supera el límite de 4kb para los encabezados, y si carga> 4kb, lo supera.
(y esto solo ocurre bajo HTTPS)

No tengo idea de si ese es el caso, solo pienso en voz alta 😀

Se actualizó el código fuente para que agregue una nueva línea adicional, se verificó en CentOS y aún falla. Entonces, la teoría anterior es incorrecta.

Esto funciona en CentOS con 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

Entonces, ¿tal vez SSL lib usado por Python es diferente a curl y el problema está en algún lugar de SSL-land?

Creo que sí. Python usa OpenSSL, curl usa NSS.

@andyone el certificado para ascii.kaos.io no es Let's Encrypt?

RapidSSL SHA256withRSA

Normalmente, diría que a CentOS le falta el certificado raíz para Let's Encrypt (o algo así 😊), pero se está realizando la conexión SSL y el error está en el nivel del protocolo HTTP (400 Bad Request) así que ... 👐

Si falta el certificado raíz de Let's Encrypt, no funcionará ni siquiera con curl.

Nuestro balanceador de carga (Brightbox) sí usa haproxy. La RFC HTTP y los documentos haproxy establecen que se requiere una CRLF para separar los encabezados del cuerpo:

https://github.com/haproxy/haproxy/blob/master/doc/internals/http-parsing.txt

¿Es posible que solo envíe un CR o un LF aquí, en lugar de un CRLF completo?

@sickill Este es un proxy en HA-Proxy 1.7.5 con LibreSSL 2.5.0 - https://ascii-ha.kaos.io. Mis grabaciones y @ThiefMaster , y over-4k.json de su repositorio se cargaron correctamente a través de este proxy.

@andyone ok. Entonces, ¿puedes cambiar tune.bufsize (https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#3.2-tune.bufsize) a 4096?

@johnl Verifiqué CRLF y todo está bien aquí.

Volví a enviar la solicitud tanto en CentOS como en macOS (a través de HTTP, nuevamente, asumiendo que la carga útil de HTTP es la misma para HTTPS).

dump-centos.pcap.txt y dump-mac.pcap.txt contienen captura tcpdump ( tcpdump -s 0 dst port 80 -w dump-centos.pcap.txt ).
dump-centos-hex.txt y dump-mac-hex.txt contienen volcados con formato hexadecimal (a través de hexdump -C ).

dump-centos-hex.txt
dump-centos.pcap.txt
dump-mac-hex.txt
dump-mac.pcap.txt

Parece que en ambos sistemas operativos se usa CRLF para nuevas líneas, y hay una línea en blanco entre los encabezados y el cuerpo.

En el CentOS izquierdo, en el macOS derecho:

centos-mac-comparison

@sickill Config actualizada. over-4k.json subidos también.

@andyone gracias por la actualización. Parece que no agrega el encabezado X-Forwarded-Proto (porque la URL de grabación devuelta es http:// ). ¿Puedes agregar http-request set-header X-Forwarded-Proto https if { ssl_fc } ?

Esta es mi configuración:

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

¿Dónde debo agregar esta línea?

@andyone Creo que debe ir a la sección backend (aunque no soy un experto en haproxy).

@andyone por cierto, REALMENTE aprecio que me hayas ayudado a depurar esto 😍 ¡Gracias!

no te olvides de reenviar también. Esto debería replicar la configuración bastante de cerca, con los cifrados ssl también:

    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

Modifiqué la configuración a esto, pero sin suerte:

    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

El cliente todavía devuelve enlaces con http:// .

Siempre estoy feliz de ayudar a mejorar los servicios útiles 😉.

@johnl Esta es una configuración completa, todas las opciones requeridas se establecen en las secciones defaults y 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

Si la configuración haproxy de @andyone ahora está muy cerca de BB y todavía no podemos reproducir el problema, ¿tiene sentido intentarlo con el certificado Let's Encrypt? Esta es una de las diferencias entre https://ascii-ha.kaos.io y https://asciinema.org.

Esta es una de las diferencias entre https://ascii-ha.kaos.io y https://asciinema.org.

No. BB LB se puede construir con OpenSSL (yo uso LibreSSL).

Intentaré agregar el certificado Let's Encrypt para https://ascii-ha.kaos.io.

Hecho - https://ascii.kaos.re
HA-Proxy 1.7.5 (con LibreSSL 2.5.0) + certificado Let's Encrypt (creado por Certbot)
Config:

    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

Parece que todo funciona bien. over-4k.json subido correctamente.

No tengo más ideas para esto. Estoy considerando volver a mi propia instancia de Nginx para el equilibrio de carga y la terminación de SSL 🤕

Estoy tratando de reducir esto a un solo comando curl que puede reproducir el problema, pero aún no lo he logrado, ¿alguien puede ayudar?

Estoy PUBLICANDO un cuerpo de 5k, con un nombre de usuario / contraseña de autenticación usando curl. Estoy usando un balanceador de carga de Brightbox con un servidor web netcat backend, por lo que puedo ver el texto de la solicitud sin procesar. Siempre pasa, no puede hacer que active una respuesta de solicitud incorrecta.

Si el equilibrador de carga lo rechaza, no debería necesitar una instancia real de la aplicación en el backend, ya que nunca debería llegar tan lejos, por lo que deberíamos poder reproducir esto con curl y sin aplicación.

Probé curl en ubuntu y centos7, y con openssl específicamente (tenga en cuenta que puede especificar el comando --engine para curl para elegir qué lib sslib usar. Los binarios de centos7 curl se compilan con la mayoría de las opciones)

@johnl gracias por investigar esto.

Tiene sentido usar netcat como backend para las pruebas 👍

curl equivalente para asciinema upload over-4k.json es más o menos esto:

curl -v -X POST -u test:uuid4 https://asciinema.org/api/asciicasts -F [email protected]

(reemplace uuid4 con el resultado de python3 -c 'import uuid; print(uuid.uuid4())' )

Y funciona con curl de hecho ...

Comparé tcpdump de asciinema upload y el rizo anterior y no hay nada en el nivel del protocolo HTTP que me parezca sospechoso. Sin embargo, algunas tramas tcp se muestran en diferentes ubicaciones (tal vez se envíen o se ajusten más / menos datos en cada paquete tcp).

Capturé la solicitud HTTP (a http://asciinema.org) con tcpflow en CentOS 7 VM:

sudo tcpflow -p -C -i eth0 port 80 >tcpflow-req.txt

Luego, en otro shell (en la misma VM) se ejecutó:

ASCIINEMA_API_URL=http://asciinema.org asciinema upload /vagrant/over-4k.json

Corté la respuesta, dejando solo una solicitud. Esto es lo que se envía, byte a byte:

Repetí esta solicitud HTTP capturada contra asciinema. org: 80 con 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

Todo bien.

Ahora, envié SSL a asciinema. org: 443 :

(cat tcpflow-req.txt; cat) | openssl s_client -connect asciinema.org:443

Aquí está el resultado:

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 ¿Puede verificar la misma solicitud con https://ascii.kaos.re?

@andyone acaba de comprobarlo. Hizo esto (cat tcpflow-req.txt; cat) | openssl s_client -connect ascii.kaos.re:443 - subido correctamente.

He investigado más aquí. curl en centos7 usa nss pero wget usa openssl. Puedo enviar la solicitud con éxito con curl o wget. Incluso puedo enviar usando la herramienta python httpie (bajo python 3).

pero no lo envía a openssl s_client a través de stdin

¡pero logra enviarlo a openssl s_client pegando la solicitud en él, en lugar de usar stdin!

Ahora estoy bastante seguro de que esto se debe a que algo está enviando solicitudes con terminaciones de línea LF en lugar de las terminaciones de línea CRLF requeridas, pero no estoy seguro de qué. Creo que "openssl s_client" es una mala herramienta de prueba y dificulta estar seguro de lo que está sucediendo.

Pero todavía tengo que reproducir esto con un cliente http adecuado, ya sea usando nss o openssl (curl en ubuntu usa openssl y también funciona bien, así que lo confirmó dos veces). ¿Alguien más logra eso?

Acabo de hacer algunas pruebas por mi cuenta y puedo confirmar que este problema persiste con una longitud de contenido de 4520, pero no con la misma solicitud despojada de 1000 caracteres ( Content-Length ajustada de acuerdo con los cambios realizados).

Los CRLF están presentes en todas mis pruebas y xxd confirma que se envían a través de la tubería.
También podría probar con nc OpenBSD (que admite TLS).

De la documentación :

tune.bufsize
Establece el tamaño del búfer en este tamaño (en bytes). Los valores más bajos permiten más
sesiones para coexistir en la misma cantidad de RAM, y los valores más altos permiten algunas
aplicaciones con cookies muy grandes para que funcionen. El valor predeterminado es 16384 y
se puede cambiar en el momento de la construcción. Se recomienda encarecidamente no cambiar este
del valor predeterminado, ya que los valores muy bajos romperán algunos servicios como
estadísticas y valores mayores que el tamaño predeterminado aumentarán el uso de memoria,
posiblemente provocando que el sistema se quede sin memoria. Al menos el maxconn global
El parámetro debe reducirse en el mismo factor que éste aumenta.
Si la solicitud HTTP es mayor que (tune.bufsize - tune.maxrewrite), haproxy
devuelve el error HTTP 400 (solicitud incorrecta). Del mismo modo, si una respuesta HTTP es más grande
que este tamaño, haproxy devolverá HTTP 502 (Bad Gateway).

A diferencia de nginx, que no guarda toda la solicitud en la memoria, sino que la transmite sobre la marcha (AFAIK) o, al menos, la almacena en un archivo temporal.

Existe la Opción no option http-buffer-request , que, si lo hago bien, deshabilita exactamente ese comportamiento (escrito para option http-buffer-request , sin no ):

A veces es deseable esperar el cuerpo de una solicitud HTTP antes
tomar una decisión. Esto es lo que está haciendo "balance url_param" para
ejemplo. El primer caso de uso es almacenar en búfer las solicitudes de clientes lentos antes
conectando al servidor. Otro caso de uso consiste en tomar el enrutamiento
decisión basada en el contenido del cuerpo de la solicitud. Esta opción colocada en un
frontend o backend obliga al procesamiento HTTP a esperar hasta que el
se recibe el cuerpo, o el búfer de solicitud está lleno, o el primer fragmento está
complete en caso de codificación fragmentada. Puede tener efectos secundarios no deseados con
algunas aplicaciones abusan de HTTP al esperar transmisiones sin búfer entre
el frontend y el backend, por lo que definitivamente no debería ser utilizado por
defecto.

Acabo de golpear esto también. Me sorprende que con sus pruebas del mismo contenido funcionando a través de HTTP pero no HTTPS, es poco probable que sean los tamaños de búfer los que fallen, a menos que algo entre su cliente y el proxy agregue muchos encabezados adicionales.

Pero tal vez haya un error en lo que sea que esté terminando sus conexiones SSL, de modo que corrompa ligeramente los encabezados.

Si es así, existe una opción que reduce la seguridad de HAProxy, pero permite un tráfico HTTP menos compatible. Consulte https://stackoverflow.com/questions/39286346/extra-space-in-http-headers-gives-400-error-on-haproxy

Si bien no defiendo la reducción de la seguridad como solución final, esto podría permitirle mantener el servicio mientras lo depura.

@peterbrittain en este momento asciinema.org usa el balanceador de carga Brightbox Cloud, así que no controlo su configuración de Haproxy. Solíamos terminar SSL en nuestro propio Nginx y eso estaba funcionando bien. Desde que cambié a BB LB, se produce este problema (para algunos). ¿Lo está experimentando bajo CentOS u otro sistema?

Francamente, no he tenido ningún problema con la solución anterior basada en Nginx. El certificado SSL que teníamos estaba caducando, así que pensé en usar Let's Encrypt. Dado que los certificados LE son de corta duración, es mejor administrarlos automáticamente y Brightbox LB lo hace por mí. Solo quería ahorrarme trabajo en la configuración de LE y BB LB parecía ser la solución más simple (ya que asciinema.org está patrocinado por Brightbox y se ejecuta en su gran infraestructura). Ahora creo que configurar LE yo mismo en Nginx probablemente tomaría 1/10 del tiempo que ya dediqué a solucionar este problema 😞😞😞

¡Ah! No vi la sutileza de quién poseía qué partes. ¿Ha tenido suerte obteniendo diagnósticos de BB para este problema?

Y en respuesta a su pregunta: mi caja es una VM CentOS 6.

También acabo de experimentar el problema de la solicitud incorrecta, usando asciinema 1.2.0 (versión de ubuntu 16.04 lts).

El truco de rizo dado anteriormente funcionó, gracias.

Acabo de descubrir que el mismo archivo produce una solicitud incorrecta en mi caja Gentoo [1], pero no en mi caja OpenBSD [2].
OpenBSD lo carga perfectamente.
Creo que debería investigarse más a fondo la diferencia entre estos clientes.
La caja de Gentoo admite los siguientes objetivos de Python por ebuild:

PYTHON_TARGETS="python3_4 -python3_5"

Sin embargo, actualmente no puedo probar python3.5 fácilmente, pero tal vez esto ya ayude.

Editar : agregué las versiones de OpenSSL, me olvidé por completo de ellas.

  • asciinema 1.4.0

    • ejecutado usando python-exec 2.4.5

    • a su vez ejecutando Python 3.4.6

  • OpenSSL 1.0.2l 25 de mayo de 2017

  • asciinema 1.3.0

    • ejecutado usando Python 3.6.0
  • LibreSSL 2.5.2

Acabo de volver a la configuración anterior (terminando SSL en Nginx). Déjame saber si te funciona ahora @andyone @ThiefMaster @benaryorg @peterbrittain @ThomasWaldmann

@sickill Estoy solo un 85% seguro de que es el mismo archivo que falló antes, pero si es así, lo ha arreglado.

@sickill funciona como un encanto para mí ahora. 👍

Sí, funciona para mí (con asciinema upload ) también ahora. ¡Gracias!

¿Fue útil esta página
0 / 5 - 0 calificaciones