具有隨機變化增量的主鍵(因此不容易猜到)
我希望主鍵自動遞增和生成,但增量不同。例如,如果我的增量範圍為 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()
增量
子句
INCREMENT BY
增量是可選的。正值表示升序,負值表示降序。如果未指定,則將保留舊的增量值。然而:
您必須擁有要使用的序列
ALTER SEQUENCE
。所以我們需要注意特權。您可以製作該功能
SECURITY DEFINER
並由超級使用者擁有。如果您沒有REVOKE
特權,public
它適用於任何序列上的任何人。限制使用有兩種基本策略:
- 要僅允許選定的序列,請將這些序列的所有者更改為某個專用角色,例如
randseq
並randseq
擁有該功能(仍然使用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。