gpt4 book ai didi

php - 如何检测假用户(爬虫)和 cURL

转载 作者:IT王子 更新时间:2023-10-29 00:56:42 25 4
gpt4 key购买 nike

其他一些网站使用 cURL 和假 http 引用来复制我的网站内容。
我们有没有办法检测 cURL 或不是真正的网络浏览器?

最佳答案

没有什么神奇的解决方案可以避免自动爬行。人类能做的每一件事,机器人也能做到。只有使工作更难的解决方案,如此之难以至于只有技术娴熟的极客可能会试图通过它们。

几年前我也遇到了麻烦,我的第一个建议是,如果你有时间,自己做一个爬虫(我认为“爬虫”就是爬你的网站的人),这是该学科最好的学校。通过爬取几个网站,我学到了不同类型的保护,通过将它们关联起来,我变得高效。

我给你一些你可以尝试的保护例子。

每个 IP 的 session 数

如果用户每分钟使用 50 个新 session ,您可以认为该用户可能是一个不处理 cookie 的爬虫。当然,curl 完美地管理 cookie,但是如果您将它与每个 session 的访问计数器结合起来(稍后解释),或者如果您的爬虫是 cookie 问题的新手,它可能会很有效。

很难想象同一共享连接的 50 个人会同时访问您的网站(这当然取决于您的流量,这取决于您)。如果发生这种情况,您可以锁定网站页面,直到验证码填满为止。

主意 :

1)您创建了 2 个表:1 个用于保存禁止的 ip,1 个用于保存 ip 和 session

create table if not exists sessions_per_ip (
ip int unsigned,
session_id varchar(32),
creation timestamp default current_timestamp,
primary key(ip, session_id)
);

create table if not exists banned_ips (
ip int unsigned,
creation timestamp default current_timestamp,
primary key(ip)
);

2)在脚本的开头,您从两个表中删除了太旧的条目

3)接下来检查您的用户的IP是否被禁止(您将标志设置为true)

4)如果没有,你计算他的ip session 数

5)如果他有太多的 session ,你把它插入你的禁止表并设置一个标志

6)如果尚未插入,则在每个 ip 表的 session 中插入他的 ip

我写了一个代码示例,以更好的方式展示我的想法。
<?php

try
{

// Some configuration (small values for demo)
$max_sessions = 5; // 5 sessions/ip simultaneousely allowed
$check_duration = 30; // 30 secs max lifetime of an ip on the sessions_per_ip table
$lock_duration = 60; // time to lock your website for this ip if max_sessions is reached

// Mysql connection
require_once("config.php");
$dbh = new PDO("mysql:host={$host};dbname={$base}", $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Delete old entries in tables
$query = "delete from sessions_per_ip where timestampdiff(second, creation, now()) > {$check_duration}";
$dbh->exec($query);

$query = "delete from banned_ips where timestampdiff(second, creation, now()) > {$lock_duration}";
$dbh->exec($query);

// Get useful info attached to our user...
session_start();
$ip = ip2long($_SERVER['REMOTE_ADDR']);
$session_id = session_id();

// Check if IP is already banned
$banned = false;
$count = $dbh->query("select count(*) from banned_ips where ip = '{$ip}'")->fetchColumn();
if ($count > 0)
{
$banned = true;
}
else
{
// Count entries in our db for this ip
$query = "select count(*) from sessions_per_ip where ip = '{$ip}'";
$count = $dbh->query($query)->fetchColumn();
if ($count >= $max_sessions)
{
// Lock website for this ip
$query = "insert ignore into banned_ips ( ip ) values ( '{$ip}' )";
$dbh->exec($query);
$banned = true;
}

// Insert a new entry on our db if user's session is not already recorded
$query = "insert ignore into sessions_per_ip ( ip, session_id ) values ('{$ip}', '{$session_id}')";
$dbh->exec($query);
}

// At this point you have a $banned if your user is banned or not.
// The following code will allow us to test it...

// We do not display anything now because we'll play with sessions :
// to make the demo more readable I prefer going step by step like
// this.
ob_start();

// Displays your current sessions
echo "Your current sessions keys are : <br/>";
$query = "select session_id from sessions_per_ip where ip = '{$ip}'";
foreach ($dbh->query($query) as $row) {
echo "{$row['session_id']}<br/>";
}

// Display and handle a way to create new sessions
echo str_repeat('<br/>', 2);
echo '<a href="' . basename(__FILE__) . '?new=1">Create a new session / reload</a>';
if (isset($_GET['new']))
{
session_regenerate_id();
session_destroy();
header("Location: " . basename(__FILE__));
die();
}

// Display if you're banned or not
echo str_repeat('<br/>', 2);
if ($banned)
{
echo '<span style="color:red;">You are banned: wait 60secs to be unbanned... a captcha must be more friendly of course!</span>';
echo '<br/>';
echo '<img src="http://4.bp.blogspot.com/-PezlYVgEEvg/TadW2e4OyHI/AAAAAAAAAAg/QHZPVQcBNeg/s1600/feu-rouge.png" />';
}
else
{
echo '<span style="color:blue;">You are not banned!</span>';
echo '<br/>';
echo '<img src="http://identityspecialist.files.wordpress.com/2010/06/traffic_light_green.png" />';
}
ob_end_flush();
}
catch (PDOException $e)
{
/*echo*/ $e->getMessage();
}

?>

参观柜台

如果您的用户使用相同的 cookie 来抓取您的页面,您将能够使用他的 session 来阻止它。这个想法很简单:你的用户有可能在 60 秒内访问 60 个页面吗?

主意 :
  • 在用户 session 中创建一个数组,它将包含访问时间()s。
  • 删除此数组中超过 X 秒的访问
  • 为实际访问添加一个新条目
  • 计算此数组中的条目
  • 禁止访问 Y 页面的用户

  • 示例代码:
    <?php

    $visit_counter_pages = 5; // maximum number of pages to load
    $visit_counter_secs = 10; // maximum amount of time before cleaning visits

    session_start();

    // initialize an array for our visit counter
    if (array_key_exists('visit_counter', $_SESSION) == false)
    {
    $_SESSION['visit_counter'] = array();
    }

    // clean old visits
    foreach ($_SESSION['visit_counter'] as $key => $time)
    {
    if ((time() - $time) > $visit_counter_secs) {
    unset($_SESSION['visit_counter'][$key]);
    }
    }

    // we add the current visit into our array
    $_SESSION['visit_counter'][] = time();

    // check if user has reached limit of visited pages
    $banned = false;
    if (count($_SESSION['visit_counter']) > $visit_counter_pages)
    {
    // puts ip of our user on the same "banned table" as earlier...
    $banned = true;
    }

    // At this point you have a $banned if your user is banned or not.
    // The following code will allow us to test it...

    echo '<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>';

    // Display counter
    $count = count($_SESSION['visit_counter']);
    echo "You visited {$count} pages.";
    echo str_repeat('<br/>', 2);

    echo <<< EOT

    <a id="reload" href="#">Reload</a>

    <script type="text/javascript">

    $('#reload').click(function(e) {
    e.preventDefault();
    window.location.reload();
    });

    </script>

    EOT;

    echo str_repeat('<br/>', 2);

    // Display if you're banned or not
    echo str_repeat('<br/>', 2);
    if ($banned)
    {
    echo '<span style="color:red;">You are banned! Wait for a short while (10 secs in this demo)...</span>';
    echo '<br/>';
    echo '<img src="http://4.bp.blogspot.com/-PezlYVgEEvg/TadW2e4OyHI/AAAAAAAAAAg/QHZPVQcBNeg/s1600/feu-rouge.png" />';
    }
    else
    {
    echo '<span style="color:blue;">You are not banned!</span>';
    echo '<br/>';
    echo '<img src="http://identityspecialist.files.wordpress.com/2010/06/traffic_light_green.png" />';
    }
    ?>

    要下载的图像

    当一个爬虫需要做他的脏活时,那是为了大量的数据,而且是在尽可能短的时间内。这就是为什么他们不在页面上下载图像;它需要太多带宽并使爬行速度变慢。

    这个想法(我认为最优雅也最容易实现)使用了 mod_rewrite将代码隐藏在 .jpg/.png/... 图像文件中。该图像应该在您要保护的每个页面上可用:它可以是您的徽标网站,但您将选择一个小尺寸的图像(因为该图像不得被缓存)。

    主意 :

    1/将这些行添加到您的 .htaccess
    RewriteEngine On
    RewriteBase /tests/anticrawl/
    RewriteRule ^logo\.jpg$ logo.php

    2/使用安全性创建您的 logo.php
    <?php

    // start session and reset counter
    session_start();
    $_SESSION['no_logo_count'] = 0;

    // forces image to reload next time
    header("Cache-Control: no-store, no-cache, must-revalidate");

    // displays image
    header("Content-type: image/jpg");
    readfile("logo.jpg");
    die();

    3/在您需要添加安全性的每个页面上增加您的 no_logo_count,并检查它是否达到您的限制。

    示例代码:
    <?php

    $no_logo_limit = 5; // number of allowd pages without logo

    // start session and initialize
    session_start();
    if (array_key_exists('no_logo_count', $_SESSION) == false)
    {
    $_SESSION['no_logo_count'] = 0;
    }
    else
    {
    $_SESSION['no_logo_count']++;
    }

    // check if user has reached limit of "undownloaded image"
    $banned = false;
    if ($_SESSION['no_logo_count'] >= $no_logo_limit)
    {
    // puts ip of our user on the same "banned table" as earlier...
    $banned = true;
    }

    // At this point you have a $banned if your user is banned or not.
    // The following code will allow us to test it...

    echo '<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>';

    // Display counter
    echo "You did not loaded image {$_SESSION['no_logo_count']} times.";
    echo str_repeat('<br/>', 2);

    // Display "reload" link
    echo <<< EOT

    <a id="reload" href="#">Reload</a>

    <script type="text/javascript">

    $('#reload').click(function(e) {
    e.preventDefault();
    window.location.reload();
    });

    </script>

    EOT;

    echo str_repeat('<br/>', 2);

    // Display "show image" link : note that we're using .jpg file
    echo <<< EOT

    <div id="image_container">
    <a id="image_load" href="#">Load image</a>
    </div>
    <br/>

    <script type="text/javascript">

    // On your implementation, you'llO of course use <img src="logo.jpg" />
    $('#image_load').click(function(e) {
    e.preventDefault();
    $('#image_load').html('<img src="logo.jpg" />');
    });

    </script>

    EOT;

    // Display if you're banned or not
    echo str_repeat('<br/>', 2);
    if ($banned)
    {
    echo '<span style="color:red;">You are banned: click on "load image" and reload...</span>';
    echo '<br/>';
    echo '<img src="http://4.bp.blogspot.com/-PezlYVgEEvg/TadW2e4OyHI/AAAAAAAAAAg/QHZPVQcBNeg/s1600/feu-rouge.png" />';
    }
    else
    {
    echo '<span style="color:blue;">You are not banned!</span>';
    echo '<br/>';
    echo '<img src="http://identityspecialist.files.wordpress.com/2010/06/traffic_light_green.png" />';
    }
    ?>

    cookies 检查

    您可以在 javascript 端创建 cookie 以检查您的用户是否会解释 javascript(例如,使用 Curl 的爬虫不会)。

    这个想法很简单:这与图像检查大致相同。
  • 将 $_SESSION 值设置为 1 并在每次访问时递增
  • 如果确实存在 cookie(在 JavaScript 中设置),则将 session 值设置为 0
  • 如果此值达到限制,请禁止您的用户

  • 代码 :
    <?php

    $no_cookie_limit = 5; // number of allowd pages without cookie set check

    // Start session and reset counter
    session_start();

    if (array_key_exists('cookie_check_count', $_SESSION) == false)
    {
    $_SESSION['cookie_check_count'] = 0;
    }

    // Initializes cookie (note: rename it to a more discrete name of course) or check cookie value
    if ((array_key_exists('cookie_check', $_COOKIE) == false) || ($_COOKIE['cookie_check'] != 42))
    {
    // Cookie does not exist or is incorrect...
    $_SESSION['cookie_check_count']++;
    }
    else
    {
    // Cookie is properly set so we reset counter
    $_SESSION['cookie_check_count'] = 0;
    }

    // Check if user has reached limit of "cookie check"
    $banned = false;
    if ($_SESSION['cookie_check_count'] >= $no_cookie_limit)
    {
    // puts ip of our user on the same "banned table" as earlier...
    $banned = true;
    }

    // At this point you have a $banned if your user is banned or not.
    // The following code will allow us to test it...

    echo '<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>';

    // Display counter
    echo "Cookie check failed {$_SESSION['cookie_check_count']} times.";
    echo str_repeat('<br/>', 2);

    // Display "reload" link
    echo <<< EOT

    <br/>
    <a id="reload" href="#">Reload</a>
    <br/>

    <script type="text/javascript">

    $('#reload').click(function(e) {
    e.preventDefault();
    window.location.reload();
    });

    </script>

    EOT;

    // Display "set cookie" link
    echo <<< EOT

    <br/>
    <a id="cookie_link" href="#">Set cookie</a>
    <br/>

    <script type="text/javascript">

    // On your implementation, you'll of course put the cookie set on a $(document).ready()
    $('#cookie_link').click(function(e) {
    e.preventDefault();
    var expires = new Date();
    expires.setTime(new Date().getTime() + 3600000);
    document.cookie="cookie_check=42;expires=" + expires.toGMTString();
    });

    </script>
    EOT;


    // Display "unset cookie" link
    echo <<< EOT

    <br/>
    <a id="unset_cookie" href="#">Unset cookie</a>
    <br/>

    <script type="text/javascript">

    // On your implementation, you'll of course put the cookie set on a $(document).ready()
    $('#unset_cookie').click(function(e) {
    e.preventDefault();
    document.cookie="cookie_check=;expires=Thu, 01 Jan 1970 00:00:01 GMT";
    });

    </script>
    EOT;

    // Display if you're banned or not
    echo str_repeat('<br/>', 2);
    if ($banned)
    {
    echo '<span style="color:red;">You are banned: click on "Set cookie" and reload...</span>';
    echo '<br/>';
    echo '<img src="http://4.bp.blogspot.com/-PezlYVgEEvg/TadW2e4OyHI/AAAAAAAAAAg/QHZPVQcBNeg/s1600/feu-rouge.png" />';
    }
    else
    {
    echo '<span style="color:blue;">You are not banned!</span>';
    echo '<br/>';
    echo '<img src="http://identityspecialist.files.wordpress.com/2010/06/traffic_light_green.png" />';
    }

    代理保护

    关于我们可能会在网络上找到的不同类型的代理的一些词:
  • “普通”代理显示有关用户连接的信息(特别是他的 IP)
  • 匿名代理不显示 IP,但会在 header 上提供有关代理使用情况的信息。
  • 高匿名代理不显示用户IP,不显示浏览器不能发送的任何信息。

  • 找到连接任何网站的代理很容易,但很难找到高度匿名的代理。

    某些 $_SERVER 变量可能包含键,特别是如果您的用户位于代理后面(详尽列表取自 this question ):
  • CLIENT_IP
  • 转发
  • FORWARDED_FOR
  • FORWARDED_FOR_IP
  • HTTP_CLIENT_IP
  • HTTP_FORWARDED
  • HTTP_FORWARDED_FOR
  • HTTP_FORWARDED_FOR_IP
  • HTTP_PC_REMOTE_ADDR
  • HTTP_PROXY_CONNECTION'
  • HTTP_VIA
  • HTTP_X_FORWARDED
  • HTTP_X_FORWARDED_FOR
  • HTTP_X_FORWARDED_FOR_IP
  • HTTP_X_IMFORWARDS
  • HTTP_XROXY_CONNECTION
  • 威盛
  • X_FORWARDED
  • X_FORWARDED_FOR

  • 如果您在您的 $_SERVER 上检测到这些键之一,您可能会为您的反爬行证券提供不同的行为(下限等)。多变的。

    结论

    有很多方法可以检测您网站上的滥用行为,因此您肯定会找到解决方案。但是您需要准确了解您的网站是如何使用的,这样您的证券就不会受到“普通”用户的攻击。

    关于php - 如何检测假用户(爬虫)和 cURL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12257584/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com