V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
这是一个专门讨论 idea 的地方。

每个人的时间,资源是有限的,有的时候你或许能够想到很多 idea,但是由于现实的限制,却并不是所有的 idea 都能够成为现实。

那这个时候,不妨可以把那些 idea 分享出来,启发别人。
est

想到一个自增 id 但是同时防止遍历的办法

  •  2
     
  •   est · Nov 12, 2015 · 16130 views
    This topic created in 3822 days ago, the information mentioned may be changed or developed.
    比如会员, uid 从 1 开始,那么一些人就可以从 1 开始爬虫。。。

    于是我在脑洞一些办法防止这个事。有的用uuid,甚至hash,感觉都不是很友好。在保持id自增的前提下,我想了一些办法:

    第一个手段当然是限频率和屏蔽手段。。。

    第二个手段,就是把自增 id 弄成稀疏的。 比如统统跳过 id 个位数为 7 的。。那么如果有人故意访问 uid=7, uid=17, uid=27 等等,就直接判定为爬虫,封锁之。

    当然,判断个位数,这个很容易被发现规律猜到。

    那么,有没有比较好的算法,让人猜不到这个 “间隙” id 的规律,但是服务器又非常容易判断为不可用 id 呢?
    85 replies    2015-11-20 10:31:59 +08:00
    pubby
        1
    pubby  
       Nov 12, 2015
    偶尔我用 /user/{uid}-{md5(uid+key)} 的形式防止遍历
    est
        2
    est  
    OP
       Nov 12, 2015
    @pubby 这个也太复杂了。。。 id 太长。。
    wy315700
        3
    wy315700  
       Nov 12, 2015
    short_uuid
    undeflife
        4
    undeflife  
       Nov 12, 2015
    不需要算法 id 随便什么规律都好 没规律也行
    fail2ban 解析 access.log 多次符合规则的 404 ban 掉就行了
    pubby
        5
    pubby  
       Nov 12, 2015
    @est 嗯,所以偶尔用用。
    ts
        6
    ts  
       Nov 12, 2015
    @est 大神你还经常在哪些站里出没或者潜水 除了 v2
    est
        7
    est  
    OP
       Nov 12, 2015
    @undeflife 这个有一个问题就是别人可以新注册一个用户,看 uid 可以大致判断出你总用户数是多少。。。
    @wy315700 也可行。但是无序了。 id 自增感觉要好点。。
    xujif
        8
    xujif  
       Nov 12, 2015
    弄几个魔术 id ,访问就 ban
    cyr1l
        9
    cyr1l  
       Nov 12, 2015   ❤️ 1
    比如判断是否是质数或者是否能被某个质数(比如 17 ) 整除?
    akira
        10
    akira  
       Nov 12, 2015
    自增的 id 只对内部使用,对外是一个 uuid 或者和 id 无表面关系的字符串
    lanlanlan
        11
    lanlanlan  
       Nov 12, 2015
    只要爬虫 IP 资源够 都是浮云嘛→_→
    est
        12
    est  
    OP
       Nov 12, 2015
    @wy315700 而且如果 mysql 里用的话,还有可能冲突。。虽然很小概率。但是为了防止冲突还得加个唯一索引。这是要让人纠结死。。。而如果自增的话,直接根据上一个 id ,按照某一个算法,跳过一些 id ,就可以得到下一个 id 了。。。现在就是在想有没有这个比较好的算法。不容易猜出来,服务器计算和判断速度也比较快的。
    est
        13
    est  
    OP
       Nov 12, 2015
    @lanlanlan 如果加上运营商判断, ip 没那么好找哦。比如只允许 ADSL 的 IP 段访问,代理 ip 绝大多数是机房 ip 段。很容易判断出来。我见过很多国外论坛都只允许 comcast verizon at&t 之类的民用宽带 ip 访问。我换了 n 个代理,但是因为出口都是机房,都被判断出来了。
    est
        14
    est  
    OP
       Nov 12, 2015
    @xujif 我也是这样想的,但是从代码维护的角度来说,每人工增加一个 magic id 就要改代码,部署流程,或者改 config ,感觉略蛋痛。
    est
        15
    est  
    OP
       Nov 12, 2015
    @ts reddit hacker news. 我现在也想找别的地方混。
    est
        16
    est  
    OP
       Nov 12, 2015
    @cyr1l 差不多是这个方向。。。不知道大家有没有灵光一现更加 NB 的。。
    Elethom
        17
    Elethom  
       Nov 12, 2015 via iPhone
    那自增就沒有意義了。還不如 hash 。
    zhujinliang
        18
    zhujinliang  
       Nov 12, 2015
    之前有个类似的需求,当时的做法很 2b
    把 id 以十进制表示,然后每位随机做一个的对照表,然后再拼起来
    RitianZhao1988
        19
    RitianZhao1988  
       Nov 12, 2015
    内部一张表,外部一张表
    外部增加时有几率增加 rand 个魔术 id ,然后在内部表里再写一份没有 magic id 的怎么样?
    undeflife
        20
    undeflife  
       Nov 12, 2015
    @est 你的"间隙" id 同样不能解决这个问题
    如果 /users/xxxx 这样一个 url 并不存在分享的需求的话 无所谓友好不友好.
    如果存在分享的需求的话 /users/username 这样不是更好吗
    所以我认为完全可以从设计上弱化 uid 在用户这的存在
    wy315700
        21
    wy315700  
       Nov 12, 2015   ❤️ 1
    @est short_uuid 是 MySQL 的一个 64 位增长型 ID 啊,就是满足你的要求的,
    18000rpm
        22
    18000rpm  
       Nov 12, 2015
    跟着思路走只能想到多挖几个坑 233
    一个一位数的坑
    两个两位数的坑
    三个三位数的坑
    能整除的都不能踩,不知道这个在没遍历前还好不好猜规律
    lwbjing
        23
    lwbjing  
       Nov 12, 2015
    mongodb _id
    oott123
        24
    oott123  
       Nov 12, 2015   ❤️ 1
    lincanbin
        25
    lincanbin  
       Nov 12, 2015
    用 GUID+截断的时间戳作为主键,可以获得更高的插入效率,同时也可以一定程度防止爬虫。
    muzuiget
        26
    muzuiget  
       Nov 12, 2015
    自增 id 只在服务器器使用,对外就 hash 不就行了么, hash 同表也是唯一,允许所以?不让客户端通过 id 访问到资源。
    imn1
        27
    imn1  
       Nov 12, 2015
    虽然会增加我将来爬东西的难度,但还是要说一句话:
    外显有序 id 是低智商

    说个故事:
    上世纪末,要抓日本某站点一批数据,当时只知道 max(id)>=17000 ,步长 1 自增
    还不会写爬虫,于是开网络蚂蚁批量,直接下
    大约抓了 5000 条左右,那站点停了几小时,然后页面浏览器访问顶部出现了“巡回禁止”的横条,哈哈
    然后发现大约下 1000 条左右后面就会全部 404
    老子 proxy 多,当年还没有 qiang 的概念, ssl proxy 都是稀有物,但 http proxy 还是不少,因为原生网路就不畅,非人为原因……
    然后就每 800 条换一个 proxy ,爬完(换了多个确认是真的没有数据而不是 404 ),总数 26000+条
    这是当年不为爬 qiang 而使用梯子的典型例子
    凭这 2w 条信息,虽然没有全部发布,并且是重新组织和翻译,在小圈子也有点名气
    但也属盗版了,后来还是怕担责(即使日本追究不到我这来),撤了,自此之后虽然爬数据,但再也没批量公开发布了
    反正从那时开始我就禁止后台程序员使用外显有序 id 了

    @akira 说的是对的,其实不要想什么算法,因为读取的次数比写入多得多,在写入时产生一个唯一用于外显的 uid 则可,读取时用算法判定会严重增加机器负担
    est
        28
    est  
    OP
       Nov 12, 2015   ❤️ 1
    @undeflife 用户 id 只是举个例子。有很多时候会用到 id 的。
    @imn1 其实还有一招。就是不封,也不返回任何错误,直接随机产生垃圾内容。。。让你区分不出来内容是否真实的。。。我抓 bing 就遇到这问题了。。。。。。。嗯。。。。。。。。

    即便是外显 uid ,也是需要防止爬虫呀。。。这个时候除非做 hash ,否则依然也是有问题的。
    est
        29
    est  
    OP
       Nov 12, 2015
    @wy315700

    仔细看了下

    The UUID_SHORT() return value is constructed this way:

    (server_id & 255) << 56
    + (server_startup_time_in_seconds << 24)
    + incremented_variable++;

    感觉也算一个不明显的自增 id 的思路吧。。。。
    est
        30
    est  
    OP
       Nov 12, 2015
    @oott123 好东西。不过 ruby 有个更好的,基于 Perfect hash function 的 https://github.com/namick/obfuscate_id
    imn1
        31
    imn1  
       Nov 12, 2015
    @est
    我没说不防啊,只是你别只穿着内衣上地铁,然后举个牌子“我可以骚,你不可扰”,这算什么?
    livelazily
        32
    livelazily  
       Nov 12, 2015
    跳过所有质数
    oott123
        33
    oott123  
       Nov 12, 2015
    @est 恕我愚昧,没发现哪里“更好”了。
    lerry
        34
    lerry  
       Nov 12, 2015
    twor2
        35
    twor2  
       Nov 12, 2015
    uuid 只是视觉上的长,其实还好,网址都是点进去的,就算是 1234 ,也不会有人敲进去吧
    liboyue
        36
    liboyue  
       Nov 12, 2015
    用一个表呗。把顺序的内部 ID 映射到随机 ID 上,多一次查表的操作
    XiaoxiaoPu
        37
    XiaoxiaoPu  
       Nov 12, 2015
    把自增 ID 用 RSA 加密(或其他加密算法),加密后的结果给用户,用户传过来的 ID 解密,不知道是否可行
    est
        38
    est  
    OP
       Nov 12, 2015
    @livelazily 2333 好办法!
    ts
        39
    ts  
       Nov 12, 2015
    @est 有中文类别的坛子或者网站吗 求大神的 bookmark .....
    millken
        40
    millken  
       Nov 12, 2015   ❤️ 2
    est
        41
    est  
    OP
       Nov 12, 2015
    @ts 网址我都背熟了。 newsmth.net/mainpage.html 纯手打。
    wingoo
        42
    wingoo  
       Nov 12, 2015
    base62
    映射规则自己指定下
    hooopo
        43
    hooopo  
       Nov 12, 2015
    内部设置一个私有函数产生黑洞 ID...
    ooh
        44
    ooh  
       Nov 12, 2015
    没有任何实际意义
    windows98
        45
    windows98  
       Nov 12, 2015   ❤️ 1
    看帖子的同时,瞟了一眼这个帖子的 url...
    ibireme
        46
    ibireme  
       Nov 12, 2015
    用 MongoDB 的 ID 生成办法就不错啊~
    est
        47
    est  
    OP
       Nov 12, 2015
    @hooopo 就是这个意思。。。那么,大家有没有什么好的私有函数建议呢。要无状态,速度快,很难逆向出的。。。这个帖子 /t/233004 被 @binux 弄一个一元四次方程就给破了。。。。。。。。。。
    dong3580
        48
    dong3580  
       Nov 12, 2015
    @est
    没用,我不信你作出站无目录列表,

    @XiaoxiaoPu
    这样变化的 id ,你让搜索引擎怎么收录?
    est
        49
    est  
    OP
       Nov 12, 2015
    @dong3580 没看懂。什么没用?
    Felldeadbird
        50
    Felldeadbird  
       Nov 12, 2015
    如果是闭源的话,直接 参数+自增 ID+参数。 混淆进去就行了。
    如: order_id =1 ;那么访问的 URL 地址为:
    /xxx.io?order=6544678198786782 拆分为三部分: 6544678 、 1 、 98786782 。
    fork3rt
        51
    fork3rt  
       Nov 12, 2015
    好无聊的方法。。。
    zdhxiong
        52
    zdhxiong  
       Nov 12, 2015
    @est 不管你的网址弄得多复杂,一个 wget 命令都能把你的整个站镜像下来。
    xierch
        53
    xierch  
       Nov 12, 2015
    next_id = hmac(last_id, key) % MAX_GAP + 1
    xierch
        54
    xierch  
       Nov 12, 2015
    哦,不是 =,是 +=
    xierch
        55
    xierch  
       Nov 12, 2015
    next_id = last_id + 1 + hmac(last_id, key) % MAX_GAP
    est
        56
    est  
    OP
       Nov 12, 2015
    @zdhxiong 你再想想呢?比如我 margin-left: -10000px 一个 div 里弄一个陷阱链接,你访问就直接给你永久返回垃圾数据。镜像下来然后呢?
    huobazi
        57
    huobazi  
       Nov 12, 2015
    snowflake
    est
        58
    est  
    OP
       Nov 12, 2015
    iambic
        59
    iambic  
       Nov 12, 2015
    感觉是不是就是一个 integer hashing 问题啊

    这个链接 https://gist.github.com/badboy/6267743 应该有用。另外 redis 源码里, dict.c 用的 Thomas Wang 的 hashing function 应该也可以参考下
    clino
        60
    clino  
       Nov 12, 2015
    取当前时间
    typcn
        61
    typcn  
       Nov 12, 2015
    @est 搜索引擎蜘蛛也会这样的。。
    est
        62
    est  
    OP
       Nov 12, 2015
    @iambic 这也是个好思路。
    est
        63
    est  
    OP
       Nov 12, 2015
    @typcn 增加一行 UA+IP 地址段判断,不拉黑就是了。
    hooopo
        64
    hooopo  
       Nov 12, 2015
    @est 无规律的随机点就可以,加一个 hole 表...里面随机填一些 id 就好吧
    est
        65
    est  
    OP
       Nov 12, 2015
    @hooopo 感觉通过算法算出来的好好玩一点。。
    jsq2627
        66
    jsq2627  
       Nov 12, 2015
    UUID/GUID 当然是最好的。只不过长的比较丑,对用户不友好。不过还是可以避免,我们最近在做的一个系统,用户注册后就必须得输入一个五位代码做 URL 定位部分。
    FrankFang128
        67
    FrankFang128  
       Nov 12, 2015
    ban 有什么用,很快就发现你的规律了。
    displayabc
        68
    displayabc  
       Nov 12, 2015
    用进制转换啊, 10 进制转换成 36 进制, 10 数字加 26 个字母,把顺序打乱
    xierch
        69
    xierch  
       Nov 12, 2015
    不如 ID 还是按顺序自增,但是提供给用户的时候,在末尾加一位数用作校验?
    效果应该类似于,每两个 ID 之间平均间隔 10 个黑洞
    校验值可以用任意算法加密 ID ,然后 mod 10 得到..

    推广一下,可以用 id * N + (encrypt(id) % N) 得到带校验码的 id_v
    服务器收到 id_v 以后,用 id_v / N 得到原 ID ,
    然后用 id_v % N == encrypt(id, key) % N 判断是否正确。
    ( N >= 2 ,越大掺的洞越多(
    dallaslu
        70
    dallaslu  
       Nov 12, 2015
    1. 使用自增 ID ,记为 A ;
    2. 生成 UUID ,去掉前面的 0 ,再取前 X 位按 16 进制转为 10 进制的值,记为 B ;
    3. 计算 X 位 16 进制数字的 10 进制值的数字个数(如 4 位 16 进制数字 FFFF 10 进制值为 65535 ,数字个数为 5 ),记为 C ;
    4. 在 B 的前面补 0 ,以使长度等于 C ,将其记为 D ;
    5. 把 A 和 D 拼接起来,用做外显 ID 。

    比如设 X 为 4 , A 为 235554 , UUID 为 3FE4C8B33C ...,则:

    B = 0x3FE4 = 16356 ;
    C = 5 ;
    D = 16356 ;
    ID = 23555416356

    遇到 404 就可以判为爬虫了。话又说回来,自增 ID 后面拼上定长的随机数不就好了么!
    dallaslu
        71
    dallaslu  
       Nov 12, 2015
    当然了,如果还有校验的需求,可以用 md5(id+salt) 来代替 UUID ,参与 12345 运算……
    hansnow
        72
    hansnow  
       Nov 12, 2015
    @est 其实我想说,你是唯一一个我在 D 版和 v2 同时看到的活跃 id
    ctftemp
        73
    ctftemp  
       Nov 12, 2015 via Android
    id 加盐 hash 一下,拿这个 hash 值作为判断依据就比较难预测了吧?
    pepsin
        74
    pepsin  
       Nov 12, 2015
    @hansnow 你可能看漏我了
    hansnow
        75
    hansnow  
       Nov 12, 2015
    @pepsin 哈哈哈,看你头像就想起来了
    Hipponensis
        76
    Hipponensis  
       Nov 12, 2015
    LS 许多思路学习了,但总觉得防遍历有点舍本逐末,不如 ID 还是按顺序自增,然后下陷阱,某些 id 对应的页面用户无法访问,让爬虫进去,然后封禁对应 ip 。以上爬虫新手瞎想的。
    varrily
        77
    varrily  
       Nov 12, 2015
    我在用 base58(uuid) 长度 22 位左右。比直接 uuid 短不少。
    msg7086
        78
    msg7086  
       Nov 12, 2015
    @haython http://ra.gg/!iMD4o 以前还做过类似的东西其实。

    @xierch 其实信用卡、身份证,都是基于这个机制。
    abscon
        79
    abscon  
       Nov 13, 2015 via iPhone
    @twor2 我就敲网址。有时候这是最方便的
    holyghost
        80
    holyghost  
       Nov 13, 2015 via iPhone   ❤️ 1
    有开源的 hashids 不用。。。
    xiaogui
        81
    xiaogui  
       Nov 13, 2015
    @holyghost hashids 看着好棒,哈哈。
    xiaogui
        82
    xiaogui  
       Nov 13, 2015
    不过非连续 ID 并不能完全阻止被爬虫。
    est
        83
    est  
    OP
       Nov 13, 2015
    @xiaogui 为什么?
    xiaogui
        84
    xiaogui  
       Nov 13, 2015
    @est 只要你把内容显示给用户,就不能保证爬虫不会抓取,只不过可能会让爬虫麻烦点而已。
    un
        85
    un  
       Nov 20, 2015
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   875 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 179ms · UTC 22:29 · PVG 06:29 · LAX 15:29 · JFK 18:29
    ♥ Do have faith in what you're doing.