V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
felix9ia
V2EX  ›  Web Dev

应不应该把主键 id 暴露在 url 上?

  •  2
     
  •   felix9ia · 8 天前 · 6437 次点击

    想请教一下大家是怎么做的?

    比如访问一个电商网站的店铺页面的 url:

    方式 1:使用自增的主键 id xxx/shop/123

    方式 2:使用雪花主键 id 或者 guid

    xxx/shop/1881238297653633026

    xxx/shop/85d93ea0-3d43-48c5-99ec-e11f54655228

    方式 3: 使用业务编号

    xxx/shop/st_003

    方式 4:

    用 sqids 把所有的实体主键 id(private_id) 在转换 VO 时加盐转换成 (public_id) 返回给前端

    相关讨论: https://www.reddit.com/r/csharp/comments/rg7xob/is_it_bad_to_expose_primary_key_to_the_user_if/

    68 条回复    2025-01-23 20:42:41 +08:00
    Rickkkkkkk
        1
    Rickkkkkkk  
       8 天前
    不是自增的就行
    javalaw2010
        2
    javalaw2010  
       8 天前
    在绝大部分场景下,我推崇方案 1 ,如果有产品端/安全端的特殊需求,我会考虑方案 3 ,只有再极少数场景下,比如日志追踪等,我会考虑 2
    javalaw2010
        3
    javalaw2010  
       8 天前
    @javalaw2010 原贴编辑过了吗?我这里的方案 3 指的是加盐,方案 2 指的是 uuid
    laobobo
        4
    laobobo  
       8 天前
    我(前端)做过的功能,后端给几乎都是用的自增 ID ,极少数场景才会用 2 ,其他目前没遇到
    felix9ia
        5
    felix9ia  
    OP
       8 天前
    @javalaw2010 是的,不好意思,我刚刚改了一下。

    其实方案 1 的自增有明显的缺陷,不应该被推荐把? 用 sqids 加盐我觉得也是少数场景,比如用户主页这种。
    CHTuring
        6
    CHTuring  
       8 天前
    2 就够用了,还是像楼上说的,只要不是自增就行了。
    felix9ia
        7
    felix9ia  
    OP
       8 天前
    @laobobo 其实,我的这个问题有场景限制,就是在客户端,而不是后台管理页面。

    如果是后台管理,我觉得暴露自增 id 没有关系。
    felix9ia
        8
    felix9ia  
    OP
       8 天前
    方案 4 有一个好处就是,定期更换盐,可以让链接失效,当然让链接失效有好处也有坏处
    laobobo
        9
    laobobo  
       8 天前
    @felix9ia 嗯,如果是用户端,个人感觉还是不要暴露自增 id ,总感觉不安全
    javalaw2010
        10
    javalaw2010  
       8 天前
    自增 id 除了暴露数据量之外,其他我也没觉得会有啥缺陷,而“暴露数据量”这件事也只有少数场景下才值得被关注,这些场景下就需要具体问题具体分析,比如订单相关场景,其实订单号比 ID 更像事实上的主键(我个人喜欢在绝大多数场景下都保留自增 ID ),业务上基本使用订单号而非主键。
    iyiluo
        11
    iyiluo  
       8 天前
    肯定不能用自增,首先安全那关就过不去,可以被黑产猜测到数据,遇到爬虫,直接把你整个业务的数据都扒下来。用 md5, uuid, 雪花都行
    anonydmer
        12
    anonydmer  
       8 天前
    目前项目都用 ULID
    musi
        13
    musi  
       8 天前
    暴露自增 id 有什么问题吗?
    我没见 v2 有什么安全性问题啊
    zpfhbyx
        14
    zpfhbyx  
       8 天前
    数字没问题啊, 只要不是自增就行 足够大 轮训不全的.
    felix9ia
        15
    felix9ia  
    OP
       8 天前
    @musi V2EX 用的是自增 id ?

    https://www.v2ex.com/t/1106781
    musi
        16
    musi  
       8 天前
    @felix9ia t 后面的不就是帖子 id 么,你加一减一不也能看到其他帖子么
    mxT52CRuqR6o5
        17
    mxT52CRuqR6o5  
       8 天前
    也可以用对称加密算法加个密,不知道密钥的话也破解不了
    felix9ia
        18
    felix9ia  
    OP
       8 天前
    @musi 卧槽,还真是
    kingcanfish
        19
    kingcanfish  
       8 天前
    其实 暴露在 url 上和暴露在接口 json 中没啥区别,不自增就行
    飞书一样暴露出来的
    hertzry
        20
    hertzry  
       8 天前 via iPhone
    京东这一串应该也是自增。
    https://item.jd.com/product/7323507.html
    DonaldY
        21
    DonaldY  
       8 天前
    @musi
    @felix9ia
    直接用自增 id ,方便爬虫穷举。

    有权限的数据页面不应该用自增 id 在 url 上
    dylanqqt
        22
    dylanqqt  
       8 天前
    我想问一下自增的有什么风险?
    jaylee4869
        23
    jaylee4869  
       8 天前
    @dylanqqt 没有做好数据权限控制会导致数据泄露的越权操作。
    BeijingBaby
        24
    BeijingBaby  
       8 天前
    安全性上讲,无所谓自增,有人说方便爬取,想多了。你随机 id 要爬取你也能爬到啊,只要数据是公开的,和自增和随机的没任何区别。
    有时候更多的是考虑暴漏业务数据量,以及分布式的时候,才抛弃自增 id 。
    zt5b79527
        25
    zt5b79527  
       8 天前
    @dylanqqt 简单来说,别人能猜到你的数据量。比如说订单号自增,竞争对手就能知道你的订单量。比如之前 b 站的 bv 号,最初好像也是自增的,竞争对手就能知道平台的投稿量,后来就换成随机的了(应该不全是这个原因,但是肯定有这方面的考量)
    esee
        26
    esee  
       8 天前
    主键用的自增 ID, 后端接口查询的时候,sql 语句对 id 加密查询出来,我是这样做的.
    musi
        27
    musi  
       8 天前
    @DonaldY #21 简单的数字我也可以穷举吧
    zjsxwc
        28
    zjsxwc  
       8 天前
    自增 id 方便调试和 dba 维护,大部分时候自增 id 就够用了,
    我只在 serverless 系统上看到用 uuid 的
    wangtian2020
        29
    wangtian2020  
       8 天前
    可以暴露,暴露在 url 中与暴露在请求体里有什么区别。
    问题是不要使用自增 id 暴露网站后台的规模!
    订单 id 自增暴露每日订单数量,商品 id 自增暴露订单数量
    dylanqqt
        30
    dylanqqt  
       8 天前
    @zt5b79527 这种算不上什么,自增 id 可以从 1 开始自增,也可以从 10000000 开始自增,别人咋看?至于小公司根本不在乎这个 id 暴露。
    chendy
        31
    chendy  
       8 天前   ❤️ 1
    暴露 id 本身没啥问题
    暴露 id + 自增 id 可能导致的问题:
    1. 对外的系统,纯自增 id 可以推算出数据增长量,暴露业务情况
    2. 如果权限做的不好,用户或者爬虫可以通过 id 遍历全部数据
    处理方式也很简单:
    1. 用一些操作对数据进行加密/编码
    2. 完善权限,完善风控
    yelog
        32
    yelog  
       8 天前   ❤️ 2
    @dylanqqt 容易被暴力攻击越权漏洞, 假如微博的私信列表有越权漏洞

    你在进入微博的私信页面, 发现获取私信列表的接口是 weibo.com/p_message/16645, 然后你把最后的数字(id) 改为 1, 发现获取到管理员 admin 的私信列表了哈哈哈, 然后依次加 1, 可以非常快把微博的所有用户的私信列表全部下载下来

    如果不是自增的, 比如 UUID, 尽管知道这个接口越权漏洞, 但是鉴于 UUID 的随机性和位数, 用户隐私泄漏的风险就非常小
    TimePPT
        33
    TimePPT  
       8 天前
    @chendy 完全同意,其实主要问题就是推断业务增长情况,和遍历爬虫(一个冷知识:QQ 邮箱的数字 @qq.com 也有类似问题所以一开始入信反垃圾策略就很严格),其他没啥大问题。

    我新项目一般数据库用 PostgreSQL ,唯一 id 使用 uuidv7 ,传给前端 url 外显时候使用 url safe 的 base64 显示了,除了丑点没啥其他副作用。
    cxxlxx
        34
    cxxlxx  
       8 天前
    liuidetmks
        35
    liuidetmks  
       8 天前
    @dylanqqt 从 1w 开始,并不能起到很大作用,人家只有作差分就能获取你某段时间内业务规模了
    自增 id 也有其他风险,
    比如某个接口配置失误,通过订单号直接查询数据,还是比较危险的
    importmeta
        36
    importmeta  
       8 天前
    里面逻辑再拿用户 id,加一层保险
    SoyaDokio
        37
    SoyaDokio  
       8 天前
    根据 RESTful 语义原则,当然是把 ID 放在 URL 里更好,但仅限于 UUID 或其他类似主键。
    自增主键的话,建议还是隐藏起来,以免用户可以轻松批量暴库。
    default996
        38
    default996  
       8 天前
    通常建表时我会创建 id,created_at, updated_at
    然后一般情况下我会使用自增 ID;
    特殊情况下,我会使用 id+created_at ,只有两个都匹配到才能查询到记录
    Reficul
        39
    Reficul  
       8 天前
    自增 ID 可能会暴露你们业务一天有多少数据,比如订单量之类的。之前我们懒惰 fix 这个问题的方法是随机跳过部分数字来给数据投毒。
    voy
        40
    voy  
       8 天前
    hackernews is self increased. done.
    forty
        41
    forty  
       8 天前   ❤️ 1
    有时候杀鸡用不上牛刀。

    其实还有 1 种简单方案,叫 hashid, 几十种语言的实现都有, github 可用搜到,可以在纯数字和"hashid"之间互相转换,既不直接暴露主键数字 id 给前端,无法被人直接遍历,同时也不增加后端复杂度。
    Hashids 改名叫 Sqids 了. https://sqids.org/

    原来 @cxxlxx 已经提出来了,刚开始没注意到。
    thinkershare
        42
    thinkershare  
       8 天前
    自增的也无所谓,需要安全的地方,需要其它权限鉴定逻辑。
    ntedshen
        43
    ntedshen  
       8 天前
    如果你用 innodb 的话,可以把 update 全部改成 insert ignore on duplate update ,你就能得到一个超音速自增的主键(狗头
    Zcyisabigman
        44
    Zcyisabigman  
       8 天前
    用自增的一些缺点:
    1 ,暴露业务数据规模,著名的瑞幸咖啡那件事就是被人蹲点捡小票,通过 ID 推算真实业务量
    2 ,方便爬虫写脚本抓数据
    3 ,存在缓存击穿问题???
    chairuosen
        45
    chairuosen  
       8 天前
    要看业务是不是数据都公开,京东的商品,论坛的帖子,这种无所谓。资源要做隔离的就需要考虑隐藏了
    xuelu520
        46
    xuelu520  
       8 天前
    暴露有什么影响吗?
    有些 ID 暴露也无所谓啊,就例如这个帖子的 ID 不就在 url 上
    涉及到隐私和安全的可以考虑加密或雪花或其他方案加密。
    正常用的无所谓的,做好暴露后问题的处理就行。
    nekochyan
        47
    nekochyan  
       8 天前
    我们有个项目是直接用 ID 异或一个较大的数给前端就行了,然后再异或回来
    zt5b79527
        48
    zt5b79527  
       8 天前
    @dylanqqt #30 单单业务规模这一点,确实对小公司可能不算什么,那大公司呢?如果是年营收上百亿,竞争对手虎视眈眈的上市公司呢?对于大公司来说,安全才是第一位的。竞争对手可能已经通过各种渠道收集了你各种各样的信息,再加上这一点交叉验证,底裤都给你扒出来。
    ospider
        49
    ospider  
       8 天前
    snowflake id 就足够了,别的纯属想太多
    yh7gdiaYW
        50
    yh7gdiaYW  
       8 天前
    看完这贴我就把 v 站的第 1,10,100,1000,10000,100000,1000000 贴看了一遍
    对很多业务来说这么轻易的能跳转是不可接受的
    lcy630409
        51
    lcy630409  
       8 天前
    自增 id 然后商户可以 缴纳 30 元 自定义一个“靓号”
    xuanbg
        52
    xuanbg  
       8 天前
    不连续就行了
    spike0100
        53
    spike0100  
       8 天前 via iPhone
    可以考虑 hashids 对主键进行映射
    dylanqqt
        54
    dylanqqt  
       7 天前
    @zt5b79527 https://ic-item.jd.com/100143612769.html 京东算不算大公司?只能说这并不算什么大不了的事情。
    dylanqqt
        55
    dylanqqt  
       7 天前
    @liuidetmks 危险是因为接口配置失误了危险,并不是自增 id 危险。就像支付宝这次打折 20%一样,并不是开发这个打折 20%的功能很危险,是因为配置错误了很危险。
    xiaomushen
        56
    xiaomushen  
       7 天前
    1. 不是自增就行
    2. 但如果是大家喜欢的 MySQL 嘛,那就加盐吧
    kakki
        57
    kakki  
       7 天前
    自增危险是你的接口处理权限有问题,就和"把某个东西藏起来不想让别人找到"在应用密码学里面提到过是一件不靠谱的事情,做好接口防范才是正道.
    barbery
        58
    barbery  
       7 天前
    2 楼正解
    zpf124
        59
    zpf124  
       7 天前
    主键暴露不暴露得看你的主键有什么意义。
    像 v2 或者贴吧、抖音、b 站的帖子 id 暴露就暴露了,除特殊板块做鉴权拦截外,其它帖子本来就允许你随便看,那数字反倒是一个很容易记忆的东西, 比如 5 、6 年之前 b 站分享很多时候人们还是直接说 av 号的。

    像淘宝京东这类 电商,他们肯定不希望可以从订单号看出什么规律,且不说万一有什么权限 bug ,导致瞎拼的 id 可以访问到其它人的数据,但从规律自增让其它竞争对手可以统计他们每日交易量就是个大风险。
    Torpedo
        60
    Torpedo  
       7 天前
    id 暴露很正常,但是还是不要暴露自增的吧
    iyaozhen
        61
    iyaozhen  
       7 天前
    不要自增就行,不然要是有漏洞会被一下子遍历走

    而且竞争对手能知道你的业务量了
    TonyDutton
        62
    TonyDutton  
       7 天前
    通过 hashids 装饰自增主键再暴露的方案是否有点自欺欺人?采用这样的方案一般就不会再更改盐值了,盐值对内部开发来说都是可获取的硬编码(),那么总有一天盐值会被暴露到外部
    yuezk
        63
    yuezk  
       7 天前
    @dylanqqt #54 京东这个页面是所有人都可以查看的,并不涉及权限验证,用自增问题不大。如果涉及权限验证,你再用自增,就有可能(比如,权限验证有漏洞)被别人猜到 ID ,然后越权访问。但是,如果用 UUID ,即便权限验证有漏洞,也很难被别人利用。这一点,#32 楼已经说的很清楚了
    lyxxxh2
        64
    lyxxxh2  
       7 天前
    这只能说看需求...
    反正我全是自增,且暴露。
    接口都是要登录,不是你的数据你也看不了。

    之前加密我用的:
    https://github.com/vinkla/laravel-hashids
    tabc2tgacd
        65
    tabc2tgacd  
       7 天前
    会暴露业务详情的有规律生成的 id 不应该被暴露。比如用户 ID 用了自增的,那可以猜出你有多少用户之类的。
    fengjianche
        66
    fengjianche  
       7 天前
    用 唯一索引字段值
    Wuuuu
        67
    Wuuuu  
       7 天前
    如果数据库又想自增,展示又怕暴露可以试试 hashids 的库
    liuidetmks
        68
    liuidetmks  
       6 天前
    @dylanqqt 接口配置是错误,自增 id 是放大了这种错误

    系统内部状态一般尽量少向外暴露避免被利用,典型的例子就是长度扩展攻击伪造签名
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   731 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:44 · PVG 03:44 · LAX 11:44 · JFK 14:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.