PDF 中繼資料與隱藏資料

文件的中繼資料是檔案在頁面內容之外攜帶的關於自身的資訊:欄位聲稱的作者是誰、哪個應用產生了它、它聲稱自己何時建立與修改,以及哪些早期材料仍留在裡面。一個 PDF 可以同時裝有兩套重疊的中繼資料系統、一條早期修訂鏈、完整的嵌入檔案和以不可見方式繪製的文字;一張 JPEG 照片裝著相機的日記;甚至一張普通的 PNG 截圖也會說出製作它的軟體。本文逐一介紹這些藏身之處在哪裡、為什麼普通編輯抹不掉這些資料,以及真實外洩是如何發生的。想邊讀邊檢查自己的檔案,就運行文件鑑識工具——它在你的瀏覽器中本機工作;同一批檔案的閱讀結構方面,見你的 PDF 是網站無障礙的一部分。

每個 PDF 裡都裝著兩套中繼資料系統

較老的一套是資訊字典:存放在檔案預告片中的一小組鍵值對——Title、Author、Creator(製作原始文件的應用)、Producer(製作 PDF 的應用)、CreationDate 與 ModDate。這些欄位在匯出時自動寫入,而大多數文件作者從未打開過能看到它們的屬性對話框——這正是它們外洩的原因。從個人筆電匯出的報告,把筆電帳戶名寫成了作者;從去年範本開始的文件,仍寫著去年的作者。它們在列印出的頁面上什麼都看不見,卻對每個檔案接收者只隔著一層屬性面板。

較新的一套是 XMP:嵌入文件的 XML 包,建立在 Adobe 的可擴展中繼資料平台之上,與 PDF 規範本身 ISO 32000-2 一同被描述。XMP 用命名空間重複了許多同樣的內容:dc:title 表示標題、pdf:Producer、xmp:CreateDate 與 xmp:ModifyDate,外加舊字典沒有的欄位,如建立工具。兩套系統若保持同步本無害處,但它們並不:一個工具更新資訊字典而忽略 XMP,另一個重寫 XMP 而讓字典過期,第三個剝掉一套留下另一套。於是單個檔案常常對自己講出兩個略有不同的故事——而這種不一致本身就是資訊,因為它記錄了不止一個工具、在不止一個時刻經手過這份文件。

增量更新:刪掉了卻從未離開的段落

PDF 是為只附加編輯而設計的。編輯器增量保存修改時並不重寫檔案:它把改動的物件、一個新的交叉參照段和一個新的預告片附加到末尾,並透過 /Prev 指標鏈回上一個預告片。每次修訂都以自己的 %%EOF 標記結尾,所以數一數這些標記,就能得到該檔案以此方式保存次數的下限——而每次早期修訂都物理地保留在位元組中且可讀。在普通閱讀器中打開這樣的檔案,你只看到最新修訂;去讀位元組,或沿鏈回滾,文件的早期狀態還在那裡:表格裡的舊數字、條款的上一版措辭、發布前被刪掉的段落。

這正是屢屢見諸新聞的塗黑失敗背後的機制。團隊需要發布一份隱去姓名或數字的報告,於是有人在敏感段落上畫黑色矩形——一種只改變頁面外觀、完全不觸碰下層內容的操作——或在隨後增量保存的編輯器裡刪除文字,讓被刪物件留在早期修訂中。發布的檔案看起來乾淨。幾天後,有讀者選取「塗黑」區域、複製、把原文貼進文字編輯器;或有研究者解析修訂鏈,恢復了被移除的內容。真正的塗黑與遮蓋是不同的操作:底層內容必須從內容串流中移除,並把檔案完整重寫,讓位元組本身不再包含頁面上不再顯示的東西。若你即將發布的檔案帶有多個 %%EOF 標記,它的歷史還裝在裡面——請假設有動機的讀者會去讀那段歷史。

嵌入檔案與隱藏文字:無人列出的貨物

PDF 可以把完整的檔案裝在自己內部。該格式定義了嵌入檔案名稱樹,透過 /EmbeddedFiles 與 /Filespec 物件到達,創作工具用它存放來源試算表、資料附錄和作品集文件。能揭示它們的附件面板是大多數讀者從不打開的,所以嵌入的貨物悄無聲息地旅行:發布那份精美的 PDF 摘要,可能同時發布了它背後的工作試算表,連同它自己的中繼資料、草稿表和批註。反過來對接收者同樣成立——收到的 PDF 裡的附件會繼承周圍文件的信任,這就是為什麼嵌入檔案值得在任何檢查清單中占一行,而不是靠偶然發現。

文字不需要成為單獨的檔案也能隱藏。PDF 以算繪模式繪製文字,而模式 3——用 3 Tr 操作符設定——既不填充也不描邊:字元在內容串流中,可以被選取、搜尋和擷取,卻在頁面上完全不可見。有些不可見文字合法且有價值:掃描頁面背後的 OCR 層正是如此,它是讓影像可搜尋的隱藏文字。問題在於其他落入模式 3 或其近親的東西——白底白字、被裁到可見頁面之外的文字、為搜尋引擎添加的關鍵詞層——因為擷取文字層的讀者會收到頁面從未顯示過的文字。當隱藏層與可見層不一致時,檔案同時在說兩件事,而其中只有一件經過校對。

圖片也記日記:PNG 資料區塊與 JPEG Exif

PNG 檔案是一串命名的資料區塊,其中幾種區塊類型純粹為攜帶文字而存在:tEXt、它的壓縮兄弟 zTXt 和國際化的 iTXt。匯出工具習慣性地寫入它們——一個名為 Software 的關鍵字寫著編輯器、一個建立工具字串,有時是一整個嵌入的 XML 設定檔——而它們在每一次保留區塊清單的裁剪和縮放中存活。tIME 區塊添加最後修改時間戳,eXIf 區塊可以裝下完整的相機中繼資料區塊,而附加在結束區塊 IEND 之後的位元組被每個檢視器忽略,卻留在檔案中。於是一張看起來只是視窗中性圖片的截圖,可能說出這台機器的軟體、給自己標上日期,並攜帶作者從未見過的資料。

JPEG 照片走得更遠。檔案是一串標記段:APP0 裝 JFIF 標頭,APP1 裝 Exif 區塊或 XMP 包——有時兩者都有。Exif 的 IFD0 欄位讀起來像相機的日記:裝置的 Make 與 Model、照片拍攝或最後修改的 DateTime、處理它的 Software,在擴展目錄中還有 GPS 座標。直接從相機膠卷發布的手機照片曾讓組織和個人出醜——把他們精確地定位在照片本身從未顯示的時間和地點。註解(COM)段添加最後保存檔案的工具留下的自由文字,尾隨位元組可以位於影像結束標記之後,而讀取這一切的工具——Phil Harvey 的 ExifTool,列在來源中——是免費下載的,也就是說你的接收者也能讀它們。

交叉核對時間戳,然後在發布前清理

單個時間戳是一項主張;多個時間戳是一個可以自我核對的故事。建立日期落在修改日期之後,不可能描述由一個工具一次產生的文件。資訊字典日期與 XMP 日期對同一事件記錄不一致,記錄了兩個工具用兩隻時鐘。落在未來的日期,記錄了設錯的時鐘、被手工編輯的欄位,或由碎片拼湊的檔案。連 PDF 日期格式本身也招致歧義——D: 字串可以省略時區,讓讀者猜測這些數字來自哪隻時鐘。像審計師對待帳目差異那樣對待每處不一致:它通常有無辜的解釋——範本複用、筆電時鐘、在上傳時重寫檔案的最佳化器——它是需要權衡的證據,本身永遠不是判定。中繼資料欄位任何人用免費工具都能編輯,所以它們只能佐證或反駁一個故事,不能證明它。

因此清理是一套流程,不是一個按鈕。第一,檢查:把檔案放過文件鑑識工具,記下它會告訴陌生人什麼——作者與工具名、修訂數、嵌入檔案、隱藏文字、相互爭吵的時間戳。第二,盡量在源頭修復:在創作應用中改正文件屬性,而不是給它的輸出打補丁。第三,匯出一份全新的完整重寫——列印為 PDF、專門的清理工具,或對圖片用 ExifTool——因為完整重寫會丟棄早期修訂、孤兒物件和尾隨資料,這是增量保存永遠做不到的。最後,複查你真正發出的那份副本,而不是你打算發的那份。並記住全篇所依據的區分:內部原件應保留其中繼資料,因為溯源、歸檔價值、乃至無障礙——文件標題也是中繼資料——都依賴它。清理發布的副本,在家裡把記錄完整保留。

來源與延伸閱讀

常見問題

中繼資料能證明文件是誰建立的嗎?

不能。中繼資料欄位是程式寫入的文字;它們可以用免費工具編輯、從範本繼承或從另一個檔案複製,因此它們是證詞而非證據。它們能做的是佐證一項主張——或者當時間戳相互矛盾、或所命名的工具不可能產生該檔案時,反駁它。把它們當作多項證據中的一項,永遠不要當作作者判定。

為什麼幾個月前刪掉的文字還能從我的 PDF 中恢復?

因為增量更新。如果你的編輯器以附加修訂的方式保存,被刪文字會留在同一檔案的早期修訂中,位於由 /Prev 連結的預告片鏈之後。檢視器只顯示最新修訂,但位元組全都還在。修復方法是完整重寫——重新匯出或列印為 PDF——它只寫入當前狀態的新檔案,然後核實新檔案的 %%EOF 計數為一。

發布前總應該剝除中繼資料嗎?

剝除發布的副本,而不是記錄。外部副本不應攜帶作者帳戶名、內部工具鏈、嵌入的工作檔案或修訂歷史。但中繼資料也承擔正當工作:文件標題是輔助技術播報的內容,也是瀏覽器分頁顯示的內容,歸檔則依賴溯源欄位。把內部原件完整保留,為發布產生一份清理過的副本——然後檢查那份副本,因為清理工具有時會移除得比它們聲稱的少。