Livid
280.84D
557.5D

20260526 - 关于已经修复的 404 bug 的具体原因

  •  1
     
  •   Livid ·
    PRO
    · 20h 59m ago · 4296 views

    假设有恶意程序写一个简单的循环,持续访问不存在的 topic id ,那么每次 V2EX 接收到这样的请求,还需要从数据库里查了之后,才知道是无效的 topic id ,这个查询过程就会很浪费资源。

    所以程序中有这样的一种机制,如果 topic id 明显大于某个值,那么就不用查任何数据库资源,直接返回 404 。

    这个值应该是被定期更新并且加上一个足够大的安全值。

    但是由于最近测试服里的一个 bug ,导致这个值自从测试服上线之后,就一直没有被正确更新。因此当 topic id 持续增长,终于来到旧值 + 安全值的边界时,所有新的 topic id 就都 404 跳转了。

    这个问题的根源是测试服上更新全站统计数据进 Memcached Key 时的 bug ,这个 bug 现在已经修复(测试服在这个地方现在使用了单独的 Memcached Key )。

    31 replies    2026-05-27 13:09:08 +08:00
    aheadlead
        1
    aheadlead  
       20h 54m ago
    没想到竟然是一个这样简单的问题..
    InDom
        2
    InDom  
       20h 54m ago
    啊?
    povsister
        3
    povsister  
       20h 52m ago
    我这类似用途是靠 id 算法,全局时间+safe margin 搞的。通过当前时间+id 编码规则就能很容易初步判定 id 是不是伪造的。后面被枚举刷太狠了就又在回源套了层布隆,也是时间校验,安全值范围内允许回源否则一律拦截。

    最开始考虑过全局通过有状态存储维护这个上限,但组件太多依赖一个单点就很麻烦。
    Pipecraft
        4
    Pipecraft  
       20h 51m ago
    那现在已经公开秘密了,这个机制似乎不能防止恶意程序了。
    ByteRan
        5
    ByteRan  
       20h 44m ago
    有点像千年虫的 BUG
    zhouzoki
        6
    zhouzoki  
       20h 43m ago
    现在应该有更好的方法了吧
    MFWT
        7
    MFWT  
       20h 42m ago
    @Pipecraft 应该也不追求完全拦住吧,至少抬高一点门槛
    Livid
        8
    Livid  
    MOD
    OP
    PRO
       20h 39m ago
    @Pipecraft 很可能这个机制现在也是不需要的。

    一些这样的逻辑都是当年应对某些恶意访问时写的。

    然后年复一年这样的逻辑堆太多,本身也是一种问题。
    itechify
        9
    itechify  
    PRO
       20h 28m ago
    哈哈哈哈哈,这也能宕机一天。历史遗留的 feature ,堆积的临时性代码,可以考虑做下减法了🤣
    tty0
        10
    tty0  
       20h 25m ago
    可不可以将 ID 改为编码?
    先校验自定义编码是否有效, 有效再去查询数据库.
    JoeJoeJoe
        11
    JoeJoeJoe  
    PRO
       20h 20m ago via iPhone
    哈哈哈哈 这是有历史沉淀的站点才能出现的问题😂
    Tink
        12
    Tink  
    PRO
       20h 4m ago
    这个机制感觉可以考虑用别的算法替代掉
    GeorgeV
        13
    GeorgeV  
       20h 3m ago   ❤️ 1
    v 站的这个 feature 很有趣,时不时来一下也蛮好的
    Ketteiron
        14
    Ketteiron  
       18h 26m ago
    @zhouzoki #6 可以借鉴 b 站当初从数字改成数字字母,或者用算法,或者给数字加个 token ,例如 /t/12345 -> /t/12345/fuawf67adafjmaiowf 。不过对于 V2EX 这种有年头的网站,重构的收益有些低。
    CEBBCAT
        15
    CEBBCAT  
       16h 9m ago
    > 假设有恶意程序写一个简单的循环,持续访问不存在的 topic id
    似乎是缓存穿透,如果是恶意请求,那就是 CC 攻击?

    听起来似乎是判定逻辑直接使用了缓存中存储的 topic count 作为 max id ?也许可以在新发帖时主动向 Cache 推送 max id ,记得使用 CAS 原子操作

    BTW Livid 你最后一段似乎语序有些模糊,是这个 bug 让你措手不及吗?注意休息
    ryd994
        16
    ryd994  
       13h 12m ago via Android
    @CEBBCAT #15 不用 CAS ,因为这个值不需要太精确。加个安全余量即可。同一时间生成的新帖 ID 应该差不了多少。
    tf2
        17
    tf2  
       11h 25m ago
    这个 idea 其实很好。不过可以做得细致一点

    故意设置一些不存在的但是红线主题 id

    谁访问,封谁的 IP
    diudiuu
        18
    diudiuu  
       11h 18m ago
    挺好的这个想法
    现在换个算法,可能以前的数据就难受了,最后全是补丁
    yougg
        19
    yougg  
       11h 12m ago
    可以通过 ULID 或者 UUID v7 判断时间戳
    ovtfkw
        20
    ovtfkw  
       11h 11m ago
    缓存穿透吗,但是现在的主题 id 都是线性增加的,很容易被猜到把,那直接恶意大量访问已经存在的主题呢
    8888888888
        21
    8888888888  
       10h 46m ago
    开始还以为是在治理那些中转站或者疑似广告贴,后来发现新帖全 404
    yelog
        22
    yelog  
       10h 43m ago
    这个场景感觉使用缓存比较好,max_topic_id 在新增帖子的更新一下缓存。查询帖子判断大于这个 max_topic_id 就 404 。
    keyfunc
        23
    keyfunc  
       10h 19m ago
    可以对 ID 额外增加校验位,校验失败就不去查数据库了。
    rrubick
        24
    rrubick  
       9h 29m ago via iPhone
    但是,有的帖子当时是有新增回复的,也就是有人是可以打开的,这又是为啥?
    penisulaS
        25
    penisulaS  
       9h 25m ago
    作为站长真不容易啊
    dudu2017
        26
    dudu2017  
       9h 12m ago
    昨晚用 chat 分析了一下,也定位到是数据库响应问题
    leekoho
        27
    leekoho  
       8h 29m ago
    @dudu2017 V2EX 源码开源了吗? 你这咋能通过 chat 去定位... 而且不是说不是数据库响应的问题吗,是程序设计导致的,是我理解错了吗
    CEBBCAT
        28
    CEBBCAT  
       7h 59m ago via iPhone
    @ryd994 make sense ,想的是既然存了就维护好这个数据,不然以后如果复用没注意到竟态可能会造成别的问题,但如果存的时候写明白,应该也行
    dudu2017
        29
    dudu2017  
       7h 50m ago
    @leekoho 重新看了一遍站长的发文,是我理解错了。可能被 AI 的幻觉误导了
    InDom
        30
    InDom  
       7h 47m ago
    @rrubick #24 也打不开, 读 404 但可以写, 所以直接 post 即可.

    还有一些是通过 api 查看的, api 没有这个检查所以不会 404.
    mywaiting
        31
    mywaiting  
       6h 47m ago   ❤️ 1
    从我过去的维护经验来说,最好把基础定义 API 和反垃圾 AntiSpam 的实现分离比较好

    一来可以保证 AntiSpam 不会影响基础 API 运行,二来方便在 AntiSpam 执行各种试验

    大概过程如下:

    所有流量从 gateway 进入到 webapp 后会有系列分离/分流机制推送到 AntiSpam 离线检测,检测后会自动标识 IP/User/Fingerprint 等标识的风险值,然后反馈到 webapp gateway 自动拉黑/喂假数据

    举个例子:正常访问的流量都会访问 /favicon.ico 这个请求进入 gateway 后会推送到 AntiSpam 离线检测后会适当降低当前访问 IP 的风险值
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3247 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 92ms · UTC 11:56 · PVG 19:56 · LAX 04:56 · JFK 07:56
    ♥ Do have faith in what you're doing.