banner
Vinking

Vinking

你写下的每一个BUG 都是人类反抗被人工智能统治的一颗子弹

禁止マーケティングクモがウェブサイトをクロールすること

今日はウェブサイトのアクセスログを見ていたら、Mozilla/5.0 (compatible; SemrushBot/7~bl; +http://www.semrush.com/bot.html)というユーザーエージェントのクローラーが非常に頻繁にサイトをクロールしていることに気付きました。そして、20MB 以上のログを見れば、サイトをクロールしているのはかなりの時間にわたっていることがわかります。

サイトログ

このクローラーがクロールしているウェブページを見ると、以前にクロールしたページのいくつかのパラメータをランダムに組み合わせて再度アクセスしているようです。そのため、クロールされるリンクは長い文字列になり、基本的に返されるのは 404 です。さらに、数秒ごとにクロールされるため、ログ内の正常なアクセス記録は数万行のゴミクローラーの記録に埋もれてしまっています。

最初は、クローラーはrobots.txtを遵守すべきだと思い、robots.txtにルールを追加すればいいだろうと思いました:

User-agent: SemrushBot
Disallow: /

しかし、ネットで調べたところ、このクローラーはrobots.txtを遵守しないようです😅(公式ページではクローラーがrobots.txtを厳密に遵守すると主張していますが、ネットのフィードバックを見る限りそうではないようです)。しかも、このSemrushBotだけでなく、多くのマーケティングクローラーもrobots.txtを遵守しません。仕方がないので、Nginx を使って遮断することにしました。宝塔のNginx 無料ファイアウォールグローバル設定User-Agent フィルタルールをクリックし、以下の正規表現を追加しました(ネットで集めたもので、こんなに多くの UA があるとは思いませんでした。使用前に必要な UA がないか確認してください):

(nmap|NMAP|HTTrack|sqlmap|Java|zgrab|Go-http-client|CensysInspect|leiki|webmeup|Python|python|curllCurl|wget|Wget|toutiao|Barkrowler|AhrefsBot|a Palo Alto|ltx71|censys|DotBot|MauiBot|MegaIndex.ru|BLEXBot|ZoominfoBot|ExtLinksBot|hubspot|FeedDemon|Indy Library|Alexa Toolbar|AskTbFXTV|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|HttpClient|MJ12bot|heritrix|Bytespider|Ezooms|JikeSpider|SemrushBot)

その後、数秒待つと遮断されたデータが見られるようになります。

遮断データ

その後、常に増加する遮断数を見て、404 でも 444 でもリクエストを発信するだけでサーバーリソースを消費することに気付きました。このように数秒ごとにリクエストを送り続けるのは長続きしません。これらのクローラーの IP を調べると、すべて国外のノードであり、私のウェブサイトの国外ルートも Cloudflare に解析されているので、Cloudflare に中間でブロックしてもらうことができ、サイトへのアクセスを防ぐことができます。

クローラー IP

Cloudflare の対応するドメインコンソールに入ったら、セキュリティWAF項目に入り、ルールを追加をクリックします。式プレビューに以下の式を追加します(同様に使用前に必要な UA がブロックされていないか確認してください):

(http.user_agent contains "SemrushBot") or (http.user_agent contains "FeedDemon") or (http.user_agent contains "Indy Library") or (http.user_agent contains "Alexa Toolbar") or (http.user_agent contains "AskTbFXTV") or (http.user_agent contains "AhrefsBot") or (http.user_agent contains "CrawlDaddy") or (http.user_agent contains "CoolpadWebkit") or (http.user_agent contains "Java") or (http.user_agent contains "Feedly") or (http.user_agent contains "UniversalFeedParser") or (http.user_agent contains "ApacheBench") or (http.user_agent contains "Microsoft URL Control") or (http.user_agent contains "Swiftbot") or (http.user_agent contains "ZmEu") or (http.user_agent contains "jaunty") or (http.user_agent contains "Python-urllib") or (http.user_agent contains "lightDeckReports Bot") or (http.user_agent contains "YYSpider") or (http.user_agent contains "DigExt") or (http.user_agent contains "HttpClient") or (http.user_agent contains "MJ12bot") or (http.user_agent contains "heritrix") or (http.user_agent contains "Bytespider") or (http.user_agent contains "Ezooms") or (http.user_agent contains "JikeSpider") or (http.user_agent contains "HTTrack") or (http.user_agent contains "Apache-HttpClient") or (http.user_agent contains "harvest") or (http.user_agent contains "audit") or (http.user_agent contains "dirbuster") or (http.user_agent contains "pangolin") or (http.user_agent contains "nmap") or (http.user_agent contains "sqln") or (http.user_agent contains "hydra") or (http.user_agent contains "libwww") or (http.user_agent contains "BBBike") or (http.user_agent contains "sqlmap") or (http.user_agent contains "w3af") or (http.user_agent contains "owasp") or (http.user_agent contains "Nikto") or (http.user_agent contains "fimap") or (http.user_agent contains "havij") or (http.user_agent contains "BabyKrokodil") or (http.user_agent contains "netsparker") or (http.user_agent contains "httperf") or (http.user_agent contains " SF/") or (http.user_agent contains "zgrab") or (http.user_agent contains "NMAP") or (http.user_agent contains "Go-http-client") or (http.user_agent contains "CensysInspect") or (http.user_agent contains "leiki") or (http.user_agent contains "webmeup") or (http.user_agent contains "Python") or (http.user_agent contains "python") or (http.user_agent contains "wget") or (http.user_agent contains "Wget") or (http.user_agent contains "toutiao") or (http.user_agent contains "Barkrowler") or (http.user_agent contains "a Palo Alto") or (http.user_agent contains "ltx71") or (http.user_agent contains "censys") or (http.user_agent contains "DotBot") or (http.user_agent contains "MauiBot") or (http.user_agent contains "MegaIndex.ru") or (http.user_agent contains "BLEXBot") or (http.user_agent contains "ZoominfoBot") or (http.user_agent contains "ExtLinksBot") or (http.user_agent contains "hubspot")

その後、操作を選択し、ブロックを選択して保存すれば完了です。

Cloudflare カスタムルール

これで、宝塔の Nginx 無料ファイアウォールのリスク遮断数が増えなくなれば、Cloudflare のファイアウォールルールの遮断数が急増しているときは、Cloudflare がこれらのゴミクローラーのアクセスを成功裏に遮断したことを示しています。

目覚めて更新#

目覚めたら、すでに 2000 回以上遮断されていました。このクローラーは本当にしつこいですね😅。

Cloudflare カスタムルール

カスタム遮断ページ#

最近、Cloudflare のデフォルトの遮断ページを見て、あまりにも醜いと感じました... カスタムの遮断ページに変更したいと思いました。

Cloudflare デフォルトの遮断ページ

結果、カスタムページを使用するには Pro プランにアップグレードする必要があることがわかりました。まあ、無料で使っている人がカスタムページのためにアップグレードすることは不可能なので、比較的単純な方法で実現することにしました。考え方は、上記の User-Agent に該当する訪問者をすべてカスタムページにリダイレクトすることです。

Note

🔔注意:Vercel にホスティングされたページは国内ではアクセスできません。なぜなら、当サイトの海外アクセスは Cloudflare を経由するため、国内でのアクセス可否は考慮する必要がありません。国内でもアクセスできるようにしたい場合は、他のページホスティングプラットフォームを使用してください。

私たちは静的な遮断ページを自分で作成し、Vercelにホスティングする必要があります。

Vercel デプロイの詳細手順#

まず、Vercelに行き、新しいプロジェクトを作成します。

新しいプロジェクト

次に、左側で既存のリポジトリからカスタムページをインポートするか、右側でテンプレートをクローンできます。ここではまだカスタムページがないので、右側のテンプレートをクローンするリンクをクリックしてテンプレートを選択します。

テンプレートをクローン

ここでは React を使用してページを作成しているので、Create React App というテンプレートを使用します。テンプレートを使用するために Deploy ボタンをクリックします。

次に、Create Git Repository 内で Github を接続し、カスタムリポジトリ名を入力し、デフォルトで Create private Git Repository を選択してプライベートリポジトリに設定し、Create をクリックすると自動的にデプロイされます。

デプロイ

Congratulations! というメッセージが表示されたら、成功裏にデプロイされたことを示します。

成功裏にデプロイ

最後に、Github でコードを先ほど作成したリポジトリにコミットします。コミットが完了すると、Vercel が自動的にページを更新します。

以下は、私が React で作成したカスタムページで、直接使用できます。

\src\App.jsファイル:

import React, { Component } from 'react'
import './App.css';

export default class App extends Component {
  state = {
    tran: {
      lang: 'en',
      title: 'このリクエストはブロックされました',
      contents_1: 'あなたのいくつかの特徴がブラックリストに存在し、このリクエストはブロックされました。',
      contents_2: 'これが誤報だと思う場合は、すぐに私に連絡してください。',
      footer: '@Vinking セキュリティセンター',
      tips: '詳細はセキュリティセンターの最適化に保存されました'
    }
  }
  handleTranslations = () => {
    const { lang } = this.state.tran
    const newState = (lang === 'en') ? {
      lang: 'zh',
      title: '请求已被拦截',
      contents_1: '您的一些特征存在于黑名单中,此次请求已被拦截。',
      contents_2: '如果您觉得这是误报,请及时联系我。',
      symbols: '@ Vinking 安全中心',
      tips: '详细信息已保存以持续优化安全中心'
    } : {
      lang: 'en',
      title: 'このリクエストはブロックされました',
      contents_1: 'あなたのいくつかの特徴がブラックリストに存在し、このリクエストはブロックされました。',
      contents_2: 'これが誤報だと思う場合は、すぐに私に連絡してください。',
      symbols: '@Vinking セキュリティセンター',
      tips: '詳細はセキュリティセンターの最適化に保存されました'
    }
    document.title = newState.title
    this.setState({ tran: newState })
  }
  render() {
    const { title, contents_1, contents_2, symbols, tips } = this.state.tran
    return (
      <div className="content">
        <div className="card">
          <div className="cardHeader">
            <div>{title}</div>
            <div className='translation' onClick={this.handleTranslations}>
              <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 1024 1024"><path fill="#f8f9fa" d="M608 416h288c35.36 0 64 28.48 64 64v416c0 35.36-28.48 64-64 64H480c-35.36 0-64-28.48-64-64V608H128c-35.36 0-64-28.48-64-64V128c0-35.36 28.48-64 64-64h416c35.36 0 64 28.48 64 64v288zm0 64v64c0 35.36-28.48 64-64 64h-64v256.032C480 881.696 494.304 896 511.968 896H864a31.968 31.968 0 0 0 31.968-31.968V512A31.968 31.968 0 0 0 864 480.032H608zM128 159.968V512c0 17.664 14.304 31.968 31.968 31.968H512A31.968 31.968 0 0 0 543.968 512V160a31.968 31.968 0 0 0-31.936-32H160a31.968 31.968 0 0 0-32 31.968zm64 244.288V243.36h112.736V176h46.752c6.4.928 9.632 1.824 9.632 2.752a10.56 10.56 0 0 1-1.376 4.128c-2.752 7.328-4.128 16.032-4.128 26.112v34.368h119.648v156.768h-50.88v-20.64h-68.768V497.76h-49.504V379.488h-67.36v24.768H192zm46.72-122.368v60.48h67.392V281.92h-67.36zm185.664 60.48V281.92h-68.768v60.48h68.768zm203.84 488H576L668.128 576h64.64l89.344 254.4h-54.976l-19.264-53.664H647.488l-19.232 53.632zm33.024-96.256h72.864l-34.368-108.608h-1.376l-37.12 108.608zM896 320h-64a128 128 0 0 0-128-128v-64a192 192 0 0 1 192 192zM128 704h64a128 128 0 0 0 128 128v64a192 192 0 0 1-192-192z" /></svg>
            </div>
          </div>
          <div className="cardDesc">
            <span className="red">{contents_1}</span>
            <br />
            {contents_2}
          </div>
          <div className="cardSymbols">
            <div>{symbols}</div>
          </div>
        </div>
        <div className="tips">{tips}</div>
      </div>
    )
  }
}

\public\index.htmlファイル:

<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, shrink-to-fit=no">
  <meta name="theme-color" content="#07092f">
  <title>このリクエストはブロックされました</title>
  <meta name="description" content="このリクエストはブロックされました。">
</head>

<body>
  <div id="root"></div>
</body>

</html>

Cloudflare に戻り、ルール項目のリダイレクトルールをクリックし、ルールを作成します。上記のマーケティングクローラーを遮断する式を式編集ボックスに入力し、タイプ静的URLに先ほどの Vercel ホスティングページのリンクを入力し、ステータスコード301に設定し、クエリ文字列を保持しないにチェックを外せばカスタム遮断ページが作成できます。

Cloudflare リダイレクト

この記事は Mix Space によって xLog に同期更新されました。原始リンクは https://www.vinking.top/posts/codes/blocking-bots-with-cloudflare

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。