Postgresql

具有隨機變化增量的主鍵(因此不容易猜到)

  • January 16, 2021

我希望主鍵自動遞增和生成,但增量不同。例如,如果我的增量範圍為 100…,那麼自動生成的密鑰將如下所示:

  • 20(1 到 100 之間的隨機數)

  • 30(添加 1 到 100 之間的隨機數 10)

  • 113(添加介於 1 和 100 之間的隨機數 83)

  • 118(添加介於 1 和 100 之間的隨機數 5)

  • 217(添加介於 1 和 100 之間的隨機數 99)

  • 220(添加介於 1 和 100 之間的隨機數 3)

數據域通常通過 HTTP REST 端點公開,我希望最終使用者無法通過簡單地遞增數字來猜測主鍵。

如果可能,我會盡量避免使用 UUID/GUID。我的 REST URL 更長,通常帶有父子標識符。(是的,這是可以避免的,但我更喜歡它來進行更簡單的測試/故障排除)。所以我更喜歡數字作為標識符。

有沒有我不知道的更簡單的解決方案?我正在使用 PostgreSQL,但任何通用解決方案也可以。

我建議一個函式採用一個regclass參數,該參數在從給定序列返回下一個值之前ALTER SEQUENCE以新的隨機生成的增量執行。

可用作. _ _nextval()

每個文件ALTER SEQUENCE

增量

子句INCREMENT BY 增量是可選的。正值表示升序,負值表示降序。如果未指定,則將保留舊的增量值。

然而:

您必須擁有要使用的序列ALTER SEQUENCE

所以我們需要注意特權。您可以製作該功能SECURITY DEFINER並由超級使用者擁有。如果您沒有REVOKE特權,public它適用於任何序列上的任何人。限制使用有兩種基本策略:

  • 要僅允許選定的序列,請將這些序列的所有者更改為某個專用角色,例如randseqrandseq擁有該功能(仍然使用SECURITY DEFINER)。
  • 僅允許選定的角色,從和到所述角色REVOKE的功能的所有權限。您可以使用組角色來簡化權限管理。public``GRANT EXECUTE

或將兩者結合起來:

CREATE OR REPLACE FUNCTION **nextval_rand**(regclass)
 RETURNS int AS
$func$
BEGIN
EXECUTE format('ALTER SEQUENCE %s INCREMENT %s'
              , $1                          -- regclass automatically sanitized
              , (random() * 100)::int + 1); -- values between 1 and 100
RETURN nextval($1)::int;
END
$func$ LANGUAGE plpgsql SECURITY DEFINER;

-- to restrict usage:
ALTER FUNCTION nextval_rand(regclass) OWNER TO randseq;
REVOKE ALL ON FUNCTION nextval_rand(regclass) FROM public;
GRANT EXECUTE ON FUNCTION nextval_rand(regclass) TO randseq;
GRANT randseq TO ???;

稱呼:

SELECT nextval_rand('tbl_tbl_id_seq'::regclass);

您現在所要做的就是在任何串列列的列預設值中nextval()替換為。nextval_rand()並可能更改序列的所有者。

ALTER SEQUENCE tbl_tbl_id_seq OWNER TO randseq;
ALTER TABLE tbl ALTER COLUMN tbl_id SET DEFAULT **nextval_rand**('tbl_tbl_id_seq'::regclass);

筆記

ALTER SEQUENCE旨在不阻止並發事務。立即生效,不可回滾。它應該在多使用者環境中可靠地工作。閱讀手冊頁的註釋部分以了解ALTER SEQUENCE行為的詳細資訊。

競爭條件的可能性非常小,其中兩個並發操作ALTER SEQUENCE在呼叫之前執行nextval()。由於無論如何我們都在使用隨機數進行操作,所以這並不重要。

由於我們正在執行動態 SQL,因此我通常會SET search_path = public, pg_temp使用該函式。但是由於參數是regclass,因此只能傳遞有效的序列名稱,並且會自動進行模式限定和明確轉義。

因為您的目標是:

最終使用者無法通過簡單地遞增數字來猜測主鍵。

那麼,不僅僅是你的鍵的可變增量(所以他們必須搜尋幾十或幾百個值),為什麼不去尋找完全非線性的東西呢?

PostgreSQL wiki 中有一個函式可以滿足您的需求,pseudo_encrypt

它接受順序輸入並返回偽隨機非重複輸出。

而不是你通常的SERIAL PRIMARY KEY,它擴展為:

CREATE SEQUENCE mytable_colname_seq;

CREATE TABLE mytable (
   colname integer PRIMARY KEY DEFAULT nextval('tablename_colname_seq'),
   ...

);

ALTER SEQUENCE mytable_colname_seq OWNED BY mytable;

DEFAULT您可以改為手動創建序列並分配所有權,並使用在序列上呼叫函式的a 定義列,例如:

DEFAULT pseudo_encrypt(nextval('tablename_colname_id_seq'));

不過,這裡有一個重要的警告。如果不修改具有現有數據的表,此技術將無法工作,因為該pseudo_encrypt函式可能返回表中已存在的值。它保證不重複self,但對錶中已有的任何內容一無所知。要使用它進行複制,您可以創建一個pseudo_encrypt帶有第二個參數的變體,即允許返回的最低 ID。如果它計算出較低的 ID,它只會使用序列中的下一個值重複計算,丟棄該 ID。

引用自:https://dba.stackexchange.com/questions/71702