زيارات ChatGPT-User في سجلات موقعك: الحقيقي من المزيف

عدسة مكبرة تفصل سطور السجل الحقيقية عن المزيفة، تعبيرًا عن التحقق من زيارات ChatGPT-User

فتحت سجلات موقعك ولقيت ChatGPT-User واخد 404 كذا مرة في اليوم، فقلت “يا نهار أبيض، ChatGPT مش لاقي صفحاتي”؟ استنى قبل ما تقلق. أغلب السطور دي مش ChatGPT أصلًا، دي ماسح ثغرات لابس اسمه. وفي المقال ده هتعرف تفرّق بينهم بسكربت واحد، وتلاقي الـ 404 اللي فعلًا بتضيّع عليك عملاء.

ماذا وجدت الدراسة؟

حلّل فريق المصدر يومًا واحدًا من زيارات البوتات، الأربعاء 7 أكتوبر 2026، على 111 موقعًا لشركات صغيرة تعمل بووردبريس. الطلبات التي تحمل وكيل المستخدم (User Agent) الخاص بـ ChatGPT-User حصلت على خطأ 404 عدد 1,022 مرة، منها 703 مرة (69%) كانت محاولات استغلال ثغرات وليست ChatGPT.

للمقارنة، هذه نسب أخطاء 404 لكل فئة من البوتات في نفس اليوم (من إجمالي 823,928 طلبًا):

الفئةنسبة 404
كل البوتات5.8%
——
مساعدات ذكاء اصطناعي تجلب صفحة لمستخدم (ChatGPT-User وClaude-User وPerplexity-User)43.7%
زواحف بحث الذكاء الاصطناعي10.0%
محركات البحث7.2%
زواحف تدريب الذكاء الاصطناعي4.4%

الفارق الضخم في الفئة الثانية سببه الماسح المنتحل. والأهم أن أخطاء 404 التي تهمك فعلًا، أي البشر الذين أرسلهم ChatGPT إلى صفحة غير موجودة، لا تظهر تحت هذا الاسم إطلاقًا.

من هو ChatGPT-User أصلًا؟

تستخدم OpenAI ثلاثة بوتات، ولكل منها وظيفة ونطاقات IP منشورة رسميًا:

وكيل المستخدموظيفتهملف نطاقات IP
GPTBotيجمع بيانات التدريبhttps://openai.com/gptbot.json
———
OAI-SearchBotيبني فهرس البحث في ChatGPThttps://openai.com/searchbot.json
ChatGPT-Userيجلب صفحة عند الطلب أثناء محادثة مستخدمhttps://openai.com/chatgpt-user.json

هكذا يبدو طلب ChatGPT-User في سجل الوصول (Access Log) بالصيغة المجمّعة (سطر توضيحي بعنوان من قائمة OpenAI):

104.208.184.197 - - [07/Oct/2026:10:14:02 +0000] "GET /services/ HTTP/1.1" 200 512 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot"

نص وكيل المستخدم سهل النسخ جدًا، أما عنوان IP فلا يمكن تزويره بسهولة. لهذا تنشر OpenAI نطاقاتها، ولهذا يجب أن يكون التحقق دائمًا بالعنوان لا بالاسم.

ماذا يطلب الماسح المنتحل؟

من بين 703 طلبًا مزيفًا، تكررت هذه الأنماط:

  • /cgi-bin/php-cgi مع معامل allow_url_include، وهي ثغرة حقن معاملات PHP-CGI المعروفة باسم CVE-2024-4577.
  • ملفات .env التي تحتوي عادة كلمات مرور قواعد البيانات ومفاتيح API.
  • قراءة /proc/self ومحاولات تجاوز المسار (Path Traversal).
  • قراءة الملفات عبر /@fs/ في خادم تطوير Vite.
  • رموز حسابات الخدمة في Kubernetes.

باقي الطلبات استهدفت ملفات إعداد وتصحيح مثل runtime-config.js و/debug/pprof لا يقدمها أي موقع شركة صغيرة. والمجسات نفسها تصل أيضًا منتحلة أسماء GrokBot وMistralAI-User وDuckAssistBot. أمثلة كما تظهر في السجل (عناوين من نطاقات التوثيق):

203.0.113.24 - - [07/Oct/2026:10:14:02 +0000] "GET /cgi-bin/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input HTTP/1.1" 404 512 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot"
203.0.113.24 - - [07/Oct/2026:10:14:02 +0000] "GET /.env HTTP/1.1" 404 512 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot"
198.51.100.7 - - [07/Oct/2026:10:14:02 +0000] "GET /@fs/etc/passwd?raw HTTP/1.1" 404 512 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot"
198.51.100.7 - - [07/Oct/2026:10:14:02 +0000] "GET /var/run/secrets/kubernetes.io/serviceaccount/token HTTP/1.1" 404 512 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot"

على موقع ووردبريس سليم، يجب أن تعود كل هذه الطلبات بخطأ 404، وهذا هو الرد الصحيح. المشكلة في التقارير فقط: إذا حسبتها على ChatGPT فرقم “ChatGPT لا يجد صفحاتنا” سيكون ضجيجًا في معظمه.

سكربت يفرز الزيارات الحقيقية من المزيفة

السكربت التالي يقارن عنوان كل طلب بنطاقات OpenAI الرسمية، ويفصل ChatGPT-User الحقيقي عن المزيف، ثم يؤدي المهمة الأهم: يجد الزوار البشر الذين أرسلهم ChatGPT ووصلوا إلى صفحة 404. يعمل بمكتبة Python القياسية فقط، بإصدار 3.8 أو أحدث:

#!/usr/bin/env python3
"""Split an access log's ChatGPT traffic into what's real and what isn't.

    python3 chatgpt_404s.py access.log

Reads the combined log format (nginx and Apache default) and downloads
OpenAI's published ChatGPT-User IP ranges. Standard library only.
"""
import ipaddress
import json
import re
import sys
import urllib.request
from collections import Counter
from urllib.parse import parse_qs, urlsplit

RANGES_URL = "https://openai.com/chatgpt-user.json"

LINE = re.compile(
    r'(?P<ip>S+) S+ S+ [[^]]+] "(?P<method>S+) (?P<path>S+)[^"]*" '
    r'(?P<status>d{3}) S+ "(?P<referer>[^"]*)" "(?P<ua>[^"]*)"'
)

# Paths no small business website serves. These are what the scanner wearing
# the ChatGPT-User name asked for in our logs.
PROBE = re.compile(
    r"php-cgi|allow_url_include|/.env|/proc/self|/@fs/|serviceaccount/token"
    r"|../|%2e%2e|/debug/pprof|runtime-config.js",
    re.IGNORECASE,
)


def load_ranges(url=RANGES_URL):
    req = urllib.request.Request(url, headers={"User-Agent": "chatgpt-404s/1.0"})
    with urllib.request.urlopen(req, timeout=20) as resp:
        prefixes = json.load(resp)["prefixes"]
    return [ipaddress.ip_network(p.get("ipv4Prefix") or p["ipv6Prefix"]) for p in prefixes]


def from_openai(ip, nets):
    try:
        addr = ipaddress.ip_address(ip)
    except ValueError:
        return False
    return any(addr in net for net in nets if net.version == addr.version)


def sent_by_chatgpt(path, referer):
    """A person clicking a link in a ChatGPT answer, not a bot."""
    sources = parse_qs(urlsplit(path).query).get("utm_source", [])
    return "chatgpt.com" in sources or urlsplit(referer).hostname in ("chatgpt.com", "chat.openai.com")


def main(log_path):
    nets = load_ranges()
    bots = Counter()
    bot_404s = Counter()
    visitor_404s = Counter()
    visitors = 0

    with open(log_path, encoding="utf-8", errors="replace") as log:
        for raw in log:
            m = LINE.match(raw)
            if not m:
                continue
            page = urlsplit(m["path"]).path
            if "ChatGPT-User" in m["ua"]:
                if not from_openai(m["ip"], nets):
                    bots["fake (not from OpenAI's IP ranges)"] += 1
                    if PROBE.search(m["path"]):
                        bots["  of which exploit probes"] += 1
                else:
                    bots["real ChatGPT-User"] += 1
                    if m["status"] == "404":
                        bot_404s[page] += 1
            elif sent_by_chatgpt(m["path"], m["referer"]):
                visitors += 1
                if m["status"] == "404":
                    visitor_404s[page] += 1

    print("ChatGPT-User requests")
    for label, n in bots.items():
        print(f"  {n:>5}  {label}")
    print("nPages real ChatGPT-User fetched that returned 404")
    for page, n in bot_404s.most_common(20):
        print(f"  {n:>5}  {page}")
    lost = sum(visitor_404s.values())
    print(f"nVisitors ChatGPT sent you: {visitors}, landed on a 404: {lost}")
    for page, n in visitor_404s.most_common(20):
        print(f"  {n:>5}  {page}")


if __name__ == "__main__":
    main(sys.argv[1])

شغّله على ملف السجل هكذا:

python3 chatgpt_404s.py /var/log/nginx/access.log

على سجل تجريبي صغير (سطر حقيقي واحد من قائمة OpenAI، وعنوانان مزيفان، وبعض الزوار)، تكون النتيجة:

ChatGPT-User requests
      2  real ChatGPT-User
      6  fake (not from OpenAI's IP ranges)
      5    of which exploit probes

Pages real ChatGPT-User fetched that returned 404
      1  /experiences/

Visitors ChatGPT sent you: 5, landed on a 404: 3
      2  /contact-us/
      1  /product/discontinued-perfume/

أين تجد ملف السجل على استضافتك؟

  • استضافة مشتركة بـ cPanel (الأكثر انتشارًا في مصر والخليج): من Metrics ← Raw Access نزّل الملف المضغوط، ثم فك ضغطه قبل التشغيل.
  • VPS بـ nginx: غالبًا في /var/log/nginx/access.log.
  • VPS بـ Apache: غالبًا في /var/log/apache2/access.log أو /var/log/httpd/access_log.

ثلاثة أمور قبل أن تثق في النتائج

  • خلف Cloudflare أو أي بروكسي، سجّل عنوان الزائر الحقيقي. وإلا ستأتي كل الطلبات من عناوين Cloudflare ويبدو كل شيء مزيفًا. في nginx يعني ذلك ضبط real_ip_header CF-Connecting-IP مع نطاقات Cloudflare في set_real_ip_from. هذه نقطة مهمة لأن Cloudflare المجاني شائع جدًا مع مواقع المنطقة.
  • اجلب النطاقات حديثة في كل تشغيل. OpenAI تحدّث ملف chatgpt-user.json باستمرار، والسكربت يفعل ذلك تلقائيًا.
  • فك ضغط السجلات المؤرشفة أولًا. الملفات المدوّرة المضغوطة تحتاج أمرًا مثل zcat access.log.2.gz > access.log.2.

كيف تجد أخطاء 404 التي يقع فيها زوار ChatGPT الحقيقيون؟

ابحث عن النقرة، لا عن البوت. عندما ينقر شخص رابطًا في إجابة ChatGPT، يرسل متصفحه الطلب بوكيل مستخدم عادي، ويضيف ChatGPT المعامل utm_source=chatgpt.com إلى الرابط، وغالبًا يكون المُحيل https://chatgpt.com/. هذا بالضبط ما تلتقطه الدالة sent_by_chatgpt().

هذه هي الزيارات التي تكلّفك عملاء. عبر 323 موقعًا استقبلت زيارات من ChatGPT بين 30 سبتمبر و9 أكتوبر 2026، وصلت 36 زيارة من أصل 4,053 (نحو زيارة من كل 113) إلى صفحة 404.

ومن بينها نوع يستحق انتباه المطوّر: روابط “مشوّهة” لصفحات موجودة فعلًا. النموذج كتب الرابط بترميز نسبة مضاعف (%25 مكان %)، أو غيّر بايتًا واحدًا، أو حذف بايتات من المنتصف. السبب أن النموذج يكتب الرابط جزءًا جزءًا بدل أن ينسخه.

ملاحظة للمواقع العربية: الروابط الدائمة (Slugs) العربية تتحول في الرابط إلى سلاسل طويلة مرمّزة مثل %D8%A7%D9%84...، وهي بالضبط النوع الذي يفسده النموذج بسهولة. إذا كان موقعك يعتمد على روابط عربية، فهذا سبب إضافي لاستخدام روابط إنجليزية قصيرة للصفحات المهمة.

ماذا تُرجع لكل نوع من أخطاء 404؟

نوع الخطأالرد المناسب
صفحة انتقلت (هيكل روابط قديم أو Slug متغير)إعادة التوجيه الدائمة (301 Redirect) إلى العنوان الجديد
——
منتج أو إعلان أو وظيفة حُذفت301 إلى البديل أو التصنيف، أو صفحة “غير متاح” مع بدائل، وليس الصفحة الرئيسية
عنوان اخترعه ChatGPT ويستمر في جلب زياراتأنشئ صفحة عليه، أو 301 إلى أقرب صفحة حقيقية
نسخة مشوّهة من رابط حقيقي301 من النسخة المكسورة إلى الصفحة الصحيحة
صفحات سبام أو تجارب يجب أن تختفي410 Gone
مجسات الاستغلال (php-cgi و.env و/@fs/)اتركها 404، أو احظرها في جدار الحماية (WAF)

لماذا ليس الصفحة الرئيسية؟ لأن جوجل يعامل التحويل الجماعي إليها كخطأ 404 ناعم (Soft 404)، فلا تستفيد شيئًا.

قاعدة عملية تبقي الأمر قابلًا للإدارة: حوّل العنوان الميت بمجرد أن يستقبل أكثر من زيارتين أو ثلاث زيارات بشرية ولديك صفحة حية تلبي نفس الحاجة، أو فورًا إذا كانت مواقع أخرى تشير إليه.

في ووردبريس: تستطيع إدارة كل هذه التحويلات من إضافة Redirection المجانية، أو من قسم التحويلات في Rank Math. وكلاهما يسجل أخطاء 404 أيضًا، فتقارن ما يظهر فيه بنتائج السكربت.

حدود هذه الأرقام

أصحاب الدراسة أنفسهم ذكروا ثلاث نقاط يجب أخذها في الاعتبار:

  • نسبة 69% مصنفة حسب المسار المطلوب، لا حسب عنوان IP. السكربت هو الطريقة الموصى بها، لكنه ليس الطريقة التي حُسبت بها الدراسة.
  • عشرة أيام قراءة أولية. 36 زيارة إلى صفحات ميتة تكشف النمط، لا معدلًا دقيقًا.
  • تحويلات Cloudflare أو خادم الويب لا تصل إلى ووردبريس أصلًا، فالموقع الذي أصلحها هناك يبدو نظيفًا في بياناتهم.

الأسئلة الشائعة

س: هل كل زيارة تحمل اسم ChatGPT-User في السجل حقيقية؟
ج: لا. الاسم سهل الانتحال، والطريقة الوحيدة الموثوقة هي مطابقة عنوان IP مع ملف chatgpt-user.json الذي تنشره OpenAI.

س: هل يجب أن أحظر ChatGPT-User في ملف robots.txt؟
ج: حظره يمنع ChatGPT من جلب صفحاتك حين يسأل عنها المستخدمون، فتخسر ظهورك في إجاباته. الأفضل أن تحظر العناوين المزيفة في جدار الحماية وتترك البوت الحقيقي.

س: كيف أعرف أن زائرًا جاء من ChatGPT في Google Analytics؟
ج: ابحث عن المصدر chatgpt.com في تقرير اكتساب الزيارات، فـ ChatGPT يضيف utm_source=chatgpt.com إلى الروابط التي يضعها في إجاباته.

س: هل يعمل السكربت على استضافة مشتركة؟
ج: يعمل على أي جهاز فيه Python 3.8 أو أحدث. نزّل ملف السجل من cPanel إلى جهازك وشغّل السكربت محليًا عليه.

الخلاصة

متخليش رقم مزيف يوجعلك دماغك: تحقق من الـ IP مش من الاسم، وركّز على الزوار البشر اللي ChatGPT بعتهم ووقعوا في 404. شغّل السكربت على سجلات الأسبوع ده، وحوّل أول تلات روابط ميتة تلاقيها النهارده.

مرجع المقال (بالإنجليزية): ChatGPT-User in your logs: how to tell real ChatGPT traffic from a scanner using its name
المقال ده مش ترجمة حرفية: متكيّف للقارئ العربي ومضاف عليه سياق ووردبريس وElementor وJetEngine.

اترك تعليقاً