我在Linux服务器上运行Apache(2.2.14)上的PHP(PHP 5.3.2)应用程序.在其历史记录中,用户开始在其浏览器中看到以下消息:"请求实体太大".首次谷歌搜索建议,当上传的文件太大或者cookie过大时,就会发生这种情况.但它不会在文件上传时发生,仅在登录时始终在登录页面上发生.用户只需通过页面上的普通POST表单进入此页面.并且cookie仅包含会话ID.
此外,apache正在记录"Invalid Content-Length".这是在我的任何代码执行之前记录的.尽管$ _POST应该包含一些数据,但它是空的.当我添加以下行时:
error_log("Content-Length: ".$_SERVER['CONTENT_LENGTH']);
Run Code Online (Sandbox Code Playgroud)
它说
Content-Length: 32, 32
Run Code Online (Sandbox Code Playgroud)
这似乎确实无效.更改浏览器或重置用户PC似乎没有帮助.一切都在第二天开始工作.
问题在哪里?是Apache,PHP,用户的网络设置吗?如果我需要添加更多信息,请告诉我.
在过去的几天里,我们遇到了Apache在error_log中记录的"Invalid Content-Length"消息.从一些特定的IP类跟踪了一些访问者的问题,例如Movistar Argentina:200.81.44.201使用tcpdump/whireshark进一步检查请求我们发现POST请求包含一些
重复标题,即Content-Length和Content-Type
真正的问题在于Content-Length,因为Apache通过连接它们来处理多个变量,例如:
Content-Length: 51
Content-Length: 51
Run Code Online (Sandbox Code Playgroud)
结果将是:
Content-Length: 51, 51
Run Code Online (Sandbox Code Playgroud)
然后Apache尝试将字符串"51,51"转换为一个不可能的整数.在较新的Apache> 2.2.17,或者,反向移植补丁Apache日志错误:413请求实体过大,与旧的Apache,过程只是hungs占用大量的CPU时间.在IP类后面,我们看到更多不同的客户端,因此它们可能是错误配置的3G网关代理服务器,因为它们会复制这些标头.所以我们找到了一个解决方案来配置Apache只用一个Content-Length和一个Content-Type Headers来重写Request:这是我的代码,使用mod_headers和在httpd.conf中插入的SetEnvIfNoCase:
SetEnvIfNoCase Content-Length (.*), MyContentLength=$1
SetEnvIfNoCase Content-Type (.*), MyContentType=$1
RequestHeader set Content-Length: "%{MyContentLength}e" env=MyContentLength
RequestHeader set Content-Type: "%{MyContentType}e" env=MyContentType
Run Code Online (Sandbox Code Playgroud)
您可以自由地测试和使用此代码,以过滤掉重复的Content-Length HTTP Header变量.
调查此类问题的最简单方法是使用TCPDump将客户端和服务器之间发送的数据包捕获到文件中,然后使用Wireshark将数据包作为 TCP 流查看。
捕获数据包的命令示例如下。
tcpdump -vvv -A -i eth0 '主机 123.123.10.12 && 端口 80' -w eth0.dat
由于它是您的登录页面,您可能需要解码 TCP 流,因为它应该位于 HTTPS 后面 - 这可以使用http://segfault.in/2010/11/decrypt-https-traffic-using-中的说明来完成wireshark 和密钥文件/
Plasmid87 几乎肯定是正确的 - 听起来其中一个标头正在大量增长,并最终变得大于 Apache LimitRequestFieldSize。
只要它增长缓慢而不是突然增长,您就可以通过检查全局变量来调查它。
function checkVars(){
$varsToCheck = array($GLOBALS, $_SERVER, $_GET, $_POST, $_FILES, $_REQUEST, $_SESSION, $_ENV, $_COOKIE);
foreach($varToCheck as $var){
foreach($var as $key => $value){
if(count($key) > 1024){
logToFile("Found ridiculous key: ".$key." value is ".$value);
}
if(count($value) > 1024){
logToFile("Found ridiculous value for key: ".$key." value is ".$value);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4747 次 |
| 最近记录: |