41

他のいくつかのWebサイトは、cURLと偽のhttpリファラーを使用して私のWebサイトのコンテンツをコピーしています。cURLを検出する方法はありますか、それとも実際のWebブラウザーではありませんか?

4

6 に答える 6

101

自動クロールを回避するための魔法の解決策はありません。人間ができることはすべて、ロボットもそれを行うことができます。仕事を難しくするための解決策しかないので、熟練したオタクだけがそれをやり遂げようとするかもしれません。

私も数年前に困っていました。最初のアドバイスは、時間があれば自分でクローラーになることです(「クローラー」はあなたのウェブサイトをクロールする人だと思います)。これはこのテーマに最適な学校です。いくつかのWebサイトをクロールすることで、さまざまな種類の保護を学び、それらを関連付けることで効率的になりました。

私はあなたが試みるかもしれない保護のいくつかの例をあなたに与える。


IPあたりのセッション

ユーザーが毎分50の新しいセッションを使用する場合、このユーザーはCookieを処理しないクローラーである可能性があります。もちろん、curlはCookieを完全に管理しますが、セッションごとの訪問カウンター(後で説明)と組み合わせる場合、またはクローラーがCookieの問題を抱える初心者である場合は、効率的である可能性があります。

同じ共有接続の50人が同時にあなたのウェブサイトにアクセスすることを想像するのは難しいです(もちろんそれはあなたのトラフィックに依存します、それはあなた次第です)。そして、これが発生した場合は、キャプチャがいっぱいになるまでWebサイトのページをロックできます。

アイディア :

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)まだ挿入されていない場合は、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();
}

?>

カウンターにアクセス

ユーザーが同じCookieを使用してページをクロールする場合、ユーザーのセッションを使用してページをブロックできます。このアイデアは非常に単純です。ユーザーが60秒で60ページにアクセスする可能性はありますか?

アイディア :

  1. ユーザーセッションで配列を作成します。配列にはvisittime()が含まれます。
  2. この配列でX秒より古い訪問を削除します
  3. 実際の訪問のために新しいエントリを追加します
  4. この配列のエントリをカウントします
  5. ユーザーが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/…画像ファイルのコードを非表示にします。この画像は、保護する各ページで利用できる必要があります。ロゴのWebサイトである可能性がありますが、小さいサイズの画像を選択します(この画像はキャッシュしてはならないため)。

アイディア :

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" />';
}
?>

クッキーチェック

javascript側でCookieを作成して、ユーザーがjavascriptを解釈するかどうかを確認できます(たとえば、Curlを使用するクローラーは解釈しません)。

考え方は非常に単純です。これは画像チェックとほぼ同じです。

  1. $ _SESSION値を1に設定し、訪問ごとに増分します
  2. Cookie(JavaScriptで設定)が存在する場合は、セッション値を0に設定します
  3. この値が制限に達した場合は、ユーザーを禁止します

コード:

<?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を表示しませんが、ヘッダーでのプロキシの使用に関する情報を提供します。
  • 匿名性の高いプロキシはユーザーIPを表示せず、ブラウザが送信できない可能性のある情報も表示しません。

Webサイトに接続するためのプロキシを見つけるのは簡単ですが、匿名性の高いプロキシを見つけるのは非常に困難です。

一部の$_SERVER変数には、特にユーザーがプロキシの背後にいる場合にキーが含まれる場合があります(この質問から抜粋した完全なリスト)。

  • 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

変数でこれらのキーの1つを検出した場合、アンチクロール証券に異なる動作(下限など)を与えることができます$_SERVER


結論

Webサイトでの不正使用を検出する方法はたくさんあるので、確実に解決策を見つけることができます。ただし、Webサイトがどのように使用されているかを正確に知る必要があるため、「通常の」ユーザーに対して証券が攻撃的になることはありません。

于 2012-09-13T07:18:06.093 に答える
2

注意:HTTPは魔法ではありません。各HTTPリクエストで送信されるヘッダーの定義済みセットがあります。これらのヘッダーがWebブラウザーによって送信される場合は、cURL(およびlibcurl)を含む任意のプログラムからも送信できます。

呪いと考える人もいますが、一方で、Webアプリケーションの機能テストを大幅に簡素化するので、それは祝福です。

更新: unr3al011が正しく認識しているように、curlはJavaScriptを実行しないため、理論的には、グラバーで表示したときに異なる動作をするページを作成できます(たとえば、設定を行い、後でJS手段で特定のCookieをチェックします)。

それでも、それは非常に脆弱な防御になるでしょう。ページのデータは引き続きサーバーから取得する必要がありました。このHTTPリクエスト(および常にHTTPリクエスト)はcurlでエミュレートできます。このような防御を打ち負かす方法の例については、この回答を確認してください。

...そして、一部のグラバーがJavaScriptを実行できることについても言及しませんでした。)。

于 2012-09-04T06:05:40.920 に答える
0

偽のリファラーを回避する方法は、ユーザーを追跡することです

次の1つ以上の方法でユーザーを追跡できます。

  1. 特別なコード(例:最後にアクセスしたURL、タイムスタンプ)を使用してブラウザクライアントにCookieを保存し、サーバーの各応答で確認します。

  2. 以前と同じですが、明示的な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)
于 2012-09-13T07:47:46.713 に答える
0

cURL-Useragentは、次の方法で検出できます。ただし、useragentはユーザーによって上書きされる可能性があることに注意してください。とにかく、デフォルト設定は次のように認識される可能性があります。

function is_curl() {
    if (stristr($_SERVER["HTTP_USER_AGENT"], 'curl'))
        return true;
}
于 2018-03-10T23:58:41.227 に答える
-1

一部の人が言及しているように、cURLは(私の知る限り)JavaScritpを実行できないので、raina77owが提案するように何かを設定してみることができますが、他のグラバー/ドナーローダーではうまくいきません。

JavaScriptを実行できるグラバー/ダウンローダーを処理する方法でボットトラップを構築してみることをお勧めします。

これを完全に防ぐための1つの解決策を知らないので、複数の解決策を試すことをお勧めします。

1).htaccessファイル内のすべてのメインストリームブラウザなどの既知のユーザーエージェントのみを許可する

2)ボットを防ぐためにrobots.txtを設定します

3)robots.txtファイルを尊重しないボット用のボットトラップを設定します

于 2012-09-12T17:19:39.060 に答える
-4

これをファイルとしてルートフォルダに入れ.htaccessます。それは役立つかもしれません。私はそれを1つのウェブホスティングプロバイダーサイトで見つけましたが、それが何を意味するのかわかりません:)

SetEnvIf User-Agent ^Teleport graber   
SetEnvIf User-Agent ^w3m graber    
SetEnvIf User-Agent ^Offline graber   
SetEnvIf User-Agent Downloader graber  
SetEnvIf User-Agent snake graber  
SetEnvIf User-Agent Xenu graber   
Deny from env=graber
于 2012-09-05T08:04:57.647 に答える