يقوم Claude الآن بإرفاق بيانات تعريف العزو (provenance metadata) المشفرة من C2PA بالملفات التي يقوم بإنشائها. وكذلك تفعل نماذج صور OpenAI، وكذلك Gemini. وهذا يعني أن إشارة عزو حقيقية تصل إلى نقطة تحميلك لأول مرة، وهناك احتمال كبير أن تقوم سلسلة المعالجة الخاصة بك بحذفها قبل أن يراها أحد.
ليس بقصد سيء. بل بشكل افتراضي. تنتج الدالة sharp().resize() ملفًا نظيفًا بدون بيانات تعريف ما لم تطلب غير ذلك. وكذلك ImageMagick. وكذلك Pillow. وكذلك معظم شبكات توصيل المحتوى (CDNs) للصور. يدخل البيان، ويخرج ملف JPEG أصغر، ولا يذكر سجلاتك أي شيء عن ذلك.
هذا فشل قابل للاختبار، والاختبار ليس معقدًا. إليك كيفية موت بيانات التعريف في سلسلة معالجة عادية، وكيفية إثبات حدوث ذلك، وكيفية ربط فحص ذهاب وعودة في CI بحيث لا يعود. تتولى Apidog التنسيق؛ ويتولى c2patool التحقق على مستوى البايت.
ما الذي يتم تدميره بالفعل
بيان C2PA هو كتلة موقعة تشفيريًا مدمجة في حاوية الملف. يسجل من قام بتوقيع الأصل وما تم الإدعاء به بشأنه، ولأنه موقع، فإن تغيير البايتات دون إعادة التوقيع يكسر التوقيع بطريقة يمكن لأي قارئ اكتشافها.
مستوى الحاوية هو العبارة الأساسية. أعد كتابة الحاوية وسيختفي البيان.
| العملية | هل يتبقى البيان افتراضيًا؟ |
|---|---|
| نسخ أو نقل بايت ببايت | نعم |
sharp().resize().toBuffer() |
لا |
ImageMagick convert / magick |
لا |
Pillow Image.save() |
لا |
| PNG إلى WebP، JPEG إلى AVIF | لا |
| تحسين تلقائي لـ CDN للصور | عادةً لا |
| لقطة شاشة | لا |
| إعادة حفظ من محرر صور | لا |
| تحميل S3 بدون تحويل | نعم |
كل شيء في عمود "لا" هو أمر يفعله تطبيق ويب عادي لكل صورة يقبلها. صور مصغرة، متغيرات سريعة الاستجابة، تفاوض التنسيق، مسح بيانات EXIF للخصوصية. كل منها معقول بشكل منفصل، وكل منها ينهي سلسلة العزو بصمت.
تجدر الإشارة: غالبًا ما تكون عادة -strip التي تحركها الخصوصية متعمدة، لأن EXIF يحمل إحداثيات GPS وأرقام تسلسل الكاميرا. يؤدي تجريد جميع البيانات الوصفية لإزالة بيانات الموقع إلى إزالة بيان العزو أيضًا. تتعارض هذه الأهداف الآن، وحلها يعني أن تكون انتقائيًا بدلاً من تدمير الكتلة بأكملها.
أثبت ذلك في دقيقتين
قبل بناء أي شيء، تأكد من أن لديك المشكلة. تحتاج إلى ملف واحد ببيان صالح. أي صورة ينشئها Claude تعمل، أو احصل على عينة موقعة من مبادرة أصالة المحتوى (Content Authenticity Initiative).
قم بتثبيت واجهة سطر الأوامر المرجعية (CLI):
cargo install c2patool
تحقق من أن المُركب موقع بالفعل:
c2patool fixtures/signed-sample.png
يجب أن تحصل على تقرير JSON يذكر منشئ المطالبة وحالة التوقيع. الآن قم بتمريره عبر مكدسك الخاص وتحقق من الطرف الآخر:
# Upload through your real endpoint
curl -sS -X POST https://api.example.com/v1/assets \
-H "Authorization: Bearer $API_TOKEN" \
-F "file=@fixtures/signed-sample.png" \
-o /tmp/upload.json
# Fetch it back through the URL your frontend would use
ASSET_URL=$(jq -r '.url' /tmp/upload.json)
curl -sS "$ASSET_URL" -o /tmp/roundtrip.png
# Did the manifest survive?
c2patool /tmp/roundtrip.png
ثلاث نتائج محتملة، وهي تعني أشياء مختلفة:
- تقرير صالح. نجا البيان. جيد.
- لم يتم العثور على بيان. قام شيء في سلسلة المعالجة الخاصة بك بتجريده. هذه هي الحالة الشائعة.
- خطأ في التحقق. يوجد بيان ولكن توقيعه لم يعد يتطابق مع البايتات. قام شيء ما بتعديل الملف وترك البيان القديم مرفقًا، وهو أسوأ من تجريده، لأنه يبدو كتلاعب لأي مدقق لاحق.
النتيجة الثالثة هي التي يجب البحث عنها. عادة ما تعني أن مكتبة التحويل احتفظت بكتلة البيانات الوصفية أثناء إعادة كتابة البكسلات.
ابحث عن الخطوة التي تفعل ذلك
إذا فشلت الرحلة ذهابًا وإيابًا، قم بتقسيم خط الأنابيب. تحقق من البيان فورًا بعد كل مرحلة بدلاً من التخمين.
المشتبه بهم النموذجيون حسب ترتيب الاحتمال:
1. خطوة تغيير الحجم أو الصورة المصغرة. الجاني الأكثر احتمالاً. في sharp، يتم إسقاط البيانات الوصفية ما لم تحتفظ بها صراحة:
// Drops the C2PA manifest
await sharp(input).resize(1200).toFile(output);
// Preserves the metadata block
await sharp(input).resize(1200).keepMetadata().toFile(output);
الحفاظ على الكتلة ضروري ولكنه غير كافٍ. تغيرت البكسلات، لذا لم يعد التوقيع الأصلي صالحًا مقابل البايتات الجديدة. للحفاظ على سلسلة عزو عاملة، يجب عليك إعادة توقيع المخرجات وتسجيل التحويل كتأكيد إجراء، عادةً c2pa.resized. تدعم مكتبات c2pa لـ Rust و Python و JavaScript و C كل هذا.
2. تحويل التنسيق. يعني تقديم AVIF أو WebP حاوية جديدة. نفس القاعدة: حافظ وأعد التوقيع، أو اقبل أن السلسلة تنتهي هناك وصرح بذلك.
3. شبكة توصيل المحتوى (CDN). تعيد العديد من شبكات CDN للصور الكتابة عند التسليم. بعضها الآن يحافظ ويعيد توقيع Content Credentials بشكل أصلي؛ وقد قامت معظمها تاريخيًا بتجريدها. اختبر عبر عنوان URL التسليم الذي يصل إليه المستخدمون فعليًا، وليس عبر الأصل، وإلا ستحصل على نتيجة خضراء لا تعني شيئًا.
4. توحيد التحميل. الخدمات التي تعيد الترميز عند الاستيعاب لتوحيد التنسيقات من السهل نسيانها، لأن الكود موجود في مستودع بنية تحتية لا يقرأه أحد.
اجعله اختبارًا دائمًا
يُثبت أمر curl لمرة واحدة الحالة اليوم. ولكنه لا يمنع أي شخص من إضافة خطوة لتغيير الحجم في السبرنت التالي. يجب أن يعيش الفحص في CI.
قسّمه إلى طبقتين، لأن أداتين مختلفتين جيدتان في شيئين مختلفين.
الطبقة الأولى: الرحلة ذهابًا وإيابًا، في Apidog
التنسيق هو اختبار API متسلسل عادي: تحميل مُركب، التقاط عنوان URL المُعاد، جلب الأصل مرة أخرى عبر مسار التسليم الحقيقي، التأكيد على ما يتم إرجاعه.
في Apidog، هذا سيناريو اختبار بخطوتين.
الخطوة 1: POST /v1/assets
- الجسم:
multipart/form-dataمع مُركبك الموقّع المرفق. الآليات هي نفسها كما في اختبار واجهات برمجة تطبيقات تحميل الملفات. - التأكيدات: الحالة هي
201، والاستجابة تتطابق مع مخططك. - نص برمجي بعد الاستجابة لتسليم عنوان URL إلى الخطوة التالية:
const body = pm.response.json();
pm.environment.set("ASSET_URL", body.url);
pm.test("upload returns a delivery URL", function () {
pm.expect(body.url).to.be.a("string").and.to.include("https://");
});
الخطوة 2: GET {{ASSET_URL}}
- التأكيدات: الحالة هي
200،Content-Typeهو التنسيق الذي تتوقعه، وحجم الجسم قريب مما قمت بتحميله. الانخفاض الكبير في الحجم هو تلميح قوي بأن الملف قد أعيد ترميزه.
const uploadedBytes = Number(pm.environment.get("FIXTURE_BYTES"));
const returnedBytes = pm.response.responseSize;
pm.test("asset was not silently re-encoded", function () {
pm.expect(returnedBytes).to.be.above(uploadedBytes * 0.9);
});
الحجم هو تقدير، وليس إثباتًا. إنه يلتقط الإخفاقات الصارخة بتكلفة منخفضة ويعمل في نفس المجموعة مثل أي شيء آخر. يتم تغطية أنماط التأكيد القياسية في تأكيدات API.
الطبقة الثانية: التحقق على مستوى البايت، في CI
التحقق من التوقيع يعني تحليل الحاوية، وهي مهمة c2patool، وليست مهمة عميل HTTP. قم بتشغيلها كخطوة في خط الأنابيب مقابل الملف الذي تم جلبه في الرحلة ذهابًا وإيابًا:
# .github/workflows/provenance.yml
name: provenance
on: [pull_request]
jobs:
c2pa-round-trip:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install c2patool
run: cargo install c2patool
- name: Install Apidog CLI
run: npm install -g apidog-cli
- name: Run the round-trip scenario
run: |
apidog run --access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" -e "$ENV_ID" -r cli,html --out-dir ./apidog-reports
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
SCENARIO_ID: ${{ vars.PROVENANCE_SCENARIO_ID }}
ENV_ID: ${{ vars.APIDOG_ENV_ID }}
- name: Verify the manifest survived
run: |
set -euo pipefail
curl -sS "$ASSET_URL" -o /tmp/roundtrip.png
c2patool /tmp/roundtrip.png > /tmp/report.json
jq -e '.validation_status == null or (.validation_status | length) == 0' /tmp/report.json
يُعد set -euo pipefail مهمًا. بدونه، يؤدي فشل c2patool في ملف مُجرد إلى تحذير وبناء أخضر، وهو الفشل المحدد الذي كنت تحاول منعه. إذا كنت جديدًا في تشغيل سيناريوهات Apidog في خط أنابيب، فإن أتمتة اختبارات API في GitHub Actions تغطي الإعداد.
الطبقة الثالثة، اختيارية: نقطة نهاية للتحقق
إذا كانت بيانات العزو (provenance) ميزة في المنتج وليست فحصًا داخليًا، فإن أنظف تصميم هو نقطة نهاية صغيرة في خدمتك الخاصة تقوم بتشغيل مكتبة c2pa وتُرجع نتيجة منظمة. عندئذٍ يكون كل شيء قابلًا للاختبار كـ JSON عادي، وتحصل واجهة المستخدم الأمامية (frontend) الخاصة بك على إجابة حقيقية بدلاً من تخمين.
{
"asset_id": "img_9f2c41",
"provenance": {
"status": "verified",
"standard": "c2pa",
"signer": "Anthropic",
"signature_valid": true,
"checked_at": "2026-08-11T09:14:22Z",
"tool": "c2patool/0.9"
}
}
احتفظ بثلاث حالات، لا اثنتين. تشير verified و absent و invalid إلى أشياء مختلفة تمامًا، ويؤدي دمج absent و invalid في قيمة منطقية واحدة إلى التخلص من الإشارة الأكثر إثارة للاهتمام التي لديك. أضف unchecked إذا كان المدقق الخاص بك غير متاح، بحيث لا يتنكر الانقطاع على أنه نتيجة نظيفة.
وثّق الشكل في تعريف OpenAPI الخاص بك وتحقق منه، حتى لا تختفي الحقول في عملية إعادة هيكلة. كيفية التحقق من مواصفات OpenAPI تغطي هذا الجانب.
التركيبات الأربعة التي تستحق الاحتفاظ بها
تحتاج مجموعة بيانات العزو (provenance) إلى مدخلات معيبة عمدًا، وليس فقط مسارًا سعيدًا.
- ملف موقع صالح. توقع
verified. يلتقط التجريد المفرط الحماس. - ملف مجرد. نفس الصورة، تم إزالة البيان باستخدام
exiftool -all=. توقعabsent، وليس خطأ وبالتأكيد ليسverified. - ملف مُتلاعب به. ملف موقع مع تغيير بايت واحد بعد التوقيع. توقع
invalid. هذا هو الذي يثبت أنك تتحقق من التوقيع بدلاً من مجرد التحقق من وجود كتلة. - تنسيق غير مدعوم. شيء لا يدعم أي بيان على الإطلاق. توقع
absentنظيف بدلاً من 500.
التزم بجميع الأربعة في المستودع بجوار سيناريو الاختبار. إنها صغيرة، ولا تتغير أبدًا، وهي الفرق بين اختبار يمر واختبار له معنى.
لماذا العناء
ثلاثة أسباب، بترتيب تصاعدي لتكلفة كل منها عليك.
ادعاء منتجك. إذا كانت واجهة المستخدم الخاصة بك تعرض شارة العزو (provenance)، وسلسلة المعالجة الخاصة بك تجرد البيانات، فإن الشارة ستكون خاطئة لكل أصل مر بتغيير حجم. هذه مشكلة ثقة ستكتشفها من مستخدم.
قصة الامتثال الخاصة بك. إذا كنت تعتمد على C2PA لأي شيء يتعلق بالمادة 50، فإن البيان المجرد هو عنصر تحكم لا يعمل. يوضح تقسيم الموفر والمستخدم في المادة 50 من قانون الاتحاد الأوروبي للذكاء الاصطناعي لمطوري API الواجبات التي تقع عليك بالفعل.
الإشارة نفسها. يعمل العزو (Provenance) فقط إذا استمرت السلسلة من البداية إلى النهاية. كل سلسلة معالجة تسقط البيانات بصمت تجعل النظام البيئي بأكمله أقل فائدة، بما في ذلك لك عندما تحاول التحقق من شيء ما.
قم بتنزيل Apidog لبناء سيناريو الرحلة ذهابًا وإيابًا مقابل نقاط النهاية الخاصة بك، ثم قم بربط خطوة c2patool خلفها.
الأسئلة الشائعة
هل يؤدي تغيير حجم الصورة إلى إزالة بيانات تعريف C2PA؟ نعم، بشكل افتراضي في كل مكتبة شائعة. يتطلب الحفاظ على كتلة البيانات التعريفية علامة صريحة، ويتطلب الحفاظ على توقيع صالح إعادة توقيع المخرج المحول.
كيف أتحقق مما إذا كان الملف يحتوي على بيانات تعريف C2PA؟ قم بتشغيل c2patool <file> من سطر الأوامر، أو قم بإسقاط الملف في صفحة التحقق من بيانات اعتماد المحتوى.
هل يمكنني الاحتفاظ ببيانات تعريف C2PA عند تغيير الحجم؟ نعم، ولكن ليس بمجرد الحفاظ عليها. احتفظ بالكتلة، ثم أعد توقيع المخرج بتأكيد إجراء مثل c2pa.resized باستخدام إحدى مكتبات c2pa. وإلا فلن يتطابق التوقيع القديم مع البايتات الجديدة.
هل تقوم شبكات توصيل المحتوى (CDNs) بتجريد بيانات اعتماد المحتوى؟ يفعل الكثير منها عند التحسين التلقائي. بعضها الآن يحافظ ويعيد التوقيع بشكل أصلي. اختبر عبر عنوان URL التسليم الذي يصل إليه المستخدمون، وليس عبر المصدر.
ما الفرق بين البيان المجرد والبيان غير الصالح؟ البيان المجرد يعني عدم العثور على بيان، وهذا لا يخبرك شيئًا عن أصل الملف. البيان غير الصالح يعني وجود بيان ولكن توقيعه لا يتطابق مع البايتات، مما يعني أن الملف تغير بعد التوقيع. احتفظ بهما كحالتين منفصلتين.
هل يمكن لـ Apidog التحقق من توقيع C2PA مباشرة؟ يقوم بتنسيق الرحلة ذهابًا وإيابًا ويؤكد على استجابات HTTP، بما في ذلك JSON الخاص بنقطة نهاية التحقق. تحليل التوقيع نفسه هو مهمة c2patool، يتم تشغيلها كخطوة CI أو داخل خدمتك الخاصة. استخدم كليهما معًا.
هل يجب علي تجريد EXIF للخصوصية ولكن الاحتفاظ بـ C2PA؟ هذا هو الهدف الصحيح ويتطلب نهجًا انتقائيًا. يزيل الأمر الشامل -strip كليهما. قم بإزالة كتل EXIF التي تهتم بها على وجه التحديد واترك بيان C2PA سليمًا.
الخلاصة
تصل بيانات تعريف العزو (provenance metadata) إلى واجهة برمجة التطبيقات الخاصة بك سليمة وعادة ما تغادر في أجزاء، ولن يخبرك أي شيء في مراقبتك بذلك. الحل هو مُركب، رحلة ذهاب وعودة عبر مسار التسليم الحقيقي، وفحص c2patool يفشل البناء.
عشرون دقيقة من الإعداد، وتحول ادعاء تقدمه في واجهة المستخدم الخاصة بك إلى ضمان تفرضه سلسلة المعالجة الخاصة بك بالفعل.
