التقاط كود Claude باستخدام `mitmproxy` — دليل خطوة بخطوة (مع إضافات جاهزة للتشغيل & سكربتات تحليل)
٢٢ سبتمبر ٢٠٢٥
هل ترغب في رؤية ما يرسله Claude Code فعليًا إلى Anthropic؟ هذه المقالة تشرح لك سير عمل عملي وقابل للتكرار لاعتراض وحفظ وتحليل حركة مرور Claude Code باستخدام mitmproxy. ستحصل على:
- إعداد خطوة بخطوة لبروكسي عكسي لـ Claude Code باستخدام
mitmproxy. - إضافة جاهزة للتشغيل تستخرج الرسائل النظامية المخفية (القواعد «المهم: …»).
- إضافة متكاملة تلتقط الطلبات + الاستجابات (الرسائل النظامية، تعريفات الأدوات، رسائل المستخدم، والاستجابات المتدفقة/الجزئية) في سجلات موقوتة.
- أدوات تحليل صغيرة لاستخراج الرسائل النظامية وربط الطلبات بالاستجابات في تنسيق JSON لإعادة التشغيل/التحليل.
- تحذيرات أمنية وخصوصية وقانونية.
ملخص سريع: شغّل mitmproxy في الوضع العكسي، اضبط
ANTHROPIC_BASE_URL=http://localhost:8000, ثق بشهادة mitm أثناء الاختبار، شغّل Claude Code — وستحفظ الإضافات أدناه الحمولات لك.
السلامة والأخلاقيات (اقرأ أولاً)
- لا تعترض إلا حركة مرور تملكها أو مُصرح لك صراحة بمراجعتها. اعتراض حركة مرور المستخدمين الآخرين غير قانوني/غير أخلاقي.
- ستحتوي السجلات الملتقطة على API مفاتيح ورموز وأسرار. تعامل معها بحساسية. قم بحذف المعلومات الحساسة قبل المشاركة.
- بعد الاختبار، أزل شهادة mitmproxy CA من مخزن الثقة الخاص بنظامك. لا تثق بها بشكل دائم.
- إذا كان العميل يستخدم تثبيت TLS، فستتم مقاطعتك — لا تحاول تجاوز التثبيت لأنظمة لا تملكها.
المتطلبات الأساسية
- macOS أو Linux (الأوامر مذكورة لـ macOS؛ Linux مشابه).
- Python 3.8+ (لإضافة mitmproxy).
- Homebrew (اختياري) أو
pipلتثبيت mitmproxy. - عميل
claude/Claude Code الذي يمكن توجيهه إلىANTHROPIC_BASE_URLمخصص (أو أي عميل يتصل بـAPI.anthropic.com).
1- تثبيت mitmproxy
macOS (Homebrew):
brew install mitmproxy
أو باستخدام pip (يفضل virtualenv):
python3 -m venv venv
source venv/bin/activate
pip install mitmproxy
الأدوات التي لديك الآن:
mitmproxy— واجهة طرفية تفاعليةmitmweb— واجهة ويب (مُفتش الويب الافتراضي على :8081)mitmdump— وضع بدون واجهة/سكربت (ممتاز لتشغيل الإضافات)
2— تشغيل mitmproxy في الوضع العكسي
يقوم Claude Code عادةً بالاتصال بـ https://API.anthropic.com. شغّل mitmproxy كـ بروكسي عكسي يوجه إلى Anthropic API الحقيقي:
mitmweb --mode reverse:https://API.anthropic.com --listen-port 8000
- يستمع على
http://localhost:8000ويوجه إلىhttps://API.anthropic.com. - يمكنك الوصول إلى الواجهة عبر
http://127.0.0.1:8081لمراجعة التدفقات مباشرة.
3— الثقة بشهادة mitmproxy CA (لـ HTTPS)
تقوم mitmproxy بإنشاء CA محلي لتوقيع شهادات TLS للمضيفين المُعتَرض عليهم. لتجنب أخطاء TLS، يجب عليك الثقة بها مؤقتًا:
- شغّل mitmproxy مرة واحدة — سيقوم بإنشاء الشهادات في
~/.mitmproxy/mitmproxy-ca-cert.pem. - على macOS: افتح Keychain Access →
File → Import Items→ استورد~/.mitmproxy/mitmproxy-ca-cert.pem.- انقر مرتين على الشهادة → Trust → اضبط
Always Trustلـ SSL.
- انقر مرتين على الشهادة → Trust → اضبط
- لـ Firefox أو iOS/Android، استورد CA إلى مخازن الشهادات الخاصة بهم (Firefox يستخدم مخزن شهادات خاص به).
مهم: عند الانتهاء من الاختبار، أزل شهادة mitmproxy CA من مخازن الثقة.
4— توجيه Claude Code إلى mitmproxy
اضبط عنوان URL الأساسي لـ Anthropic إلى عنوان mitmproxy قبل تشغيل Claude Code:
export ANTHROPIC_BASE_URL="http://localhost:8000"
claude
الآن Claude Code → mitmproxy → Anthropic API.
5— ما ستلتقطه
الأمور النموذجية التي ستلتقطها في الطلبات:
- حقل
system: الرسالة النظامية المخفية / قواعد السياسة (النص «المهم: …»). tools: مخطط الأداة (البحث، git، التحرير، إلخ.).messages: رسائل المستخدم / المساعد.
قد تصل الاستجابات بشكل متدفق ومجزأ (قطع JSON جزئية). mitmproxy يعرض محتوى الطلبات والاستجابات بحيث يمكنك حفظها.
6— إضافة جاهزة للتشغيل: استخراج الرسائل النظامية فقط
أنشئ dump_claude_prompts.py بهذا المحتوى. يستخرج حقول system ويضيفها إلى ملف نصي.
# dump_claude_prompts.py
from mitmproxy import http
import json
OUTPUT_FILE = "claude_system_prompts.txt"
def request(flow: http.HTTPFlow):
if "anthropic.com" not in flow.request.pretty_host:
return
try:
body = flow.request.get_text()
data = json.loads(body)
if "system" in data:
system_prompt = data["system"]
with open(OUTPUT_FILE, "a", encoding="utf-8") as f:
f.write("\n=== New System Prompt Captured ===\n")
f.write(system_prompt)
f.write("\n----------------------------------\n")
print(f"[+] Captured system prompt ({len(system_prompt)} chars)")
except Exception as e:
print(f"[!] Error parsing request: {e}")
شغّله:
mitmdump -s dump_claude_prompts.py --mode reverse:https://API.anthropic.com --listen-port 8000
الإخراج: claude_system_prompts.txt يحتوي على كل كتلة system ملتقطة.
7— إضافة موسعة: التقاط موجّهات النظام + تعريفات الأدوات
إذا كنت تريد التقاط كل من موجّهات النظام وتعريفات tools في ملف نصي منظم، استخدم:
# dump_claude_prompts_and_tools.py
from mitmproxy import http
import json
OUTPUT_FILE = "claude_prompts_and_tools.txt"
def request(flow: http.HTTPFlow):
if "anthropic.com" not in flow.request.pretty_host:
return
try:
body = flow.request.get_text()
data = json.loads(body)
with open(OUTPUT_FILE, "a", encoding="utf-8") as f:
f.write("\n==============================\n")
f.write(" NEW CLAUDE REQUEST CAPTURED\n")
f.write("==============================\n\n")
if "system" in data:
f.write("### SYSTEM PROMPT ###\n")
f.write(data["system"].strip())
f.write("\n\n")
if "tools" in data:
f.write("### TOOL DEFINITIONS ###\n")
for tool in data["tools"]:
name = tool.get("name", "<no name>")
desc = tool.get("description", "<no description>")
params = json.dumps(tool.get("parameters", {}), indent=2)
f.write(f"- Tool: {name}\n")
f.write(f" Description: {desc}\n")
f.write(f" Parameters:\n{params}\n\n")
f.write("----------------------------------\n")
print("[+] Captured Claude system + tools")
except Exception as e:
print(f"[!] Error parsing request: {e}")
شغّل:
mitmdump -s dump_claude_prompts_and_tools.py --mode reverse:https://API.anthropic.com --listen-port 8000
مخرجات: claude_prompts_and_tools.txt
8— إضافة متكاملة الميزات: التقاط الطلبات + الاستجابات (منسقة، سجلات موقوتة)
هذه الإضافة الكاملة تُنشئ ملفًا موقوتًا .log لكل زوج طلب/استجابة. احفظ باسم dump_claude_full.py.
# dump_claude_full.py
from mitmproxy import http
import json, os, time
OUTPUT_DIR = "claude_captures"
os.makedirs(OUTPUT_DIR, exist_ok=True)
def _safe_json_parse(text: str):
try:
return json.loads(text)
except Exception:
return None
def _write_section(f, title: str, content: str):
f.write(f"\n### {title} ###\n")
f.write(content.strip() if content else "<empty>")
f.write("\n")
def request(flow: http.HTTPFlow):
if "anthropic.com" not in flow.request.pretty_host:
return
ts = time.strftime("%Y%m%d-%H%M%S")
filename = os.path.join(OUTPUT_DIR, f"claude_{ts}_{flow.id}.log")
body = flow.request.get_text()
data = _safe_json_parse(body)
with open(filename, "w", encoding="utf-8") as f:
f.write("=====================================\n")
f.write(f" CLAUDE REQUEST {time.ctime()}\n")
f.write("=====================================\n")
if data and "system" in data:
_write_section(f, "SYSTEM PROMPT", data["system"])
if data and "tools" in data:
tool_dump = []
for tool in data["tools"]:
name = tool.get("name", "<no name>")
desc = tool.get("description", "<no description>")
params = json.dumps(tool.get("parameters", {}), indent=2)
tool_dump.append(f"- {name}: {desc}\n Params: {params}")
_write_section(f, "TOOLS", "\n".join(tool_dump))
if data and "messages" in data:
messages = []
for msg in data["messages"]:
role = msg.get("role", "?")
content = msg.get("content", "")
messages.append(f"{role.upper()}: {content}")
_write_section(f, "MESSAGES", "\n".join(messages))
f.write("\n--- Waiting for response ---\n")
flow.metadata["dump_file"] = filename
print(f"[+] Captured request → {filename}")
def response(flow: http.HTTPFlow):
if "anthropic.com" not in flow.request.pretty_host:
return
filename = flow.metadata.get("dump_file")
if not filename:
ts = time.strftime("%Y%m%d-%H%M%S")
filename = os.path.join(OUTPUT_DIR, f"claude_{ts}_{flow.id}.log")
text = flow.response.get_text()
data = _safe_json_parse(text)
with open(filename, "a", encoding="utf-8") as f:
f.write("\n=====================================\n")
f.write(f" CLAUDE RESPONSE {time.ctime()}\n")
f.write("=====================================\n")
if data:
formatted = json.dumps(data, indent=2, ensure_ascii=False)
_write_section(f, "RAW JSON RESPONSE", formatted)
else:
_write_section(f, "RAW TEXT RESPONSE", text)
f.write("\n========== END OF CAPTURE ==========\n")
print(f"[+] Appended response → {filename}")
شغّل التقاط:
mitmdump -s dump_claude_full.py --mode reverse:https://API.anthropic.com --listen-port 8000
إخراج: ملف .log واحد لكل طلب في claude_captures/. كل ملف يحتوي على:
SYSTEM PROMPTTOOLSMESSAGESRAW JSON RESPONSEأوRAW TEXT RESPONSE(قطع تدفق مضمنة)
9— محلل: استخراج و إزالة التكرار لمطالبات النظام
استخدم هذا النص البرمجي extract_system_prompts.py لفحص سجلات claude_captures/، استخراج أقسام مطالبات النظام، إزالة التكرار باستخدام SHA-256، و اكتب:
all_system_prompts.txt— مطالبات قابلة للقراءة البشرية (واحد لكل مطالبة فريدة)system_prompts_index.csv— فهرس معfilename,prompt_excerpt,captured_at, وhash.
extract_system_prompts.py (احفظ و شغل):
#!/usr/bin/env python3
import os, re, hashlib, csv, argparse, datetime, json
SYSTEM_HEADING = "### SYSTEM PROMPT ###"
DIVIDER = "\n=== PROMPT ===\n"
def extract_system_from_text(text):
pattern = re.compile(r"###\s*SYSTEM PROMPT\s*###\s*(.*?)\s*(?=###\s*\w+\s*###|$)", re.S|re.I)
m = pattern.search(text)
if m:
return m.group(1).strip()
return None
def scan_directory(dirname):
prompts = []
for root, _, files in os.walk(dirname):
for fname in sorted(files):
if not fname.lower().endswith(".log"):
continue
path = os.path.join(root, fname)
with open(path, "r", encoding="utf-8") as fh:
txt = fh.read()
prompt = extract_system_from_text(txt)
if prompt:
h = hashlib.sha256(prompt.encode("utf-8")).hexdigest()
captured_at = ""
m = re.search(r"claude_(\d{8}-\d{6})", fname)
if m:
try:
captured_at = datetime.datetime.strptime(m.group(1), "%Y%m%d-%H%M%S").isoformat()
except:
pass
prompts.append({"filename": path, "prompt": prompt, "hash": h, "captured_at": captured_at})
return prompts
def save_prompts(prompts, out_txt="all_system_prompts.txt", index_csv="system_prompts_index.csv"):
seen = {}
for p in prompts:
h = p["hash"]
if h not in seen or (p["captured_at"] and p["captured_at"] < seen[h]["captured_at"]):
seen[h] = p
unique = list(seen.values())
unique.sort(key=lambda x: x["captured_at"] or "")
with open(out_txt, "w", encoding="utf-8") as fh:
for u in unique:
fh.write(DIVIDER)
fh.write(f"Source file: {u['filename']}\nCaptured at: {u['captured_at']}\n\n")
fh.write(u["prompt"].strip())
fh.write("\n")
with open(index_csv, "w", newline='', encoding="utf-8") as csvf:
writer = csv.writer(csvf)
writer.writerow(["filename", "captured_at", "prompt_excerpt", "hash"])
for u in unique:
excerpt = u["prompt"].replace("\n", " ")[:200]
writer.writerow([u["filename"], u["captured_at"], excerpt, u["hash"]])
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--dir", default="claude_captures")
parser.add_argument("--out", default="all_system_prompts.txt")
parser.add_argument("--index", default="system_prompts_index.csv")
args = parser.parse_args()
prompts = scan_directory(args.dir)
if not prompts:
print("No system prompts found.")
else:
save_prompts(prompts, out_txt=args.out, index_csv=args.index)
print(f"Saved {len(prompts)} prompt entries to {args.out} and {args.index}")
شغل:
python3 extract_system_prompts.py --dir claude_captures --out all_system_prompts.txt --index system_prompts_index.csv
10— ربط الطلب + الاستجابة في JSON (لإعادة التشغيل/التحليل)
إذا كنت تفضل ربطًا صديقًا للآلة (JSON واحد لكل التقاط + ملف JSON رئيسي)، استخدم سكريبت الربط أدناه. يقرأ ملفات .log المُنتَجة بواسطة dump_claude_full.py، ويحلل الأقسام ويكتب:
paired_captures.json— مصفوفة رئيسية لكائنات التقاطpaired_jsons/*.json— ملفات JSON لكل التقاط
سكريبت الربط (تنفيذ مثال):
# pair_captures.py (concept)
# Pseudo: read .log files from claude_captures, parse headings using regex,
# construct object: {source_file, captured_at, system_prompt, tools (list), messages, raw_response, response_json}
# write per-capture JSONs into paired_jsons/, and a master paired_captures.json.
# (see the earlier detailed pairing code in this guide — you can copy it verbatim or adapt)
يمكنك بعد ذلك:
- استخدم ملفات JSON لكل التقاط لإنشاء طلبات إعادة التشغيل (curl, httpie) أو لإدخالها في منصة اختبار محلية.
- حول التقاطات إلى تنسيق mitmproxy server-replay إذا كنت تريد إعادة تشغيل حركة المرور بدقة دون اتصال.
11— إعادة تشغيل التقاطات (ملاحظة سريعة)
- يدعم mitmproxy server-replay باستخدام التدفقات المسجلة (
mitmdump -w flows.mitmللتسجيل؛--server-replay flows.mitmلإعادة التشغيل). - يُقصد من إخراج ربط JSON للتحليل البرمجي أو سكريبتات إعادة التشغيل المخصصة (curl/requests). لإجراء إعادة تشغيل طلب/استجابة حقيقية بتنسيق mitmproxy، فكر في تسجيل ملفات تدفق
.mitmباستخدامmitmdump -w flows.mitmبدلاً من النصوص العادية.log.
12— حذف الأسرار والتنظيف
قبل مشاركة أو أرشفة السجلات:
- قم بإزالة أو تخفيف قيم الرؤوس (Authorization, Cookies). مثال (مقتطف بايثون):
# naive header redaction example
if "Authorization" in flow.request.headers:
flow.request.headers["Authorization"] = "<REDACTED>"
- قم بإزالة ثقة CA من Keychain بعد الاختبار لاستعادة أمان النظام.
- احتفظ بملفات التقاط في دليل مشفر إذا كانت ستبقى.
13— استكشاف الأخطاء وإصلاحها ونصائح
- أخطاء TLS → ربما لم تثق في CA الخاص بـ mitm أو العميل يربط الشهادات.
- لا يوجد حركة مرور مُلتقطة → تأكد من ضبط
ANTHROPIC_BASE_URLعلىhttp://localhost:8000أو تكوين العميل لاستخدام بروكسي HTTP. - استجابات JSON مجزأة → Anthropic غالبًا ما يبث JSON جزئي؛ يجب على محركات التحليل التعامل مع JSON جزئي/غير صالح بسلاسة (حاول التقاط
RAW TEXT RESPONSEثم إعادة البناء). - شهادة في الأجهزة المحمولة → استورد CA الخاص بـ mitm إلى مخزن الثقة للجهاز؛ بالنسبة لـ iOS، قد تواجه تعقيدات في التخصيص.
- سجلات كبيرة → قم بتدوير السجلات أو ضغطها. فكر في تخزين الحقول المستخرجة فقط (النظام، الأدوات، الرسائل) لتقليل الحجم.
14— مثال لسير العمل (تشغيل كامل)
- ابدأ mitmproxy مع الإضافة الكاملة:
mitmdump -s dump_claude_full.py --mode reverse:https://API.anthropic.com --listen-port 8000
- صدر البيئة وقم بتشغيل Claude Code:
export ANTHROPIC_BASE_URL="http://localhost:8000"
claude
# interact with Claude Code like normal
- بعد الجلسة، أوقف mitmproxy. راجع
claude_captures/للبحث عن ملفات.logذات الطوابع الزمنية. - استخرج محفزات النظام الفريدة:
python3 extract_system_prompts.py --dir claude_captures --out all_system_prompts.txt --index system_prompts_index.csv
- ربط الطلب والاستجابة في JSON:
python3 pair_captures.py # or run the ready pairing script provided above
- قم بتخفيف الأسرار وإزالة CA الخاص بـ mitm من الثقة (تنظيف).
ملاحظات ختامية
هذا سير العمل هو الطريقة التي استخدمها الباحثون والمهندسين لفحص عملاء مثل Claude Code لفهم:
- كيف يتم توصيل محفزات النظام/القيود إلى النموذج، وكيف يتم التعامل مع JSON الجزئي المتدفق، وما هي السياسات التي يضيفها العميل إلى كل طلب.