有什麼可以顯示同時創建或更新了 2 個獨立條目嗎?
虛構的例子,簡化以更好地解釋問題。假設我有一個包含以下欄位的表單:
- 使用者電子郵件
- 你在 2012 年投票給了誰
- 你在 2016 年投票給了誰
送出後,我填寫以下 PostgreSQL (v.11) 數據庫表:
“使用者列表”表
- 串列(自增 INT)
- 電子郵件(文本)
“使用者數據”表
- Unique_Random (INT)
- Vote_2012(文字)
- Vote_2016(文字)
這些條目(據我所知)無法跨錶鍊接,因為 Serial 和 Unique Random int 之間沒有關係。
威脅模型:攻擊者完全控制了 postgreSQL DB 伺服器(硬體和軟體)
如果我是正確的,UserData 條目在創建時不會插入到任何特定位置,因此應該無法分辨最後添加的是哪個。
還有其他任何東西(日誌、磁碟上的數據位置、記憶體……)可以揭示哪些條目是同時創建或更新的(因此是連結的)?
如果是這樣,可以做些什麼來防止這種情況發生?
就像提供的 mustaccio 一樣,
CLUSTER
是刪除插入順序的物理痕蹟的好方法。但是行不一定保持物理順序:其他命令(如VACUUM
或各種寫操作)也可以自由移動元組,因為 Postgres 認為合適。行的物理順序不可靠。除此之外,還有一種更簡單、更可靠的方法來辨識插入到具有事務 ID 的同一事務中的行
xmin
:您的邪惡攻擊者可以簡單地加入
xmin
:SELECT * FROM "UserList" ul JOIN "UserData" ud ON ud.xmin = ul.xmin
更糟糕的是(或更好,取決於誰在問):從 Postgres 9.5 開始,您還可以使用設置跟踪送出時間戳,
track_commit_timestamp
從而辨識在特定時間送出的行:即使插入到單獨的事務中,事務 ID 也是連續的,並且由於它們的接近性仍然可能洩漏資訊……
可能的解決方案
要覆蓋您可能會定期(如每週?)的
xmin
曲目:UPDATE
UPDATE "UserList" SET email = email; UPDATE "UserData" SET vote_2012 = vote_2012;
這會在不更改使用者列的情況下以全部成本為整個表寫入新的行版本。但它設置了一個新的
xmin
,從而覆蓋了所有軌道。您可能會跟進CLUSTER
(也從重寫所有行中刪除表和索引膨脹)並VACUUM ANALYZE
使其完成。如果您的表很大,請考慮在執行此操作之前刪除所有索引並在之後添加它們:總體上更便宜。
或者只是編寫新表並刪除舊表,在此過程中隨機排序行 - 如果您沒有很多依賴項,這會很痛苦。比上述更快,它將完美地達到目的。