在尝试提供mod-rewrite redirect but prevent direct access的答案时,我正在做一些测试。
原始问题目标基本上是
example.com/public/foo
example.com/foo
,同时禁止访问真实网址example.com/public/foo
。
我找到一个可能的解决方案,将令牌附加到重写的URL的查询字符串中,
RewriteCond %{REQUEST_URI} !/public/
RewriteRule ^(.*)$ /public/$1?token=SECRET_TOKEN [L]
RewriteCond %{REQUEST_URI} /public/
RewriteCond %{QUERY_STRING} !token=SECRET_TOKEN
RewriteRule ^(.*)$ / [R=403,L]
我意识到(使用Chrome的DevTools)我真的无法在请求标题中看到此标记。
我理解这是因为第一个RewriteRule
没有触发客户端上的重定向,所有这些重写过程都发生在服务器中。
如果我是对的,这SECRET_TOKEN
是安全的,不是吗? (安全,我的意思是客户无法以任何方式知道)
答案 0 :(得分:2)
通常,客户端永远不会看到SECRET_TOKEN
- 如您所说,重写是服务器内部的。
但是,SECRET_TOKEN
可能会在某些条件下暴露,具体取决于服务器配置。
例如,使用您发布的代码,SECRET_TOKEN
可以通过请求example.com/public
或example.com/subdir
(其中subdir
是/public
内的子目录来公开/public
}) - 注意遗漏斜杠。
example.com/public - 如果您要请求RewriteRule
(没有尾部斜杠),则mod_dir通过附加一个尾部斜杠来“纠正”这个,这是通过301外部重定向。但是,重定向不会立即发生,并且您的REQUEST_URI
指令最终会重写此请求(因为此时/public
变量仍然是/public/?token=SECRET_TOKEN
- 没有尾随斜杠)到{{1} (注意目录上的尾部斜杠)。 (由于某些原因,RewriteRule
似乎没有更新URL路径,因为您可能会认为这是/public/public
,但是,查询字符串仍然被追加。可能与mod_dir发出的子请求?不确定原因?)由于mod_dir已经触发了301,因此该响应(包含SECRET_TOKEN
)现在作为外部重定向发送回用户<{1}}已曝光。
example.com/subdir - 如果存在子目录SECRET_TOKEN
并且您请求/public/subdir
(没有尾随),则会发生类似(但略有不同)的事情削减)。您的/subdir
指令首次启动,并在内部将请求重写为RewriteRule
。好到目前为止。但是然后mod_dir启动并希望在/public/subdir?token=SECRET_TOKEN
附加一个尾部斜杠 - 它使用外部301重定向执行此操作。因此,请求现在重定向到/public/subdir
,/public/subdir/?token=SECRET_TOKEN
向用户(以及之前未知的SECRET_TOKEN
子目录公开)。< / p>
但是,以这种方式使用查询字符串确实有一些其他注意事项:
目前,您正在覆盖请求中的任何其他查询字符串。
要合并请求中的现有查询字符串,您需要在/public
上指定QSA
标记。但是,如果用户随后在请求中附加了RewriteRule
,那么如果您想在PHP脚本中使用?token=
超全局读取它,那么他们将覆盖您的token
URL参数。您可以通过在替换中明确包含$_GET
服务器变量而不是使用QSA标志来手动更改查询字符串参数的顺序 - 但这有点混乱(例如,什么如果没有查询字符串?)。