php - Facebook 爬虫严重攻击我的服务器并忽略指令。多次访问同一个资源

标签 php facebook facebook-graph-api web-crawler

Facebook 爬虫每秒多次访问我的服务器,它似乎同时忽略了 Expires header 和 og:ttl 属性。

在某些情况下,它会在 1-5 分钟内多次访问同一个 og:image 资源。在一个示例中 - 爬虫在 3 分钟内使用 12 个不同的 IP 地址访问了同一张图像 12 次。

在捕获以下示例之前,我只需要记录请求 10 分钟:

一张图片的时间列表和爬虫IP地址:

2018-03-30 15:12:58 - 66.220.156.145
2018-03-30 15:13:13 - 66.220.152.7
2018-03-30 15:12:59 - 66.220.152.100
2018-03-30 15:12:18 - 66.220.155.248
2018-03-30 15:12:59 - 173.252.124.29
2018-03-30 15:12:15 - 173.252.114.118
2018-03-30 15:12:42 - 173.252.85.205
2018-03-30 15:13:01 - 173.252.84.117
2018-03-30 15:12:40 - 66.220.148.100
2018-03-30 15:13:10 - 66.220.148.169
2018-03-30 15:15:16 - 173.252.99.50
2018-03-30 15:14:50 - 69.171.225.134

根据 Facebook's documentation 的 og:image 是什么:

The URL of the image that appears when someone shares the content to Facebook. See below for more info, and check out our best practices guide to learn how to specify a high quality preview image.

我在 og:image 中使用的图像的 Expires header 设置为 future +7 天。最近,我将其更改为 future +1 年。这两种设置似乎都没有任何区别。爬虫似乎忽略的 header :

Cache-Control: max-age=604800
Content-Length: 31048
Content-Type: image/jpeg
Date: Fri, 30 Mar 2018 15:56:47 GMT
Expires: Sat, 30 Mar 2019 15:56:47 GMT
Pragma: public
Server: nginx/1.4.6 (Ubuntu)
Transfer-Encoding: chunked
X-Powered-By: PHP/5.5.9-1ubuntu4.23

根据 Facebook 的 Object Properties documentation , og:ttl 属性是:

Seconds until this page should be re-scraped. Use this to rate limit the Facebook content crawlers. The minimum allowed value is 345600 seconds (4 days); if you set a lower value, the minimum will be used. If you do not include this tag, the ttl will be computed from the "Expires" header returned by your web server, otherwise it will default to 7 days.

我已将此 og:ttl 属性设置为 2419200,即 future 28 天。

我一直想使用这样的东西:

header("HTTP/1.1 304 Not Modified"); 
exit;

但我担心 Facebook 的爬虫会忽略标题并将图像标记为已损坏 - 从而从共享故事中删除图像预览。

A video showing the rate 来自 Crawler 的这些请求正在进入。

有没有办法防止爬虫这么快回来攻击这些资源?

显示我的开放图和元属性的示例代码:

<meta property="fb:app_id" content="MyAppId" />
<meta property="og:locale" content="en_GB" />
<meta property="og:type" content="website" />
<meta property="og:title" content="My title" />
<meta property="og:description" content="My description" />
<meta property="og:url" content="http://example.com/index.php?id=1234" />
<link rel="canonical" href="http://example.com/index.php?id=1234" />
<meta property="og:site_name" content="My Site Name" />
<meta property="og:image" content="http://fb.example.com/img/image.php?id=123790824792439jikfio09248384790283940829044" />
<meta property="og:image:width" content="940"/>
<meta property="og:image:height" content="491"/>
<meta property="og:ttl" content="2419200" />

最佳答案

在我尝试了缓存、 header 等几乎所有其他方法之后,唯一让我们的服务器免于“过度热情”的 Facebook 爬虫 (用户代理 facebookexternalhit) 只是拒绝访问并发回 HTTP/1.1 429 Too Many Requests HTTP 响应,当爬虫“抓取太多”时。

诚然,我们有数千张图片需要爬虫抓取,但 Facebook 爬虫实际上对我们的服务器进行了 DDOS 攻击,请求数以万计(是的,一遍又一遍地使用相同的 URL ),每小时。我记得当时使用 facebookexternalhit 用户代理的不同 Facebook IP 地址每小时 40 000 个请求

我们不想完全阻止爬虫,通过 IP 地址阻止也不是一种选择。 我们只需要 FB 爬虫(相当)后退一点。

这是我们用来做的一段PHP代码:

.../images/index.php

<?php

// Number of requests permitted for facebook crawler per second.
const FACEBOOK_REQUEST_THROTTLE = 5;
const FACEBOOK_REQUESTS_JAR = __DIR__ . '/.fb_requests';
const FACEBOOK_REQUESTS_LOCK = __DIR__ . '/.fb_requests.lock';

function handle_lock($lockfile) {
    flock(fopen($lockfile, 'w'), LOCK_EX);
}

$ua = $_SERVER['HTTP_USER_AGENT'] ?? false;
if ($ua && strpos($ua, 'facebookexternalhit') !== false) {

    handle_lock(FACEBOOK_REQUESTS_LOCK);

    $jar = @file(FACEBOOK_REQUESTS_JAR);
    $currentTime = time();
    $timestamp = $jar[0] ?? time();
    $count = $jar[1] ?? 0;

    if ($timestamp == $currentTime) {
        $count++;
    } else {
        $count = 0;
    }

    file_put_contents(FACEBOOK_REQUESTS_JAR, "$currentTime\n$count");

    if ($count >= FACEBOOK_REQUEST_THROTTLE) {
        header("HTTP/1.1 429 Too Many Requests", true, 429);
        header("Retry-After: 60");
        die;
    }

}

// Everything under this comment happens only if the request is "legit". 

$filePath = $_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI'];
if (is_readable($filePath)) {
    header("Content-Type: image/png");
    readfile($filePath);
}

您还需要配置重写以将针对您的图像的所有请求传递给此 PHP 脚本:

.../images/.htaccess (如果您使用的是 Apache)

RewriteEngine On
RewriteRule .* index.php [L] 

看起来爬虫“理解这种”方法并且有效地将尝试率从每小时数万请求降低到>每小时数百/数千请求。

关于php - Facebook 爬虫严重攻击我的服务器并忽略指令。多次访问同一个资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49577546/

相关文章:

php - 如何在 Windows XP 上安装适用于 php 5.3.5 的 openssl?

php - 尝试在 Mac 上设置 Selenium + Behat

Android:在 Webview 中加载 facebook 页面

facebook - 无需登录即可获取访问 token | Facebook `

javascript - 如何解决不停止加载的 Facebook 请求对话框的问题?

jquery - Facebook 对于电子邮件和生日返回未定义

php - 提前一周从数据库中获取事件

php - 一个父行,另一个表中的多个子行。如何将它们全部排成一排?

javascript - FB JavaScript SDK : What's the point of the signed_request?

iOS Facebook 访问 token 获取用户墙订阅源(状态)