【问题标题】:Deny direct access to files or directory using .htaccess拒绝使用 .htaccess 直接访问文件或目录
【发布时间】:2011-04-17 00:14:23
【问题描述】:

我正在使用.htaccess,我想知道是否可以在根目录中仅使用 .htaccess 来阻止来自浏览器的所有针对现有文件或目录的请求。

让我们试试这个例子:

RewriteEngine On

RewriteBase /~my_user/my_base/

RewriteRule ^list/$ list.php [L]
RewriteRule ^element_of_list/([a-zA-Z0-9\-]+)/$ element.php?elem_id=$1 [L]

现在,如果我写http://127.0.0.1/~my_user/my_base/list/,这很好,但如果我写http://127.0.0.1/~my_user/my_base/list.php,它仍然有效。我不想要那个。我希望用户在最后一种情况下获得 404 错误。

我们有 /etc/apache2/mods-enabled/userdir.conf

<IfModule mod_userdir.c>
        UserDir public_html
        UserDir disabled root

        <Directory /home/*/public_html>
                AllowOverride All
                Options Indexes FollowSymLinks
                <Limit GET POST OPTIONS>
                        Order allow,deny
                        Allow from all
                </Limit>
                <LimitExcept GET POST OPTIONS>
                        Order deny,allow
                        Deny from all
                </LimitExcept>
        </Directory>
</IfModule>

我的第一次尝试是使用RewriteCond:

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*)$ 404.php [L]

但它不起作用。每个请求最终都会重定向到 404.php

更新

所以我设法为目录创建了过滤器:

RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !^/~my_user/my_base/$ [NC]
RewriteRule ^(.*)$ 404.php [L]

它的作用是检查请求的路径(REQUEST_FILENAME)是否存在并且它是一个目录AND如果它不是我的RewriteBase基本上是index.php,然后重定向到404.php

我仍在尝试找到对文件执行相同操作的方法。我知道我可以有选择地使用扩展文件名来做到这一点,但我想要一个文件的通用过滤器。

【问题讨论】:

    标签: .htaccess mod-rewrite apache2


    【解决方案1】:

    如果我正确理解了您的要求,那么您正在寻求执行以下操作:

    # This is a real directory...
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    # Or it's a real file...
    RewriteCond %{REQUEST_FILENAME} -d
    # And it's not 404.php...
    RewriteCond $0 !=404.php
    # And it's not the root
    RewriteCond $0 !=""
    # And it's not any of the above due to an internal redirect...
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    # So cause a 404 response (you could redirect to 404.php if you want)
    RewriteRule ^.*$ - [R=404,L]
    
    # Set the 404 error document
    ErrorDocument 404 /~my_user/my_base/404.php
    

    请记住,这会阻止所有存在的,因此任何图像、样式表或脚本也会被发送到 404 页面。如果您只想阻止访问 PHP 文件,Gumbo's solution 更合适。我认为在这种情况下,您需要另一个 RewriteCond 来防止循环:

    # Make sure the reason this request has a .php is because it was requested
    # by the user (and not due to a redirect)
    RewriteCond %{THE_REQUEST} ^[A-Z]+\s/[^\s]+\.php
    # Make sure we aren't on 404.php already
    RewriteRule %{REQUEST_URI} !404\.php$
    # We aren't, so redirect to 404.php
    RewriteRule ^ 404.php [L]
    

    【讨论】:

    • 是的,我想阻止一切,但只是出于好奇。你能解释一下$0 的用法吗?它是否包含${REQUEST_FILENAME}?而你链接了 5 RewriteCond,apache 怎么理解你需要用前两个的结果来对抗后三个?它是否只是在一切之前评估前两个(按出现顺序)?
    • @dierre:$0 是对RewriteRule 测试模式的反向引用(它包含来自^.*$ 的整个匹配项)。有可能将这两个RewriteCond 压缩成RewriteRule 的测试模式,我想,就像!^(|404\.php)$。至于链接,有一个隐含的AND 将所有RewriteCond 连接在一起,除非您指定[OR] 标志。
    • 与此相关,mod_rewrite 首先处理RewriteRule 的测试模式,然后测试附加到当前规则(正上方)的每个RewriteCond,从顶部开始向下工作。如果所有这些都通过了,那么它将在 RewriteRule 中执行替换。
    • 我在想,你在ErrorDocument 中使用RewriteBase 的完整路径,有没有包含RewriteBase 值的env:variable?
    • @dierre:我不知道。据我所知,也没有任何方法可以让ErrorDocument 使用相对于当前目录的文件。在这种情况下,直接重定向到 404.php 可能会更好,就像第二个示例中的 RewriteRule 一样,因为这样您就不需要再次编写整个路径。在这种情况下,请确保 404.php 返回 404 状态标头。
    【解决方案2】:

    试试这个规则:

    RewriteCond %{THE_REQUEST} ^[A-Z]+\ /[^?\ ]*\.php[/?\ ]
    RewriteRule .*\.php$ 404.php [L]
    

    这会将路径内部包含.php 的所有请求重写为404.php。

    【讨论】:

    • 没关系,但是目录呢?是否可以在不使用 php 文件检查它们的情况下做到这一点? -d 标志很奇怪。我想我没听懂。
    • 其实,为什么需要 RewriteCond? RewriteRule 呢 ^(.*)\.php$ 404.php [L]
    猜你喜欢
    • 2014-05-11
    • 1970-01-01
    • 2017-03-17
    • 2015-01-26
    • 2012-08-02
    • 1970-01-01
    • 2016-03-12
    • 2016-10-18
    • 2012-03-06
    相关资源
    最近更新 更多