DEV Community

Cover image for API الخاص بك يزيل بيانات C2PA الوصفية: كيفية كشف ذلك بالاختبار
Yusuf Khalidd
Yusuf Khalidd

Posted on • Originally published at apidog.com

API الخاص بك يزيل بيانات C2PA الوصفية: كيفية كشف ذلك بالاختبار

يقوم Claude الآن بإرفاق بيانات تعريف العزو (provenance metadata) المشفّرة وفق C2PA بالملفات التي ينشئها. وينطبق الأمر نفسه على نماذج الصور من OpenAI وGemini. هذا يعني أن إشارة العزو تصل سليمة إلى نقطة التحميل لأول مرة، لكن سلسلة معالجة الصور لديك قد تحذفها قبل أن يراها أي شخص.

جرّب Apidog اليوم

لا يحدث ذلك بنية سيئة؛ بل يحدث افتراضيًا. فمثلًا، تنشئ sharp().resize() ملفًا جديدًا بلا بيانات تعريف ما لم تطلب الاحتفاظ بها صراحةً. وينطبق ذلك أيضًا على ImageMagick وPillow ومعظم شبكات CDN الخاصة بالصور. يدخل الملف، ويخرج JPEG أصغر، ولا تخبرك السجلات أن بيانات العزو اختفت.

هذه مشكلة قابلة للاختبار. ستتعلم هنا كيف تحدد المرحلة التي تحذف بيانات C2PA، وتثبت ذلك عبر رحلة رفع وتنزيل حقيقية، وتضيف فحصًا في CI يمنع عودة المشكلة. يتولى Apidog تنسيق سيناريو الـ API، بينما يتولى c2patool التحقق من صحة البيانات على مستوى البايت.

ما الذي يتم تدميره بالفعل؟

بيان C2PA هو كتلة موقعة تشفيريًا ومضمّنة داخل حاوية الملف. يسجل من وقّع الأصل وما الذي ادعاه عنه. وبما أنه موقّع، فإن تغيير البايتات دون إعادة التوقيع يكسر التوقيع بطريقة يستطيع أي مدقق اكتشافها.

النقطة المهمة هنا هي حاوية الملف: عندما تعيد كتابة الحاوية، قد يختفي البيان.

العملية هل يبقى البيان افتراضيًا؟
نسخ أو نقل بايت ببايت نعم
sharp().resize().toBuffer() لا
ImageMagick عبر convert أو magick لا
Pillow عبر Image.save() لا
تحويل PNG إلى WebP أو JPEG إلى AVIF لا
التحسين التلقائي في CDN للصور غالبًا لا
لقطة شاشة لا
إعادة الحفظ من محرر صور لا
رفع إلى S3 دون تحويل نعم

كل عنصر في عمود لا هو إجراء شائع في تطبيقات الويب: إنشاء صور مصغرة، توليد صور متجاوبة، التفاوض على التنسيق، أو إزالة EXIF لأسباب الخصوصية. كل خطوة منطقية بمفردها، لكنها قد تنهي سلسلة العزو بصمت.

انتبه أيضًا إلى أن استخدام -strip لإزالة بيانات EXIF قد يكون مقصودًا، لأن EXIF قد يحمل إحداثيات GPS أو أرقامًا تسلسلية للكاميرا. لكن إزالة جميع البيانات الوصفية للتخلص من بيانات الموقع تزيل بيان C2PA كذلك. الحل هو إزالة البيانات الحساسة بشكل انتقائي، لا حذف الكتلة كاملة.

أثبت المشكلة في دقيقتين

قبل تغيير خط الأنابيب، تحقق من وجود المشكلة فعلًا. تحتاج إلى ملف واحد يحتوي على بيان C2PA صالح: يمكنك استخدام صورة أنشأها Claude، أو تنزيل عينة موقعة من Content Authenticity Initiative.

ثبّت أداة CLI المرجعية:

cargo install c2patool
Enter fullscreen mode Exit fullscreen mode

تحقق أولًا من أن العينة تحتوي على بيان صالح:

c2patool fixtures/signed-sample.png
Enter fullscreen mode Exit fullscreen mode

يجب أن يظهر تقرير JSON يتضمن منشئ المطالبة وحالة التوقيع.

الآن مرّر الملف عبر مسار الرفع والتسليم الحقيقيين في تطبيقك:

# ارفع الملف عبر نقطة النهاية الفعلية
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

# نزّل الملف عبر رابط التسليم الذي تستخدمه الواجهة الأمامية
ASSET_URL=$(jq -r '.url' /tmp/upload.json)
curl -sS "$ASSET_URL" -o /tmp/roundtrip.png

# تحقق: هل بقي البيان؟
c2patool /tmp/roundtrip.png
Enter fullscreen mode Exit fullscreen mode

هناك ثلاث نتائج محتملة:

  1. تقرير صالح: نجا البيان، وهذه النتيجة المطلوبة.
  2. لم يتم العثور على بيان: قامت مرحلة في خط المعالجة بتجريد البيان. هذه الحالة الأكثر شيوعًا.
  3. خطأ في التحقق: البيان موجود، لكن توقيعه لم يعد يطابق البايتات الحالية. هذا يعني أن ملفًا عُدّل مع الإبقاء على البيان القديم.

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

حدّد المرحلة التي تحذف البيان

إذا فشل اختبار الذهاب والإياب، لا تخمّن. قسّم خط المعالجة وتحقق باستخدام c2patool بعد كل مرحلة:

c2patool /tmp/after-upload.png
c2patool /tmp/after-resize.png
c2patool /tmp/after-cdn.png
Enter fullscreen mode Exit fullscreen mode

ابدأ بالمشتبه بهم التالية.

1. تغيير الحجم أو إنشاء الصورة المصغرة

هذه هي أكثر نقطة فشل شيوعًا. في sharp، تُحذف البيانات الوصفية افتراضيًا:

// يحذف بيان C2PA
await sharp(input).resize(1200).toFile(output);

// يحتفظ بكتلة البيانات الوصفية
await sharp(input).resize(1200).keepMetadata().toFile(output);
Enter fullscreen mode Exit fullscreen mode

لكن الاحتفاظ بالكتلة وحده لا يكفي. بما أن البكسلات تغيرت، فلن يبقى التوقيع الأصلي صالحًا للبايتات الجديدة.

للحفاظ على سلسلة عزو قابلة للتحقق، يجب أن:

  1. تحتفظ ببيانات C2PA المناسبة.
  2. تعيد توقيع الملف الناتج.
  3. تسجل التحويل كتأكيد إجراء، مثل c2pa.resized.

توفر مكتبات c2pa للغات Rust وPython وJavaScript وC أدوات لتنفيذ ذلك.

2. تحويل التنسيق

تقديم ملفات AVIF أو WebP يعني إنشاء حاوية جديدة. تنطبق القاعدة نفسها:

  • احتفظ بالبيان وأعد توقيع الناتج.
  • أو اقبل انتهاء سلسلة العزو عند هذه الخطوة وصرّح بذلك بوضوح.

3. شبكة CDN

تعيد كثير من شبكات CDN الخاصة بالصور كتابة الملفات عند التسليم، خصوصًا عند تفعيل التحسين التلقائي أو تحويل التنسيق.

لا تختبر الأصل فقط. اختبر دائمًا رابط التسليم الذي يصل إليه المستخدمون:

curl -sS "https://cdn.example.com/images/asset.png?w=1200" \
  -o /tmp/cdn-output.png

c2patool /tmp/cdn-output.png
Enter fullscreen mode Exit fullscreen mode

قد تحصل على نتيجة سليمة عند فحص الأصل، بينما يكون الملف النهائي الذي يتلقاه المستخدم قد فقد بيانات العزو.

4. توحيد الملفات عند الرفع

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

افحص الملف قبل وبعد كل خدمة تحول الملف، وليس فقط قبل الرفع وبعد التنزيل النهائي.

اجعله اختبارًا دائمًا في CI

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

قسّم الاختبار إلى طبقتين: تنسيق رحلة الـ API، ثم التحقق من التوقيع على مستوى البايت.

الطبقة الأولى: رحلة الذهاب والإياب في Apidog

السيناريو بسيط:

  1. ارفع ملفًا موقّعًا.
  2. التقط رابط التسليم من الاستجابة.
  3. اجلب الملف من الرابط الفعلي الذي يستخدمه العميل.
  4. تحقق من استجابة HTTP وحجم الملف.

في Apidog، أنشئ سيناريو اختبار من خطوتين.

الخطوة الأولى: POST /v1/assets

  • أرسل multipart/form-data مع الملف الموقّع.
  • تحقق من الحالة 201.
  • تحقق من مطابقة الاستجابة للمخطط.
  • خزّن رابط الأصل لاستخدامه في الخطوة التالية.

آلية الإعداد مماثلة لما هو موضح في اختبار واجهات برمجة تطبيقات تحميل الملفات.

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://");
});
Enter fullscreen mode Exit fullscreen mode

الخطوة الثانية: 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);
});
Enter fullscreen mode Exit fullscreen mode

فحص الحجم ليس إثباتًا لصحة C2PA، لكنه إشارة منخفضة التكلفة تلتقط حالات إعادة الترميز الواضحة. راجع تأكيدات API لتطبيق أنماط التأكيد المعتادة.

الطبقة الثانية: التحقق على مستوى البايت في CI

التحقق من توقيع C2PA يتطلب تحليل حاوية الملف، وهي مهمة 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
Enter fullscreen mode Exit fullscreen mode

استخدم set -euo pipefail. بدونه، قد يفشل c2patool عند التعامل مع ملف مجرّد من البيانات، بينما يستمر البناء ويظهر باللون الأخضر.

إذا كنت تبدأ باستخدام سيناريوهات Apidog في خط الأنابيب، راجع أتمتة اختبارات API في GitHub Actions.

الطبقة الثالثة، اختيارية: نقطة نهاية للتحقق

إذا كانت بيانات العزو ميزة مرئية للمستخدم وليست مجرد فحص داخلي، أنشئ نقطة نهاية صغيرة في خدمتك تشغّل مكتبة c2pa وتعيد نتيجة منظمة.

بهذه الطريقة:

  • تختبر كل شيء كاستجابة JSON عادية.
  • تحصل الواجهة الأمامية على حالة صريحة بدل التخمين.
  • تستطيع توثيق العقد في OpenAPI والتحقق منه.

مثال للاستجابة:

{
  "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"
  }
}
Enter fullscreen mode Exit fullscreen mode

استخدم ثلاث حالات على الأقل، لا حالتين فقط:

  • verified: يوجد بيان وتوقيعه صالح.
  • absent: لا يوجد بيان.
  • invalid: يوجد بيان، لكن التوقيع لا يطابق الملف.

وأضف unchecked إذا لم يكن المدقق متاحًا، حتى لا يبدو انقطاع الخدمة كأنه نتيجة نظيفة.

وثّق هذا الشكل في تعريف OpenAPI وتحقق منه حتى لا تختفي الحقول أثناء إعادة الهيكلة. راجع كيفية التحقق من مواصفات OpenAPI.

احتفظ بأربع عينات اختبار

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

  1. ملف موقّع صالح: توقع verified. يكشف التجريد غير المقصود للبيانات.
  2. ملف مجرّد: استخدم الصورة نفسها بعد إزالة البيان عبر exiftool -all=. توقع absent، لا خطأ ولا verified.
  3. ملف متلاعب به: غيّر بايتًا واحدًا في ملف موقّع بعد توقيعه. توقع invalid. هذا يثبت أنك تتحقق من التوقيع بدل فحص وجود الكتلة فقط.
  4. تنسيق غير مدعوم: ملف لا يدعم أي بيان أصلًا. توقع absent بشكل نظيف بدل خطأ 500.

هذه الملفات صغيرة وثابتة، لكنها تحول الاختبار من فحص شكلي إلى اختبار له معنى.

لماذا يستحق الأمر؟

هناك ثلاثة أسباب عملية.

ادعاء المنتج: إذا كانت الواجهة تعرض شارة للعزو بينما سلسلة المعالجة تجرد البيانات، فإن الشارة ستكون خاطئة لكل أصل مر بعملية تغيير حجم أو تحويل.

الامتثال: إذا كنت تعتمد على C2PA لأي التزام يتعلق بالمادة 50، فإن البيان المجرّد يعني أن عنصر التحكم لا يعمل. يشرح المادة 50 من قانون الاتحاد الأوروبي للذكاء الاصطناعي لمطوري API مسؤوليات المزوّد والمستخدم.

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

قم بتنزيل Apidog لبناء سيناريو الذهاب والإياب أمام نقاط النهاية الخاصة بك، ثم أضف خطوة c2patool بعدها في CI.

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

هل يؤدي تغيير حجم الصورة إلى إزالة بيانات تعريف C2PA؟

نعم، افتراضيًا في معظم المكتبات الشائعة. يتطلب الاحتفاظ بكتلة البيانات الوصفية إعدادًا صريحًا، ويتطلب الاحتفاظ بتوقيع صالح إعادة توقيع الملف الناتج.

كيف أتحقق من أن الملف يحتوي على بيانات C2PA؟

شغّل:

c2patool <file>
Enter fullscreen mode Exit fullscreen mode

أو ارفع الملف إلى صفحة التحقق من بيانات اعتماد المحتوى.

هل يمكن الاحتفاظ ببيانات C2PA عند تغيير الحجم؟

نعم، لكن ليس بمجرد الاحتفاظ بالبيانات الوصفية. احتفظ بالكتلة ثم أعد توقيع الناتج بتأكيد إجراء مثل c2pa.resized باستخدام إحدى مكتبات c2pa.

هل تقوم شبكات CDN بتجريد بيانات اعتماد المحتوى؟

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

ما الفرق بين البيان المجرّد والبيان غير الصالح؟

البيان المجرّد يعني عدم العثور على بيان، ولا يثبت شيئًا عن أصل الملف. أما البيان غير الصالح فيعني وجود بيان لا يطابق توقيعه البايتات الحالية، ما يشير إلى تغير الملف بعد التوقيع.

هل يستطيع Apidog التحقق من توقيع C2PA مباشرة؟

يتولى Apidog تنسيق رحلة الـ API والتحقق من استجابات HTTP، بما فيها استجابة JSON من نقطة تحقق مخصصة. أما تحليل التوقيع نفسه فهو مهمة c2patool في CI أو مكتبة c2pa داخل خدمتك.

هل يجب إزالة EXIF للخصوصية مع الاحتفاظ بـ C2PA؟

نعم، هذا هو الهدف الصحيح، لكنه يتطلب إزالة انتقائية. الأمر العام مثل -strip قد يزيل EXIF وبيان C2PA معًا؛ أزل كتل EXIF الحساسة فقط واترك بيان C2PA سليمًا.

الخلاصة

قد تصل بيانات تعريف العزو إلى واجهة API سليمة ثم تختفي أثناء تغيير الحجم أو التحويل أو تسليم CDN، دون أن تخبرك المراقبة بأي شيء.

الحل العملي هو:

  1. استخدام ملف موقّع كعينة ثابتة.
  2. رفعه وتنزيله عبر مسار التسليم الحقيقي.
  3. فحص الناتج باستخدام c2patool.
  4. جعل الفحص يفشل البناء عند فقدان البيان أو عدم صلاحية توقيعه.

إعداد يستغرق نحو عشرين دقيقة يحول شارة العزو في واجهتك من ادعاء إلى ضمان تفرضه سلسلة المعالجة فعليًا.

Top comments (0)