.htaccess,防止热链接,允许大机器人,允许一些访问并允许我自己的域而不静态添加它

.htaccess, prevent hotlinking, allow big bots, allow some access and allow my own domain without adding it statically

  1. 我想允许几个不同的漫游器在我的网站上抓取图片并排除所有其他漫游器。
  2. 我想允许至少一个文件夹中的图像不会因任何请求而被阻止。
  3. 我不想在我自己的网站上阻止访问者的图像请求。
  4. 为了可移植性,我不想在 .htaccess 文件中包含我的域名。

我在这里问这个问题而不是自己简单地测试以下代码的原因是我自己工作,没有大学可以问,也没有外部资源可以测试。我认为我得到的是正确的,但我发现 .htaccess 规则非常混乱,我不知道我现在还不知道什么。

RewriteCond %{HTTP_REFERER} !^$ [OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?bing\..+$ [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?facebook\..+$ [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?google\..+$ [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?instagram\..+$ [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?linkedin\..+$ [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?reddit\..+$ [NC,OR]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?twitter\..+$ [NC,OR]
RewriteCond %{REQUEST_URI} !^/cross-origin-resources/  [NC,OR]
RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} !^([^@]*)@@https?:///.* [NC]
RewriteRule \.(bmp|gif|jpe?g|png|webp)$ - [F,L,NC]

我已经在 htaccess tester, and looks good but does complain about the second last line when tested using the following URL: http://www.example.co.uk/poignant/foo.webp

上测试过了

你的逻辑是相反的。如所写,这些条件(RewriteCond 指令)将始终成功并且请求将始终 被屏蔽了。

您有一系列否定的条件,它们是或运算的。如果所有条件都匹配,这些只会 fail (即 not 阻止请求),这是不可能的。 (例如 Referer header 不能是 bing facebook。)

您需要删除所有 RewriteCond 指令上的 OR 标志,因此它们隐式 AND'd.

顺便说一句,@StephenOstermiller 在评论中建议将 HTTP_REFERER 检查合并为一个(这是一个很好的检查)等同于拥有单独的条件 AND'd,而不是 OR'd(正如您最初发布的那样)。

  1. I want to allow image crawling on my site from a couple of different bots and exclude all others.

一旦您如上所述更正了 OR/AND,此规则可能会允许所有机器人 抓取 您的网站图片,因为机器人通常不会发送一个 Referer header。这些指令并不是真正关于“爬行”,它们允许某些网站在其域中显示您的图像(即热链接)。这可能是意图,但是,这不是您在第 1 点中所说的。

(要阻止机器人 抓取 您的网站,您需要检查 User-Agent 请求 header,即 HTTP_USER_AGENT -在单独的规则中可能会更好。)

RewriteCond %{HTTP_REFERER} !^https?://(www\.)?bing\..+$

次要点,但正则表达式末尾的 +$ 是多余的。如果您只对 hostname 感兴趣,则无需匹配整个 Referer。尽管这些站点可能有一个 Referrer-Policy 设置来防止 URL-path 在 Referer header 中被(浏览器)发送,但仍然没有必要。

RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} !^([^@]*)@@https?:///.* [NC]

在评论中,您问的是这一行的作用。这满足您列表中的第 3 点和第 4 点,因此肯定需要它。它确保请求的 Host header (HTTP_HOST) 与 Referer 中的 hostname 匹配。所以请求来自同一个站点。

另一种方法是在您试图避免的条件中对您的域进行硬编码。

(同样,正则表达式中的尾随 .* 是不必要的,应该删除。)

这是通过在 TestString(第一个争论)。 @@ 字符串只是一个任意字符串,不会出现在 HTTP_HOSTHTTP_REFERER 服务器变量中。

如果您展开 TestString 以查看匹配的内容,这会更清楚。例如,如果您从主页(即 https://example.com/)向 https://example.com/myimage.jpg 发出内部请求,那么 RewriteCond 指令中的 TestString 是:

example.com@@https://example.com/

然后将其与正则表达式 ^([^@]*)@@https?:/// 匹配(CondPattern 上的 ! 前缀是一个 operator 并且是参数的一部分,而不是正则表达式)。

  1. ([^@]*) - 第一个捕获组捕获 example.comHTTP_HOST 的值)。
  2. @@https?:// - 仅匹配 TestStringHTTP_REFERER 的一部分)中的 @@https://
  3. </code> - 这是一个内部反向引用。所以这必须匹配从第一个捕获组(上面的#1)捕获的值。在此示例中,它必须匹配 <code>example.com。确实如此,所以匹配成功。
  4. CondPattern 上的 ! 前缀(严格来说不是正则表达式的一部分)否定整个表达式,因此当正则表达式 匹配。

所以,在上面的例子中,正则表达式匹配,所以条件失败(因为它被否定),所以规则没有被触发,请求也没有被阻止。

但是,如果从外部站点向 https://example.com/myimage.jpg 发出请求,例如。 https://external-site.example/ 那么 RewriteCond 指令中的 TestString 是:

example.com@@https://external-site.example/

按照上面的步骤,正则表达式匹配失败(因为external-site.example不匹配example.com)。 negated 条件因此成功并触发规则,因此请求被阻止。 (除非其他条件之一失败。)

请注意,对于所写的条件,www.example.comexample.com 不同。例如,如果您使用 example.com 并且使用 www.example.com 对图像使用绝对 URL,则正则表达式将无法匹配并且请求将被阻止。这也许可以合并到正则表达式中,以允许这样做。但这在很大程度上是一种边缘情况,可以通过配置中较早的规范 301 重定向来避免。

RewriteCond %{HTTP_REFERER} !^$

这允许空(或不存在)Referer header。你“可能”确实需要这个。它允许机器人抓取您的图像。它允许直接请求图像。它还允许选择禁止 Referer header 的用户能够在您的 网站。

然而,现在网站也可以设置 Referrer-Policy 来完全抑制 Referer header 被发送(通过浏览器)等绕过你的热链接保护。

RewriteRule \.(bmp|gif|jpe?g|png|webp)$ - [F,L,NC]

次要点,但是当使用 F 标志时不需要 L 标志(这是隐含的)。

您真的提供 .bmp 图片吗?!

旁白: 网站不一定是“热链接”

其中一些外部网站(bing、Facebook、Google、Instagram、LinkedIn、Reddit、twitter 等)无论如何都不一定“热链接”图像。他们通常制作自己的 (resized/compressed) 图片“副本”(机器人发出检索图片的初始请求 - 没有 Referer - 因此请求未被阻止)。

因此,无论如何,在您的“hotlink-protection”脚本中明确允许其中一些站点可能是不必要的。

总结

考虑到以上几点,指令应该看起来更像这样:

RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?(bing|facebook|google|instagram|linkedin|reddit|twitter)\.
RewriteCond %{REQUEST_URI} !^/cross-origin-resources/  [NC]
RewriteCond %{HTTP_HOST}@@%{HTTP_REFERER} !^([^@]*)@@https?:///
RewriteRule \.(gif|jpe?g|png|webp|bmp)$ - [F,NC]