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

Php 如何检测假用户(爬虫)和cURL,php,curl,spam-prevention,Php,Curl,Spam Prevention,其他一些网站使用cURL和假的http引用来复制我的网站内容。 我们有什么方法可以检测cURL或不是真正的web浏览器吗?记住:HTTP不是魔法。每个HTTP请求都会发送一组定义好的头文件;如果这些头文件是通过web浏览器发送的,那么它们也可以由任何程序发送,包括cURL(和libcurl) 有些人认为这是诅咒,但另一方面,这是一种祝福,因为它大大简化了Web应用程序的功能测试。 更新:正如unr3al011正确地注意到的那样,curl不执行JavaScript,因此理论上可以创建一个页面,该页

其他一些网站使用cURL和假的http引用来复制我的网站内容。
我们有什么方法可以检测cURL或不是真正的web浏览器吗?

记住:HTTP不是魔法。每个HTTP请求都会发送一组定义好的头文件;如果这些头文件是通过web浏览器发送的,那么它们也可以由任何程序发送,包括cURL(和libcurl)

有些人认为这是诅咒,但另一方面,这是一种祝福,因为它大大简化了Web应用程序的功能测试。

更新:正如unr3al011正确地注意到的那样,curl不执行JavaScript,因此理论上可以创建一个页面,该页面在被抓取者查看时会表现出不同的行为(例如,通过设置,稍后通过JS方式检查特定的cookie)

不过,这将是一个非常脆弱的防御。页面的数据仍然需要从服务器抓取——而这个HTTP请求(总是HTTP请求)可以被curl模拟。查看如何击败此类防御的示例


。。。我甚至没有提到一些抓取程序能够执行JavaScript。)

将其作为
.htaccess
文件放入根文件夹。这可能会有帮助。我在一家网络主机提供商的网站上找到了它,但不知道这意味着什么:)


正如一些人提到的,cURL不能执行JavaScritp(据我所知),所以您可以尝试设置一些类似raina77ow的东西,但这对于其他抓取器/donwloader来说是行不通的

我建议您尝试构建一个能够处理可以执行JavaScript的抓取器/下载器的方法

我不知道有哪一种解决方案可以完全防止这种情况,因此我的最佳建议是尝试多种解决方案:

1) 仅允许在.htaccess文件中使用已知的用户代理,如所有主流浏览器

2) 设置robots.txt以防止机器人


3) 为不遵守robots.txt文件的机器人设置机器人陷阱

没有避免自动爬行的神奇解决方案。人类能做的每一件事,机器人也能做。只有解决办法才能让工作变得更难,因为只有技术过硬的极客才能通过

几年前我也遇到了麻烦,我的第一个建议是,如果你有时间,自己做一个爬虫(我想“爬虫”就是爬你网站的人),这是最好的学校。通过抓取几个网站,我学到了不同的保护方法,通过将它们关联起来,我的工作效率很高

我给你举一些保护措施的例子,你可以试试


每IP会话数 如果一个用户每分钟使用50个新会话,您可以认为该用户可能是一个不处理cookie的爬虫。当然,curl可以完美地管理cookies,但是如果您在每次会话中都使用访问计数器(稍后解释),或者如果您的爬虫是一个处理cookie事务的noobie,那么它可能会很有效

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

想法:

1) 创建2个表:1个用于保存禁止的ip,1个用于保存ip和会话

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会话

5) 如果他有太多的会话,你可以将其插入你的禁止表并设置一个标志

6) 如果尚未插入,则在sessions per ip表中插入他的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();
}

?>
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();

避免虚假推荐的方法是跟踪用户

您可以通过以下一种或多种方法跟踪用户:

  • 使用一些特殊代码(例如:上次访问的url、时间戳)在浏览器客户端中保存cookie,并在服务器的每个响应中验证它

  • 与之前相同,但使用会话而不是显式cookie

  • 对于cookie,您应该添加加密安全性,如

    [Cookie]
    url => http://someurl/
    hash => dsafdshfdslajfd
    
    散列是用这种方法在PHP中计算的

    $url = $_COOKIE['url'];
    $hash = $_COOKIE['hash'];
    $secret = 'This is a fixed secret in the code of your application';
    
    $isValidCookie = (hash('algo', $secret . $url) === $hash);
    
    $isValidReferer = $isValidCookie & ($_SERVER['HTTP_REFERER'] === $url)
    

    您可以通过以下方法检测cURL Useragent。但请注意,用户可能会覆盖useragent,默认设置可以通过以下方式识别:

    function is_curl() {
        if (stristr($_SERVER["HTTP_USER_AGENT"], 'curl'))
            return true;
    }
    

    现在cURL可以设置用户代理和http refefer。所以,我们根本检测不到它?不。我会说“很不幸”,但事实上,它不是:如果curl无法发送它,任何其他库都会取代它。你“可以”检测到curl。如果假设请求来自curl,请检查它是否可以执行Javascript。Curl无法执行Javascript。你如何在PHP代码上检测到“无法执行Javascript”?KenLe你检查过我提到的答案了吗?它既包含带JS检查的HTML代码,也包含击败它的PHP代码。我也不认为在这里包含这段代码有什么意义,因为它通常不是一个解决方案。你确定你应该发布你不知道其含义的解决方案吗?你可以自己找到它的含义,我刚刚复制了这段代码。他们说用这个很难抓到你的网页。我认为这是对一些抓取器的限制,正如您所看到的。它所做的是获取指定的用户代理字符串部分,将它们定义到“graber”env中,并拒绝访问。如果这些都没有在用户代理中使用,这就没什么作用了。你不能假设scraper不能运行Javascript……有一些东西,比如rhino,可以让他们在运行Javascript的时候刮取你的站点。除非你把你的内容放在数字墙后面(登录、认证等),否则它就可以被删除。版权材料,然后起诉他们,如果他们张贴未经书面许可。如果他们在另一个国家,祝你好运。我不知道这在将来是否会改变,但是cURL(至少是PHP cURL)忽略了
    连接:clo
    
    <?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" />';
    }
    ?>
    
    <?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" />';
    }
    
    [Cookie]
    url => http://someurl/
    hash => dsafdshfdslajfd
    
    $url = $_COOKIE['url'];
    $hash = $_COOKIE['hash'];
    $secret = 'This is a fixed secret in the code of your application';
    
    $isValidCookie = (hash('algo', $secret . $url) === $hash);
    
    $isValidReferer = $isValidCookie & ($_SERVER['HTTP_REFERER'] === $url)
    
    function is_curl() {
        if (stristr($_SERVER["HTTP_USER_AGENT"], 'curl'))
            return true;
    }