安全 如何生产唯一数据可以混淆后得到 Int 小于 4294967295 ?

mapana · 2019年01月07日 · 最后由 mapana 回复于 2019年01月09日 · 6237 次阅读

在需要数据混淆的情况下

如何生产唯一数据,然后转成Int并且小于4294967295

# 比如
irb(main):001:0> require "securerandom"
=> true
irb(main):002:0> data = SecureRandom.uuid
=> "45f196d4-2af5-4ae0-b771-b855fcd3e12d"
# 混淆数据 < 4294967295
irb(main):003:0> data.to_i(16)
=> 1173460692
# 原数据
irb(main):004:0> data.to_i(16).to_s(16)
=> "45f196d4"
irb(main):005:0>

最终,我能拿到原数据和混淆后唯一的小于 4294967295 的 Int 数据;并且可以逆向

说说

  • uuid.to_i(16) 会有弊端吗?
  • 你们有什么更好的经验?

先多谢各位!!!

SecureRandom.rand 4294967295 不过不保证唯一

真的需要 random 么?不需要的话数据库 int id

如果 1 秒一个的话:

Time.now.to_i

可以用 bitset 来确保唯一,不过的足够稀疏才有效率😂

最近用 Pg 实现了一个 Instagram Style ID,可供参考,32 位的 integer 也差不多,只不过碰撞几率就大了:

bigint 范围 -9223372036854775808 到 9223372036854775807,9223372036854775807 也就是:

select 9223372036854775807::bit(64);
                               bit
------------------------------------------------------------------
 0111111111111111111111111111111111111111111111111111111111111111

把 64 位的 bigint 分三段,第一段是 41 位 bit 的时间(可存 69 年),第二段是 13 位的 shard_id(可存 8191 个),第三段是 10 个 bit 的自增序列(可存 1024 个)

                   time                    |     shard     |    seq
-------------------------------------------+---------------+------------
 11111111111111111111111111111111111111111 | 1111111111111 | 1111111111

一年的毫秒数:31556952000,所以,41 位的 bit 可以存 69 年。

select b'11111111111111111111111111111111111111111'::bigint / 31556952000;
 ?column?
----------
       69

13 位 bit 的 shard_id:

select b'1111111111111'::bigint;
 int8
------
 8191

10 位的自增 seq:

select b'1111111111'::bigint;
 int8
------
 1023

所以,每毫秒每个 shard 可以产生 1023 个唯一 ID。

代码:

def change
  execute("create schema id_pool")
  execute("create sequence id_pool.table_id_seq")
  execute(<<~SQL)
  CREATE OR REPLACE FUNCTION id_pool.next_id(OUT result bigint) AS $$
    DECLARE
        our_epoch bigint := 1546300800000; /* 2019-01-01 单位ms */
        seq_id bigint;
        now_millis bigint;
        shard_id int := 1;
    BEGIN
        SELECT nextval('id_pool.table_id_seq') % 1024 INTO seq_id;

        SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO now_millis;
        result := (now_millis - our_epoch) << 23;
        result := result | (shard_id << 10);
        result := result | (seq_id);
    END;
    $$ LANGUAGE PLPGSQL;
  SQL
end

instagram article: http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram

很抱歉,看到大家的回答我才意识到自己的问题描述的非常差

这个问题最重要的是在于转成 Int 的同时,数据已经被混淆

mapana 回复

搜 scatter_swap obfuscate_id

hooopo 回复

obfuscate_id 管用,非常感谢

mapana 关闭了讨论。 01月09日 10:18
需要 登录 后方可回复, 如果你还没有账号请 注册新账号