记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)

Posted 华天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)相关的知识,希望对你有一定的参考价值。

django+nginx+uwsgi部署的站点访问某个URL时发生了400 bad request的错误,而使用django自带的开发版的web server时没有遇到此问题。初步判断是nginx或uwsgi配置问题。

网上有说是因为request header过大而nginx配置的client_header_buffer_size和large_client_header_buffers过小引起的,但就当前的状态来看感觉不太可能。因为request header并不是特别大。至于是别的什么原因还暂未找到,所以还是先试试看。

在nginx配置文件nginx.conf中的http部分加入如下两行参数:
client_header_buffer_size 16k;
large_client_header_buffers 4 64k;
nginx默认会用client_header_buffer_size这个buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取header值。若该值设置过小而请求头/COOKIE过大则会报400 bad request错误。

调整参数重新载入配置文件重启uwsgi后发现问题并未解决。
经仔细查看才发现原来是请求的URL中参数包含了特殊字符%,导致Web Server没能够正确解析出该URL,才报了这个错误。

在URL中下列字符具有特殊含义:
符号 含义     如何转义
+     URL中+号表示空格                           %2B     
空格 URL中的空格可以用+号或者编码 %20   
/   分隔目录和子目录                                 %2F       
?     分隔实际的URL和参数                     %3F       
%     指定特殊字符                                    %25       
#     表示书签                                             %23       
&     URL中指定的参数间的分隔符        %26       
=     URL中指定参数的值                        %3D 

比如sever端从提交的表单的输入框中的值构造包含参数的URL,
若提交的内容为“pkgcr+awldb”,地址栏的URL显示为“xxx/?q=pkgcr%2Bawldb”,也即参数中q的值实际上为“pkgcr+awldb”
若提交的内容为“pkgcr awldb”,地址栏的URL显示为“xxx/?q=pkgcr+awldb”,也即参数中q的值实际上为“pkgcr awldb”
若提交的内容为“pkgcr/awldb”,地址栏的URL显示为“xxx/?q=pkgcr%2Fawldb”,也即参数中q的值实际上为“pkgcr/awldb”
若提交的内容为“pkgcr?awldb”,地址栏的URL显示为“xxx/?q=pkgcr%3Fawldb”,也即参数中q的值实际上为“pkgcr?awldb”
若提交的内容为“pkgcr%awldb”,地址栏的URL显示为“xxx/?q=pkgcr%25awldb”,也即参数中q的值实际上为“pkgcr%awldb”
若提交的内容为“pkgcr#awldb”,地址栏的URL显示为“xxx/?q=pkgcr%23awldb”,也即参数中q的值实际上为“pkgcr#awldb”
若提交的内容为“pkgcr&awldb”,地址栏的URL显示为“xxx/?q=pkgcr%26awldb”,也即参数中q的值实际上为“pkgcr&awldb”
若提交的内容为“pkgcr=awldb”,地址栏的URL显示为“xxx/?q=pkgcr%3Dawldb”,也即参数中q的值实际上为“pkgcr=awldb”

若要是直接在server端构造URL呢?比如server端的文件中有个变量ip,值为“172.142.%”,要在server端构造一个URL供客户端访问,如“href=?ip={ip}&q=‘mysql‘”(此处假定{ip}是对变量的一种引用方式),那么我们点击这个链接会是什么结果呢?

我们会看到,因为变量ip中包含特殊字符“%”,而“%”在URL中具有特殊含义,我们通过上述方式构造的URL相当于是“href=?ip=172.142.%&q=mysql”,web服务器解析该URL时无法解释%&从而导致出错。同样的原因,包含其他一些特殊字符时也会发生一些意想不到的问题,比如有另一个变量addr,值为“china&america”,构造的URL为“href=?addr={addr}&q=‘mysql’”,此时构建的URL相当于是“href=?addr=china&america&q=mysql”,web服务器会把该URL中的第一个“&”后的“america”解析为另外一个参数而不是将“china&america”整体作为“addr”参数的值。

那么如何在需要的时候在URL中包含诸如%、&、+、=等等这样的特殊的字符呢?答案就是用相应的编码代替特殊字符本身来构建URL。比如上例中可以先将ip的值替换为“172.142.%25”,将addr的值替换为“china%26america”,这样构建出的URL分别为“href=?ip=172.142.%25&q=mysql”和“href=?addr=china%26america&q=‘mysql’”,这样最终能够将URL中的参数ip的值成功解析为“172.142.%”而将addr的值成功解析为china&america,而且不会引起其他参数解析混乱。

最终,发现是在访问url的中文未进行转码导致的400错误。

ps: js中文转码(encodeURIComponent)

 

以上是关于记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)的主要内容,如果未能解决你的问题,请参考以下文章

记一次由tcp_tw_recycle参数引发的血案

git 填坑记录----记一次git低版本引发的问题

springboot中URL带有斜杠的转义字符百分之2F导致的400错误

URL 传参转义 (特殊符号转义)

url传值含有特殊符号会被转义,怎样保证所有特殊符号都被编码?

url路径中 符号是特殊字符吗