我有以下网址:
example.com/?redirect=some-url-encoded
我需要将其重定向到查询字符串(redirect
参数)中指定的 URL。
我努力了:
RewriteCond %{QUERY_STRING} redirect=(.+)
RewriteRule ^(.*)$ %1 [R=302,L,QSA]
但我被重定向到以下 URL:
example.com/some-url-encoded?redirect=some-url-decoded
所以:
- 我的 URL 未解码
- 应用了旧的查询字符串。
- URL 从 example.com 开始
该如何正确处理?
答案1
- 我的 URL 未解码
服务器QUERY_STRING
变量未经过 URL 解码,而 mod_rewrite 也会对替换进行 URL 编码,因此您最终可能会得到双重编码的 URL?您可能需要NE
( NOESCAPE
) 标志。
但是,如果冒号和斜线(如http://
)在查询字符串参数中经过 URL 编码(即http:%3A%2F%2F
),则这些字符将传递到已编码的替换中,从而否定它们在 URL 中的正常含义。虽然大多数 URL 编码函数都会对这些字符进行编码,但它们并不严格需要在 URL 参数值中进行编码(尽管这可能取决于您的服务器配置 - 如果您正在更改服务器认为的 URL 分隔符 - 但这种情况很少见)。因此,对 URL 参数值中的所有其他字符(和 除外)进行编码:
。/
例如,而不是:
example.com/?redirect=https%3A%2F%2Fwww.google.pl%2F
保持:
(冒号)和/
(斜线)字符未编码:
example.com/?redirect=https://www.google.pl/
PATH_INFO
另一种方法是在 URL 末尾使用 additional,而不是使用 URL 参数,因为这应该会自动进行 URL 解码。但是,这取决于AcceptPathInfo
指令,您还需要启用AllowEncodedSlashes
(在服务器配置中),但这会带来自身的安全问题。请参阅 Apache 文档:http://httpd.apache.org/docs/current/mod/core.html#allowencodedlashes
- 应用了旧的查询字符串。
您明确地告诉 mod_rewrite 使用 (Query String Append) 标志应用原始查询字符串QSA
。但它无论如何都会默认这样做。您需要使用QSD
Apache 2.4+ 上的 (Query String Discard) 标志明确删除它,或者将 a 附加?
到RewriteRule
替换中。
- URL 起始于
example.com
您需要http://
在 URL 参数中包含一个绝对 URL(即使用方案完成)(或者在替换中明确硬编码?)。请注意,如果冒号和/或斜线经过http://
URL 编码,则 Apache 将不会将其视为绝对 URL,它将被视为相对 URL(相对于当前目录),Apache 将在其上添加目录前缀,然后尝试将其设为绝对 URL(因为标志R
-外部的通过在协议和当前域前面加上前缀来实现重定向,即。http://example.com
这不仅会完全破坏重定向,还会暴露您的内部目录结构。
综合以上所有,尝试以下操作:
RewriteCond %{QUERY_STRING} redirect=(.+)
RewriteRule ^ %1? [R=302,L,NE]
这是假设协议/方案是传入查询字符串参数。例如http://example.com/?redirect=http://www.google.pl/
模式中的括号子模式RewriteRule
(即(.*)
)在这里似乎是不必要的。
关于安全
请注意,允许任何在像这样的简单重定向脚本中将绝对 URL 用作目标存在安全风险。如果黑客发现这一点,那么它很可能会被滥用并用作重定向链的一部分,引导用户下载恶意软件等。
答案2
您走错了路。使用 RewriteCond/RewriteRule 将路径(使用 QSA 保留查询字符串)重写为脚本(PHP 或某些 CGI,无论您喜欢什么),然后让该脚本体现逻辑和正确性约束以获得您想要的重定向。
这也提供了有用的启用功能。一些想法:
- 不区分大小写,不区分分隔符(此事物与此事物与……)
- 从数据库提供此类重定向
- 然后它可以有一个前端,供受信任的网站维护人员添加链接并允许某种生命周期维护。
- 您甚至可以使用编辑距离来帮助确定需要哪个文档(请参阅https://en.wikipedia.org/wiki/Levenshtein_distance)