💡 Volledig werkend voorbeeld beschikbaar op GitHub:
sanitize-office-document-pii-python
De gegevens die niemand controleert voordat hij op Verzenden drukt
Een kwartaalrapport voor de raad wordt naar een externe auditor gestuurd. De tekst is vlekkeloos; drie beoordelingscycli hebben dat verzekerd. Het bestand zelf vertelt een ander verhaal. De eigenschappen vermelden nog steeds de analist die het heeft opgesteld, de manager die het heeft herwerkt, de dochteronderneming die het sjabloon bezit, een LastPrinted‑tijdstempel van de avond vóór de deadline, en een SharePoint‑goedkeurder‑ID uit de interne ondertekeningsworkflow. Niets hiervan verschijnt op een pagina. Alles reist mee met het bestand.
PII‑verwijdering is een GroupDocs.Metadata‑workflow voor Python via .NET die deze identiteitsdragende eigenschappen van Word-, Excel- en PowerPoint‑bestanden programmatically verwijdert. Dit artikel vergelijkt de drie benaderingen die de API biedt: tag‑gedreven verwijdering voor identiteitsvelden, naam‑patroonverwijdering voor eigenschapsfamilies zoals opmerkingen en revisies, en de één‑oproep sanitize() die alles opruimt. Je ziet ook de stap die de meeste sanitisatiescripts overslaan, een verificatiescan die bewijst dat de opruiming daadwerkelijk heeft plaatsgevonden.
Waarom metadata‑PII een eigen pijplijn verdient
Inhouds‑reviewtools controleren wat mensen lezen. Ze controleren niet wat bestandssystemen opslaan, en die kloof is waar compliance‑incidenten ontstaan. Een GDPR‑verzoek omvat persoonsgegevens in de velden Author en Manager net zo goed als gegevens in de tekst. Juridische ontdekking leest revisietellers en bewerkingstijdtotalen om te reconstrueren hoe lang een position paper werd onderhandeld. Aanbestedings‑reviewers kunnen je organisatiestructuur afleiden uit SharePoint‑workflow‑eigenschappen, en de commentaarvelden van een persbericht bewaren de namen van reviewers naast concept‑opmerkingen. Elk daarvan is een bevinding. Geen van hen is zichtbaar in de documentinhoud.
Voorvereisten
Zorg ervoor dat je het volgende hebt voordat je begint:
- Python 3 met pip
- GroupDocs.Metadata voor Python via .NET, vastgezet in de voorbeeld‑repository op versie 26.5
- Een Office‑bestand met echte eigenschappen om op te oefenen
Installatie
pip install groupdocs-metadata-net==26.5
De companion repository levert een voorbeeld‑DOCX en voert elk fragment hieronder uit als een geverifieerde pijplijn.
Methode 1: Tag‑gedreven identiteitsverwijdering
De vier meest gevoelige velden, Author, LastSavedBy, Manager en Company, hebben verschillende interne namen in Office‑formaten. Het tagsysteem lost dit op: in plaats van eigenschappen te benoemen, vraagt de predicaat om alles dat gemarkeerd is als een persoon of een bedrijf.
# 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")
Belangrijke punten:
- Formaatonafhankelijkheid: dezelfde lambda reinigt DOCX, XLSX en PPTX omdat tags klassificeren op rol.
- Telbaar resultaat:
remove_propertiesgeeft terug hoeveel eigenschappen overeenkwamen, wat in je auditlog moet worden opgenomen. - Kopie‑semantiek: opslaan naar een nieuw pad behoudt het origineel voor je administratie.
💡 Tip: deze stap behoudt Title, Subject en andere beschrijvende velden, zodat het bestand vriendelijk blijft voor zoeken en DMS‑indexering.
Methode 2: Naam‑patroonverwijdering voor eigenschapsfamilies
Tags dekken geclassificeerde concepten. Hele families van lekgevoelige velden zitten buiten die classificatie: commentaareigenschappen, revisietellers, SharePoint‑workflow‑stempels. Voor deze match je op de eigenschapsnaam zelf.
# 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")
Dezelfde structuur behandelt de andere twee families; alleen de lijst met substrings verandert:
| Familie | Substrings om te matchen |
|---|---|
| Revisietracé | Revision, TrackedChange, LastPrinted, TotalEditingTime, EditTime |
| Server / workflow | Server, Workflow, Approver, ContentType, Template |
Dit ruilt precisie in voor bereik: "Comment" vangt ook Comments en CommentCount, wat meestal is wat een sanitisatie‑pass wil. Brede substrings kunnen onschuldige sjabloonvelden ook treffen, dus controleer het geretourneerde aantal tegen je verwachtingen.
💡 Tip: voer elke familie als een eigen pass uit wanneer je auditlog per‑categorie‑aantallen nodig heeft; voeg de substrings samen in één predicaat wanneer dat niet nodig is.
Methode 3: De één‑oproep volledige sanitatie
Wanneer het bestand de organisatie verlaat en niets in de metadata‑laag mag overleven, stop dan met het schrijven van predicaten.
# 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() wist elk pakket dat de bibliotheek detecteert: document‑info‑identiteitsvelden, opmerkingen, revisiegeschiedenis, auteurs van tracked changes en aangepaste OOXML‑onderdelen. Het gedrag wordt gedocumenteerd op de pagina Clean metadata. De sterkte is ook de kost. Title en Subject verdwijnen samen met de PII, waardoor het beter geschikt is voor de export‑poort dan voor het midden van een samenwerkingsworkflow.
Heb ik alle vier gerichte passes nodig?
Nee. Elke pass bestaat omdat een ander team het risico bezit. Identiteitsvelden storen privacy‑officieren, commentaarsporen storen juridische, revisietellers storen onderhandelaren, en server‑velden storen beveiliging. Voer de passes uit die bij je reviewers passen, in welke volgorde dan ook, want elke pass schrijft zijn eigen output‑kopie. Wanneer niemand overlevende velden nodig heeft, ga direct naar sanitize() en verifieer.
Vergelijking van de drie benaderingen
| Methode | Beste voor | Belangrijkste voordelen | Beperkingen |
|---|---|---|---|
| Tag‑gedreven verwijdering | Werkende kopieën, multi‑formaat pijplijnen | Formaat‑onafhankelijk, behoudt beschrijvende velden | Dekken alleen tag‑geclassificeerde concepten |
| Naam‑patroonverwijdering | Opmerkingen, revisies, server‑velden | Bereikt aangepaste eigenschappen die tags missen | Substrings moeten per omgeving worden afgestemd |
Volledige sanitize() |
Definitieve export buiten de organisatie | Kan geen vergeten eigenschap missen | Verwijdert ook onschuldige velden |
De benaderingen combineren zich natuurlijk: gerichte passes terwijl het document leeft, sanitize() wanneer het wordt verzonden.
Verifieer voordat je erop vertrouwt
Een verwijderingsaanroep die een aantal teruggeeft, is geen bewijs dat het bestand schoon is. De repository sluit elke run af door de gesaniteerde output opnieuw te openen en te scannen met find_properties, gebruikmakend van een predicaat dat de tag‑regels en naam‑regels van alle bovenstaande passes combineert.
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}")
De volledige versie in de repository sorteert overgebleven items in twee bakken, en dat onderscheid is belangrijk. Metadata‑lekken moeten nul zijn. Restanten op inhoudsniveau, Word‑commentaarballonnen en tracked changes die zich binnen word/document.xml bevinden, zijn body‑content die een metadata‑API niet kan bereiken; het verwijderen daarvan vereist een content‑bewerkingsbibliotheek zoals Aspose.Words. Een eerlijk rapport noemt beide bakken in plaats van de overwinning alleen op de eerste te verklaren. De eerste keer dat ik deze scan op een “schone” file draaide, markeerde hij een Department‑veld dat een bedrijfs‑sjabloon stilletjes maandenlang had toegevoegd.
Best practices en tips
- Sanitiseer kopieën, nooit originelen: elk fragment hier schrijft naar een nieuw pad, zodat de bron behouden blijft voor je administratie en retentie‑regels.
- Log de aantallen: de retourwaarden van
remove_propertiesensanitize()vormen je auditspoor. Bewaar ze per bestand, per pass. - Integreer verificatie in CI: een lek‑check die de build faalt, vangt sjabloon‑regressies op de dag dat ze gebeuren, niet op de dag dat een klant het opmerkt.
- Let op de grens tussen metadata en content: rapporteer een bestand nooit als schoon terwijl body‑level opmerkingen blijven; breng ze als een afzonderlijke bevinding naar voren.
- Licenties: evaluatiemodus reproduceert alles in dit artikel; gebruik een licentie in productie zodat er geen evaluatiemerkjes op uitgaande bestanden staan.
Conclusie
Drie benaderingen, één beslissingsregel. Match op tag wanneer het concept geclassificeerd is en het bestand bruikbaar moet blijven. Match op naam wanneer de familie zich in aangepaste eigenschappen bevindt. Roep sanitize() aan wanneer het bestand de vertrouwensgrens overschrijdt, en verifieer met een terug‑scan, ongeacht welke route je hebt gekozen.
Klaar om dieper te gaan? Hier zijn enkele vervolgstappen:
- Bestudeer het predicaat‑oppervlak op de pagina Remove metadata properties in de documentatie
- Volg de step‑by‑step use case guide die op dezelfde code is gebaseerd
- Clone de sample repository en voer de geverifieerde pijplijn uit tegen je eigen bestanden
Aanvullende bronnen
- GroupDocs.Metadata Documentation
- API Reference
- Sample Projects on GitHub
- GroupDocs.Metadata Blog Category
Heb je vragen of wil je je implementatie delen? Neem contact op via het support forum.