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

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

在需要数据混淆的情况下

如何生产唯一数据,然后转成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) 会有弊端吗?
  • 你们有什么更好的经验?

先多谢各位!!!

共收到 7 条回复

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
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册