Tom*_*ing 5 python apache django mod-rewrite
我在端口8000上运行Django,在80上运行Apache.我在apache中配置了以下重写规则以重定向到django:
RewriteRule ^/?checkout/ http://%{HTTP_HOST}:8000/checkout/ [L,QSA]
Run Code Online (Sandbox Code Playgroud)
如果在浏览器中打开网址,它可以正常工作并完美重定向.
但是,外部客户端(在没有apache的情况下直接连接到django时效果很好)总是会在Django服务器上导致错误的请求语法错误.来自Django Log的Heres片段.看起来Apache会自动将这些"Content-length"内容附加到查询中,为什么?
[05/Mar/2014 18:01:35] code 400, message Bad request syntax ('GET /checkout/wx_signature?signature=b226bb8f6e9ce2fdecb752c6808a979c62e235f7&echostr=5987526888415258224×tamp=1394042480&nonce=1394079741Content-Length: 445Connection: closeContent-Type: text/html; charset=iso-8859-1 HTTP/1.0')
Run Code Online (Sandbox Code Playgroud)
tl; dr:这是由"外部客户端"中的错误引起的.它是一个设计糟糕的HTTP客户端,应该避免,因为它不仅会导致此错误,还可能为安全漏洞开辟道路.
为了理解正在发生的事情,您需要向后工作.
首先,让我们从Django内置服务器的日志行开始:
[05/Mar/2014 18:01:35] code 400, message Bad request syntax ('GET /checkout/wx_signature?signature=b226bb8f6e9ce2fdecb752c6808a979c62e235f7&echostr=5987526888415258224×tamp=1394042480&nonce=1394079741Content-Length: 445Connection: closeContent-Type: text/html; charset=iso-8859-1 HTTP/1.0')
Run Code Online (Sandbox Code Playgroud)
"代码400"指的是HTTP状态代码400这意味着实际的HTTP请求被严重构造,并且不能被理解.幸运的是,Django记录了错误的输入,因此我们可以对其进行分析.
现在我们了解了问题的本质,我们将删除不相关的日志绒毛和长签名,以深入了解实际请求:
GET /checkout/wx_signature?[SIGNATURE REMOVED]Content-Length: 445Connection: closeContent-Type: text/html; charset=iso-8859-1 HTTP/1.0
Run Code Online (Sandbox Code Playgroud)
在这里,我们看到HTTP请求的第一行无效.
来自RFC2616第5.1节:
Request-Line以方法标记开头,后跟Request-URI和协议版本,以CRLF结尾.元素由SP字符分隔.除最终的CRLF序列外,不允许使用CR或LF.
Run Code Online (Sandbox Code Playgroud)Request-Line = Method SP Request-URI SP HTTP-Version CRLF
在无效请求中,我们可以识别HTTP动词GET是否存在且版本结尾HTTP/1.0是否存在,因此这些不是问题.中间部分,应该是URL如下:
/checkout/wx_signature?[SIGNATURE REMOVED]Content-Length: 445Connection: closeContent-Type: text/html; charset=iso-8859-1
Run Code Online (Sandbox Code Playgroud)
URL中的空格通常在发送到服务器之前+或%20之前被替换.如您所见,这不是这种情况,它是无效请求的原因.一个好的HTTP客户端永远不会这样做,因为它会自动转义URL.这是一个红旗,您使用的"外部客户"质量很差.
请注意,空间旁边出现了许多看起来很奇怪的字段.
如果你看一下RFC2616第14.13节,你会发现它Content-Length实际上是HTTP 1.1标头的名称.这也是的情况下Connection,和Content-Type.
它显然不属于那里,为什么它与URL连接?
从这里我只能猜测,因为我无法访问您的代码.但是,我想我对发生的事情非常了解.
让我们暂时了解HTTP标头的本质.如果我们访问" http://google.com ",我们会发送原始请求来模拟会发生什么.这将触发Google将我们重定向到" http://www.google.com ".
原始请求:
GET / HTTP/1.1
Host: google.com
Run Code Online (Sandbox Code Playgroud)
原始响应:
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
Date: Thu, 15 May 2014 21:28:46 GMT
Expires: Sat, 14 Jun 2014 21:28:46 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 219
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alternate-Protocol: 80:quic
[HTML content removed]
Run Code Online (Sandbox Code Playgroud)
哇,谷歌回复了一大堆标题!我们只关注前几行:
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
...
Content-Length: 219
Run Code Online (Sandbox Code Playgroud)
在这里,你可以看到Content-Type,Content-Length和其它标题跟随Location头.实际的顺序无关紧要,因为HTTP客户端或服务器足够聪明,可以理解每个客户端或服务器的含义.但是,如果在Location标题后删除行结尾怎么办?
你最终会得到这样的东西:
HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/Content-Type: text/html; charset=UTF-8Content-Length: 219
Run Code Online (Sandbox Code Playgroud)
呃哦...如果你是一个HTTP客户端,你会认为我想重定向你http://www.google.com/Content-Type: text/html; charset=UTF-8Content-Length: 219.
这看起来就像你的症状......但为什么会这样呢?
Apache以这种损坏的形式返回标头是非常不可能的(除非你自定义编码插件或其他东西).
收到后,你的"外部客户" 也不太可能故意剥夺标题中的行结尾.
一个可能的情况是,"外部客户端"被编码为解释内容之前的所有内容以及之后的Location:URL以及之后的某个地方剥离CRLF字符(通常在处理HTTP标头时出于安全原因,在这种情况下讽刺地做错了) .客户端尝试使用HTTP/1.0而不是HTTP/1.1发送请求的事实支持这一点,因为HTTP/1.0客户端在功能方面通常非常有限,并且倾向于根据其过时的知识做出重大假设.
您的"外部客户端" 也可能在请求行之后将整个标头读入字符串,并且字符串处理程序会自动删除CRLF.
我认为很明显,问题在于"外部客户端",尽管没有足够的信息可以深入研究.
我建议您使用不同的客户端或库来执行请求.
当您在 Django 中使用 HTTPS url时,似乎会出现此消息。您可能还需要在 Apache2 中配置 HTTPS 配置,灵感来自于这个问题,例如:SSL based virtual host with django and mod_wsgi
| 归档时间: |
|
| 查看次数: |
2645 次 |
| 最近记录: |