Django:从Apache mod_rewri重定向时请求语法错误

2024-06-15 16:04:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我有Django在端口8000上运行,Apache在80端口上运行。我在apache中配置了以下重写规则以重定向到django:

RewriteRule ^/?checkout/ http://%{HTTP_HOST}:8000/checkout/ [L,QSA]

如果在浏览器中打开一个url,它可以很好地工作并完美地重定向。在

但是,外部客户机(在没有apache的情况下直接连接到django时工作良好)总是导致django服务器上出现错误的请求语法错误。这是Django日志中的片段。看起来Apache会自动将那些“内容长度”的内容附加到查询中,为什么?在

^{pr2}$

Tags: django端口httphost内容规则apache浏览器
2条回答

dr:这是由“外部客户机”中的一个错误引起的。它是一个设计糟糕的HTTP客户机,应该避免,因为它不仅会导致此错误,还可能为安全漏洞利用开辟途径。在

为了了解发生了什么,你需要反向工作。在


首先,让我们从Django内置服务器的日志行开始:

[05/Mar/2014 18:01:35] code 400, message Bad request syntax ('GET /checkout/wx_signature?signature=b226bb8f6e9ce2fdecb752c6808a979c62e235f7&echostr=5987526888415258224&timestamp=1394042480&nonce=1394079741Content-Length: 445Connection: closeContent-Type: text/html; charset=iso-8859-1 HTTP/1.0')

“代码400”是指HTTP状态代码400。这意味着实际的HTTP request结构不好,无法理解。幸运的是,Django记录了错误的输入,这样我们就可以分析它了。在


既然我们了解了问题的本质,我们将删除不相关的日志绒毛和长签名,以便更深入地了解实际请求:

^{2}$

这里我们看到一个无效的HTTP请求的第一行。在


RFC2616 Section 5.1

The Request-Line begins with a method token, followed by the Request-URI and the protocol version, and ending with CRLF. The elements are separated by SP characters. No CR or LF is allowed except in the final CRLF sequence.

   Request-Line   = Method SP Request-URI SP HTTP-Version CRLF

在无效请求中,我们可以确定HTTP动词GET在那里,而{}的版本结尾在那里,所以这些不是问题所在。中间部分,即URL,如下所示:

/checkout/wx_signature?[SIGNATURE REMOVED]Content-Length: 445Connection: closeContent-Type: text/html; charset=iso-8859-1

在发送到服务器之前,URL中的空格通常被+或{}替换。如您所见,这里不是这种情况,这是无效请求的原因。一个好的HTTP客户机永远不会这样做,因为它会自动转义URL。这是一个危险信号,表明您使用的“外部客户”质量低劣。


注意,这个空间出现在一些看起来很奇怪的区域旁边。在

如果您查看RFC2616 Section 14.13,您将看到Content-Length实际上是HTTP1.1头的名称。这也是Connection,和Content-Type的情况。在

它显然不属于那里,那么为什么它与URL连接?在

从这里我只能猜测,因为我不能访问你的代码。不过,我想我对发生的事情有一个很好的了解。在


让我们先了解一下HTTP头的性质。我们将发送一个原始请求来模拟访问“http://google.com”时发生的情况。这将触发Google将我们重定向到“http://www.google.com”。在

原始请求

GET / HTTP/1.1
Host: google.com

原始响应

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]

哇,谷歌返回了一大堆标题!我们只对前几行感兴趣:

HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/
Content-Type: text/html; charset=UTF-8
...
Content-Length: 219

在这里您可以看到Content-TypeContent-Length,以及其他头文件都跟在Location头之后。实际的顺序通常并不重要,因为HTTP客户机或服务器足够智能,能够理解每一个客户机或服务器的含义。但是,如果去掉Location头之后的行尾怎么办?在

你最终会得到这样的结果:

HTTP/1.1 301 Moved Permanently
Location: http://www.google.com/Content-Type: text/html; charset=UTF-8Content-Length: 219

哦哦。。。如果您是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。在


我认为很明显问题出在“外部客户”身上,尽管没有足够的信息来挖掘它。在

我建议您使用不同的客户机或库来完成请求。在

此消息似乎出现在you are using HTTPS url with Django时。您可能还需要在Apache2中配置一个HTTPS配置,这个配置的灵感来自于这个问题,例如:SSL based virtual host with django and mod_wsgi

相关问题 更多 >