💡 Повний робочий приклад доступний на GitHub:
sanitize-office-document-pii-python

Дані, які ніхто не переглядає перед надсиланням

Щоквартальний звіт правління надсилається зовнішньому аудитору. Текст бездоганний; три цикли перевірки це підтвердили. Сам файл — інша історія. Його властивості все ще містять ім’я аналітика, який його склав, менеджера, який його доопрацював, дочірню компанію, що володіє шаблоном, мітку часу LastPrinted з нічі перед дедлайном і ідентифікатор затверджувача SharePoint з внутрішнього процесу підписання. Жодне з цього не з’являється на сторінках. Усе це подорожує разом із файлом.

Видалення PII — це робочий процес GroupDocs.Metadata для Python через .NET, який програмно видаляє ці ідентифікаційні властивості з файлів Word, Excel та PowerPoint. У цій статті порівнюються три підходи, які пропонує API: видалення за тегами для полів ідентифікації, видалення за шаблоном імен для сімей властивостей (коментарі, ревізії) та одноразовий виклик sanitize(), який очищає все. Ви також побачите крок, який пропускає більшість скриптів санітизації, — перевіркове сканування, що доводить, що очистка дійсно пройшла.

Чому метадані PII заслуговують власного конвеєра

Інструменти перевірки вмісту контролюють те, що читають люди. Вони не контролюють те, що зберігає файлові системи, і саме в цьому розриві виникають інциденти з дотриманням вимог. Запит GDPR охоплює персональні дані в полях Author і Manager так само, як і дані в тексті. Юридичне розслідування читає лічильники ревізій і сумарний час редагування, щоб відтворити, як довго обговорювали позиційну записку. Оцінювачі тендерів можуть відтворити структуру вашої організації за властивостями робочого процесу SharePoint, а поля коментарів у прес‑релізах зберігають імена рецензентів разом із зауваженнями на етапі чернетки. Кожен з цих елементів — знахідка. Жоден з них не видно у тілі документа.

Передумови

Перш ніж розпочати, переконайтеся, що у вас є:

  • Python 3 з pip
  • GroupDocs.Metadata для Python через .NET, зафіксований у прикладі репозиторію на версію 26.5
  • Office‑файл із реальними властивостями для практики

Встановлення

pip install groupdocs-metadata-net==26.5

[companion repository] (https://github.com/groupdocs-metadata/sanitize-office-document-pii-python) надає зразковий DOCX і виконує кожен фрагмент коду як підтверджений конвеєр.

Метод 1: Видалення ідентифікації за допомогою тегів

Чотири найчутливіші поля — Author, LastSavedBy, Manager і Company — мають різні внутрішні назви у різних форматах Office. Система тегів вирішує цю проблему: замість називання властивостей предикат запитує все, що позначено тегом «особа» або «компанія».

# Match identity properties by meaning, not by format-specific name
with Metadata("board-report.docx") as metadata:
    removed = metadata.remove_properties(lambda p:
        Tags.person.creator in list(p.tags)     # Author, LastSavedBy
        or Tags.person.editor in list(p.tags)
        or Tags.person.manager in list(p.tags)
        or Tags.corporate.company in list(p.tags))
    metadata.save("board-report-clean.docx")

print(f"{removed} identity properties removed")

Ключові моменти:

  • Незалежність від формату: одна й та сама lambda очищає DOCX, XLSX і PPTX, бо теги класифікують за роллю.
  • Вимірюваний результат: remove_properties повертає кількість властивостей, що підпали під умову, що можна записати у ваш журнал аудиту.
  • Семантика копіювання: збереження у новий шлях залишає оригінал для ваших записів.

💡 Порада: цей проход зберігає Title, Subject та інші описові поля, тому файл залишається зручним для пошуку та індексації DMS.

Метод 2: Видалення за шаблоном імен для сімей властивостей

Теги охоплюють класифіковані концепції. Окремі сім’ї «протіканих» полів живуть поза цією класифікацією: властивості коментарів, лічильники ревізій, штампи робочих процесів SharePoint. Для них треба підходити до назви властивості безпосередньо.

# Comment fields often live in custom properties the tag system
# does not classify, so match them by name substring
with Metadata("board-report.docx") as metadata:
    removed = metadata.remove_properties(lambda p:
        p.name is not None and (
            "Comment" in p.name
            or "Reviewer" in p.name
            or "Reviewed" in p.name))
    metadata.save("board-report-no-comments.docx")

Ту ж саму схему можна застосувати до інших двох сімей; змінюються лише підрядки:

Сім’я Підрядки для збігу
Слід ревізій Revision, TrackedChange, LastPrinted, TotalEditingTime, EditTime
Сервер / робочий процес Server, Workflow, Approver, ContentType, Template

Це обмінює точність на охоплення: "Comment" також ловить Comments і CommentCount, що зазвичай і потрібно під час санітизації. Широкі підрядки можуть збігатися з безпечними полями шаблону, тому аудитуйте повернуту кількість у відповідності до очікувань.

💡 Порада: запускайте кожну сім’ю окремим проходом, коли ваш журнал аудиту потребує підрахунку за категоріями; об’єднуйте підрядки в один предикат, якщо це не потрібно.

Метод 3: Одноразове повне очищення

Коли файл залишає організацію і нічого в шарі метаданих не повинно залишитися, відмовтеся від предикатів.

# One call, every detected metadata package
with Metadata("board-report.docx") as metadata:
    removed = metadata.sanitize()
    metadata.save("board-report-final.docx")

print(f"sanitize() removed {removed} properties")

sanitize() стирає кожен пакет, який бібліотека виявляє: поля ідентифікації у document‑info, коментарі, історію ревізій, авторів відстежуваних змін та користувацькі частини OOXML. Поведінка задокументована на сторінці Clean metadata. Сила цього методу — його вартість. Title і Subject зникають разом із PII, тому його слід застосовувати на виході, а не посеред процесу спільної роботи.

Чи потрібні мені всі чотири цільові проходи?

Ні. Кожен проход існує, бо за ризиком відповідає різна команда. Поля ідентифікації турбують офіцерів конфіденційності, сліди коментарів — юридичний відділ, лічильники ревізій — переговорники, а серверні поля — безпеку. Запускайте ті проходи, що відповідають вашим ревізорам, у будь‑якому порядку, бо кожен створює власну копію виходу. Коли жодне поле не потрібно залишати, переходьте одразу до sanitize() і перевіряйте результат.

Порівняння трьох підходів

Метод Краще підходить для Ключові переваги Обмеження
Видалення за тегами Робочі копії, багатоформатні конвеєри Незалежність від формату, зберігає описові поля Покриває лише концепції, класифіковані за тегами
Видалення за шаблоном імен Коментарі, ревізії, серверні поля Досягає користувацьких властивостей, які пропускаються тегами Підрядки потребують налаштування для кожного середовища
Повне sanitize() Остаточний експорт за межі організації Не пропустить забуту властивість Також стирає безпечні поля

Підходи природно комбінуються: цільові проходи під час «життя» документа, sanitize() — коли він відправляється.

Перевірте, перш ніж довіряти

Повернення кількості видалених властивостей не є доказом чистоти файлу. Репозиторій завершує кожен запуск повторним відкриттям очищеного виходу та скануванням його за допомогою find_properties, використовуючи предикат, що об’єднує правила тегів і імен з усіх попередніх проходів.

def is_pii(p):
    if p.name is None:
        return False
    return (
        Tags.person.creator in list(p.tags)
        or Tags.person.editor in list(p.tags)
        or Tags.person.manager in list(p.tags)
        or Tags.corporate.company in list(p.tags)
        or any(n in p.name for n in (
            "Comment", "Reviewer", "Revision", "TrackedChange",
            "Classification", "Department", "Server", "Workflow")))

with Metadata("board-report-final.docx") as metadata:
    for p in metadata.find_properties(is_pii):
        value = (str(p.interpreted_value) if p.interpreted_value is not None
                 else (str(p.value) if p.value is not None else ""))
        if value and value not in ("0", "0.0"):
            print(f"LEAK {p.name}={value}")

Повна версія в репозиторії розподіляє залишки у два «кошики», і ця різниця має значення. Протікання метаданих має бути нульовим. Залишки на рівні вмісту — коментарі Word‑балони та відстежувані зміни у word/document.xml — це вже вміст тіла, до якого API метаданих не має доступу; їх видалення вимагає бібліотеки редагування вмісту, наприклад Aspose.Words. Чесний звіт називає обидва «кошики», а не оголошує перемогу після першого. Перший раз, коли я запустив це сканування на «чистому» файлі, він виявив поле Department, яке корпоративний шаблон тихо додав протягом місяців.

Кращі практики та поради

  • Санітізуйте копії, ніколи оригінали: кожен фрагмент коду тут записує у новий шлях, залишаючи джерело для ваших записів і правил зберігання.
  • Логуйте кількості: значення, що повертаються remove_properties і sanitize(), — це ваш аудиторський слід. Зберігайте їх по файлу, по проходу.
  • Інтегруйте перевірку в CI: перевірка на витік, що провалює збірку, ловить регресії шаблонів у той же день, коли вони виникають, а не коли клієнт їх помітить.
  • Слідкуйте за межою метаданих/вмісту: ніколи не повідомляйте файл «чистим», коли залишаються коментарі в тілі; виводьте їх як окрему знахідку.
  • Ліцензування: режим оцінки відтворює все, що описано в статті; використовуйте ліцензію у продакшені, щоб жодні позначки оцінки не потрапляли у вихідні файли.

Висновок

Три підходи, одне правило вибору. Використовуйте теги, коли концепція класифікована і файл має залишатися корисним. Використовуйте імена, коли сім’я живе в користувацьких властивостях. Викликайте sanitize(), коли файл перетинає межу довіри, і перевіряйте результат скануванням, яким би шляхом ви не пішли.

Готові заглибитися? Наступні кроки:

Додаткові ресурси

Маєте питання або хочете поділитися реалізацією? Звертайтеся у support forum.