【Nginx】图片不完整,竟然是Nginx的锅!!

admin 2022年3月13日23:19:47评论396 views字数 5115阅读17分3秒阅读模式




前言

最近,安全运维过程中遇到一个奇葩问题,通过浏览器访问某静态图片,只能访问大约八分之一,其余的部分无法完全加载出来。最初我们以为是某信Waf拦截导致图片无法下载,为了解决问题,增加某0 WAf路线,结果,某信异常,某0正常,问题越来越复杂,经过一系列排查(过程省略,直奔主题),最终定位是Nginx的问题。

问题定位

1.首先尝试关闭某信Waf然后查看图片情况,经确认,图片依然异常,排除某信Waf规则拦截导致图片不完整。

【Nginx】图片不完整,竟然是Nginx的锅!!
image-20220313172125833

2.抓包分析,发现Transfer-Encoding: chunked字段,猜测服务器给客户端返回数据过程中采用分块传输。

【Nginx】图片不完整,竟然是Nginx的锅!!
image-20220313172546623

3.根据分块传输原理,搜索到一些资料,增大缓冲可以解决问题。

客户端(PC浏览器或者手机浏览器)在接受到Nginx代理响应的时候,头信息通常都会带上Content-Length,一般情况下客户端会在接受完Content-Length长度的数据之后才会开始解析。而在Nginx代理上,页面处理过程中会将数据都放在缓存中,然后一次性的返回给客户端。

另外一种情况就是头信息中不存在Content-Length ,取而代之的是Tansfer-Encoding:chunked ,这个头信息的的意思是response的内容会被Nginx代理分成一块一块的发送,客户端也就不需要等到内容都传输完毕了才解析其中的内容。因为这个时候被传送的数据长度是无法预计的,所以存在Tansfer-Encoding:chunked的话也没有存在Content-Length 的意义了。

Nginx代理服务器测试后配置进行如下修改后可以完整传输

# 代理互联网地址
location /acore {
client_max_body_size    150m;
client_body_buffer_size 128k;
proxy_connect_timeout   130;
proxy_send_timeout      300;
proxy_read_timeout      1800;

# 默认开启
# proxy_buffering on;

# 以下配置以proxy_buffers配置为中心适配的缓冲大小策略,因为nginx对缓存值相互制约,
# 从proxy_buffers设置思路比较清晰,当然也可以针对不同情况选择不同的配置项为主作为开端突破口。
# 以下配置在包资源1.7m并小于proxy_buffers 2M的话是可以正常运行的
# 可以设置很小 该指令设置缓冲区大小,从代理后端服务器取得的第一部分的响应内容,会放到这里.小的响应header通常位于这部分响应内容里边.
# 默认来说,该缓冲区大小等于指令 proxy_buffers所设置的一个块区大小;可以把它设置得更小。
# 但是最大值不能超过 proxy_buffers 减一个缓冲区的大小 3X500k (1500k)
# proxy_buffer_size  128k;

# 该指令设置缓冲区的数量(最少2)和大小,从被代理的后端服务器取得的响应内容,会放置到这里. 默认情况下,一个缓冲区的大小等于内存页面大小,可能是4K也可能是8K,这取决于平台、
#数据响应包不能大于proxy_buffers总值(在不支持分块传输条件下)如果超过需要增大proxy_buffers
proxy_buffers 4 512k;

# 默认值:proxy_buffer_size * 2; (官方文档是这样的,但是如果我proxy_buffer_size不按照推荐来设置 ,proxy_buffer_size * 2没有满足此项的最小值是不能使用的)
# 此选项最小值要大于或者等于 128k(proxy_buffer_size 128k)和512k(proxy_buffers的一个区512k)的最大值 512k
# 此选项最大值小于等于proxy_buffers 减一个缓冲区的大小 3X512K(1536k)
# proxy_busy_buffers_size 512k;

# 同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。
# 如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。
# proxy_temp_file_write_size 4m;

# proxy_redirect http:// https://;
proxy_pass http://xxx.xxx.xxx/core/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header x-agent $http_user_agent;
proxy_set_header X-Forwarded-scheme $scheme;
}

分析后真正起到作用的是

proxy_buffers 4 512k;

只要缓冲总大小4*512k=2048k大于图片大小,图片就可以完整下载。

一波三折

问题看似解决,实际上其他问题又来了,问题就是之前的缓冲大小不足的时候,某信通道异常,某0通道却是正常的,这又是怎么回事?

我们已经确定问题出在某信通道的Nginx代理上面,查看Nginx代理报错信息,信息如下:

2022/03/13 17:06:10 [crit] 92638#0: *26924337 open() "/usr/local/nginx/proxy_temp/9/40/0000005409" failed (13: Permission denied) while reading upstream, client: 0.0.0.0, server: 8.8.8.8, request: "GET /acore/download.shtml?p=image&f=pdf/img/190618new.jpg HTTP/1.1", upstream: "http://1.1.1.1:80/core//download.shtml?p=image&f=pdf/img/190618new.jpg", host: "8.8.8.8"

直接在后台服务器上用后台服务器的IP地址去访问,发现速度相当快,于是怀疑是Nginx的配置问题。

注意:当下载大的附件,或是页面中有大图片时,就会下载中断或是图片无法显示,也许你会说我用的Nginx缺省的配置也从来没有碰到过这种问题呀!我想说的是:那是因为你的网站没有大文件,至少没有大到使用Nginx的默认配置加载不出来。

诚如之前所说,问题就出在proxy_buffers上,当服务器上的文件超过该参数设置的大小时,Nginx会先将文件写入临时目录(缺省为Nginx安装目下/proxy_temp目录),缺省Nginx是以nobody身份启动的,用ls -al 命令查看proxy_temp目录,nobody是proxy_temp目录的所有者,接下来查看proxy_temp的父目录即Nginx安装目录,发现nobody没权限。

问题解决

可以使用两种方式解决这个问题,如下所示。

设置任何人都可以写proxy_temp目录,重启Nginx即可解决。直接更改proxy_buffers的值,将其修改为大于图片和文件的大小,重启Nginx。

如果是以第一种方式解决问题的话,比如proxy_temp目录是/usr/local/nginx/proxy_temp,用如下命令将/usr/local/nginx/proxy_temp目录设置为任何人都可以写,问题解决。

chmod -R 777 /usr/local/nginx/proxy_temp/

如果问题还存在,那就用如下命令将/usr/local/nginx/目录设置为任何人都可以执行,问题解决。

chmod -R 755 /usr/local/nginx/

如果是使用第二种方式解决问题的话,就可以直接修改nginx.conf文件,如下所示。

# 代理互联网地址
location /acore {
client_max_body_size    150m;
client_body_buffer_size 128k;
proxy_connect_timeout   130;
proxy_send_timeout      300;
proxy_read_timeout      1800;

# 默认开启
# proxy_buffering on;

# 以下配置以proxy_buffers配置为中心适配的缓冲大小策略,因为nginx对缓存值相互制约,
# 从proxy_buffers设置思路比较清晰,当然也可以针对不同情况选择不同的配置项为主作为开端突破口。
# 以下配置在包资源1.7m并小于proxy_buffers 2M的话是可以正常运行的
# 可以设置很小 该指令设置缓冲区大小,从代理后端服务器取得的第一部分的响应内容,会放到这里.小的响应header通常位于这部分响应内容里边.
# 默认来说,该缓冲区大小等于指令 proxy_buffers所设置的一个块区大小;可以把它设置得更小。
# 但是最大值不能超过 proxy_buffers 减一个缓冲区的大小 3X500k (1500k)
# proxy_buffer_size  128k;

# 该指令设置缓冲区的数量(最少2)和大小,从被代理的后端服务器取得的响应内容,会放置到这里. 默认情况下,一个缓冲区的大小等于内存页面大小,可能是4K也可能是8K,这取决于平台、
#数据响应包不能大于proxy_buffers总值(在不支持分块传输条件下)如果超过需要增大proxy_buffers
proxy_buffers 4 512k;

# 默认值:proxy_buffer_size * 2; (官方文档是这样的,但是如果我proxy_buffer_size不按照推荐来设置 ,proxy_buffer_size * 2没有满足此项的最小值是不能使用的)
# 此选项最小值要大于或者等于 128k(proxy_buffer_size 128k)和512k(proxy_buffers的一个区512k)的最大值 512k
# 此选项最大值小于等于proxy_buffers 减一个缓冲区的大小 3X512K(1536k)
# proxy_busy_buffers_size 512k;

# 同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。
# 如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。
# proxy_temp_file_write_size 4m;

# proxy_redirect http:// https://;
proxy_pass http://xxx.xxx.xxx/core/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header x-agent $http_user_agent;
proxy_set_header X-Forwarded-scheme $scheme;
}

写在最后

问题原因已经很明确了,图片传输过程中,采用分块传输,缓冲区大小不足,导致文件下载不完整。由于某信通道和某0通道代理服务器配置存在差异,导致某信异常,某0正常,配置修改后,给定/usr/local/nginx/执行权限后,两个通道均正常。

配置差异如下:

【Nginx】图片不完整,竟然是Nginx的锅!!


原文始发于微信公众号(利刃信安):【Nginx】图片不完整,竟然是Nginx的锅!!

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月13日23:19:47
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【Nginx】图片不完整,竟然是Nginx的锅!!https://cn-sec.com/archives/827935.html

发表评论

匿名网友 填写信息