Detalles sobre el error HTTP 413 - Request entity too large

Imaginemos el siguiente escenario: Tenéis una aplicación web que requiere o acepta certificados de cliente, y que mediante un formulario HTML hace POST para subir ficheros al servidor. En algunas ocasiones, cuando los ficheros superan un determinado tamaño, la petición falla y en los logs de IIS vemos un error HTTP 413 – Request entity too large.

Este es un comportamiento conocido cuando están habilitados certificados de cliente en combinación con que se realiza un petición HTTP de gran tamaño (por ejemplo un POST HTTP adjuntando ficheros). El motivo es que IIS lee los primeros n bytes de la petición (ahora veremos qué determina esa n), asumiendo que deberían haber llegado todos los encabezados de la petición (HTTP headers), pero no necesariamente todos los datos asociados (entity body) de la petición.

 

Esto habitualmente no supone un problema, pero en nuestro escenario en particular, IIS examina los encabezados de la petición, encuentra que la página requiere certificados de cliente y que por lo tanto necesita renegociar la conexión SSL. Desafortunadamente, el cliente (IE) no puede renegociar la conexión porqué está esperando a poder enviar el resto de datos del entity body a IIS. Para evitar que se produzca un deadlock (IIS esperando a poder renegociar la conexión SSL e IE esperando a poder mandar el entity body), IIS devuelve un error HTTP 413 y cierra la conexión.

 

Para evitar que se produzca este problema tenemos dos opciones:

 

1) Para que la renegociación de la conexión se pueda llevar a cabo, el entity body completo tiene que estar “precargado” utilizando SSL Preload. SSL Preload utiliza la propiedad de la metabase UploadReadAheadSize para determinar el tamaño del buffer en el que almacenará la petición (los n bytes a los que hacía referencia antes). Por lo tanto si el tamaño de este buffer es inferior al tamaño total de la petición HTTP (lo que incluye los encabezados HTTP y el entity body), IIS devuelve el error HTTP 413.

El tamaño predeterminado de ese buffer son 48k, lo cual es un tamaño insuficiente en muchas ocasiones, pero que fue establecido así para evitar ataques de denegación de servicio subiendo ficheros “basura” de gran tamaño.

La sintaxis para aumentar dicho buffer es la siguiente, y se puede especificar de forma granular a nivel de directorio virtual:

C:\inetpub\adminscripts>cscript adsutil.vbs set w3svc/1/root/myApp/uploadreadaheadsize 20000000

Microsoft (R) Windows Script Host Version 5.6

Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

uploadreadaheadsize : (INTEGER) 20000000

El número indicado es el número de bytes, por lo que 20.000.000 bytes (como en el ejemplo) serían aproximadamente unas 19,1MB.

2) La otra alternativa es habilitar la clave de la metabase SSLAlwaysNegoClientCert de forma que forcemos a que por cada nueva conexión SSL que se establezca, el servidor negociará inmediatamente el certificado de cliente. De esta forman se previene la renegociación, lo cual supone una ganancia de rendimiento en sí misma, y además evita el problema asociado a las peticiones con entity body de gran tamaño. La sintaxis para habilitar esta clave es:

C:\inetpub\adminscripts>cscript adsutil.vbs set w3svc/1/SSLAlwaysNegoClientCert true

Microsoft (R) Windows Script Host Version 5.6

Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

SSLAlwaysNegoClientCert : (BOOLEAN) True

 

INFORMACIÓN ADICIONAL

Client cannot renegotiate request and returns an HTTP 413 error (IIS 6.0)

https://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/7e0d74d3-ca01-4d36-8ac7-6b2ca03fd383.mspx?mfr=true

                       

 Happy hacking

- Daniel Mossberg