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

求问:主流站点登录加密方式?

  •  
  •   acr0ss · 2020-12-21 11:56:05 +08:00 · 5218 次点击
    这是一个创建于 1428 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我想请教一下,现在业界都怎么处理登录密码传输呢?

    我看主流网站,百度、京东、淘宝和 qq 等,都会把登录密码加密传输,而且参数很多,是有什么通用加密规则吗?


    未防止不必要的跑题、炫耀等,我事先声明,我了解:
    1. 对称非对称加密基本知识
    2. 可逆非可逆摘要算法基本知识
    3. HTTPS 基本知识,包含不限于数字签名、信任机构、信任链等。


    我只想了解:
    1. 为什么加密
    2. 加密的主流通用规则
    第 1 条附言  ·  2020-12-22 10:11:35 +08:00
    根据评论大致解决了两点疑惑:
    1. 为什么加密
    A: HTTPS 网络环境不一定可信,例如证书不可靠等;防止明文被截获。

    2. 加密的主流通用规则
    A: 暂无可靠回复。


    于此,我又有 2 个新问题:
    1. 加密之后是否可以解密?
    2. 多登录来源,如果保证加密一致性?这种方案是否容易维护?(毕竟 APP 发版时间难说)
    69 条回复    2020-12-24 14:30:25 +08:00
    3dwelcome
        1
    3dwelcome  
       2020-12-21 12:28:22 +08:00
    就是防止中间人嗅探密码吧,https 传输的证书也不是完全可信的。密码不加密的话,万一本地被注入了第三方根证书,那不就验证通过,直接看到密码了。
    xmumiffy
        2
    xmumiffy  
       2020-12-21 12:31:32 +08:00 via Android
    没有,有些只是为了编码
    xmumiffy
        3
    xmumiffy  
       2020-12-21 12:32:44 +08:00 via Android
    不过你说的这些站都是早期从 http 过来的系统,即使现在上了 https 也还在沿用以前的体系,反正不改也不会有问题
    Mitt
        4
    Mitt  
       2020-12-21 12:37:29 +08:00   ❤️ 1
    你可以再对比下国外的主流网站,就会发现只有国内的普遍会二次加密,主要就是历史遗留,http 时代劫持和中间人问题太严重,加上国内的网络环境并不是那么理想
    opengps
        5
    opengps  
       2020-12-21 12:42:17 +08:00   ❤️ 2
    https 是防止网络中间传输过程中的暴露
    客户端加密,是为了防止本机抓包工具等轻松看到密码明文
    至于密码在加密之前的运算环节,虽然是公开的,但是难度摆在那,难度每高一层,就能轻松排除掉一层 90%的小白攻击者。
    以前我网站有很多疯狂的爬虫,我只把 reffer 限制了一下,就轻松换来了清净。这个经历足够解释基础防御的重要性了。
    westoy
        6
    westoy  
       2020-12-21 12:42:52 +08:00
    这个其实就只是代表一种态度, 我平台没有你的明文密码

    就算 http 时代, 意义也不大, 针对 input[type=password]搞定向劫持拿到加密前的明文和整个表单数据太容易了
    systemcall
        7
    systemcall  
       2020-12-21 12:45:44 +08:00
    @westoy http 时代,ActiveX 的各种操作,上个网会往浏览器甚至系统里加不少东西
    3dwelcome
        8
    3dwelcome  
       2020-12-21 12:47:16 +08:00
    简单看了一下 JD,有下面这些参数。
    d: 03s0029nq3BQS9000001000g102001000h000001000j101001000e000001000g101000000h000001006l101000000b103001000h1040010...
    c: c5b7bb1712a347d9a84998dc7b42dd24
    w: 0
    appId: 1604ebb2287
    scene: login
    product: bind-suspend
    e: WBNPEK7FHYVGCTYUDSB4O5MO5LOZG5MALJQWPH6C6BGZPESVXB2J66SXYEFX26QQ654RBABHHR4CNA23UUERNDXTRM
    s: 693759515443421745

    第一个 D 参数特别的长,我也不知道为什么官方不用 16 进制,非要用一大堆 0 和 1 来表示,也许是这样看起来很酷。
    具体参数吗,就是那些 nonce, 把密码散列化,非对称魔改算法。最后再加个 JS 签名验证防止非法篡改。都是百变不离其中。
    xuanbg
        9
    xuanbg  
       2020-12-21 12:50:57 +08:00   ❤️ 4
    后端生成一个动态的盐给前端,并且拿密码加盐 hash 作为 key 寸 redis,value 是用户 id 。前端对密码加盐进行 hash 后传输。后端直接在 redis 里面以 hash 为 key 找用户 id 。
    340244120w
        10
    340244120w  
       2020-12-21 12:51:38 +08:00 via iPhone   ❤️ 2
    主要就防中间人攻击,而且多一层防护终究比没防护好。 像银行客户端的乱序键盘,猛一看似乎没啥卵用,其实可以避免别人通过监控,根据你指法位置判断出输入的字符
    acr0ss
        11
    acr0ss  
    OP
       2020-12-21 13:18:44 +08:00
    @xmumiffy 历史遗留确实是个问题,之前只考虑到网络环境是否可信。
    acr0ss
        12
    acr0ss  
    OP
       2020-12-21 13:23:45 +08:00   ❤️ 1
    @opengps 本机只是网络环境的一部分,往大了说是 HTTPS 证书不可信。
    虽说 Referer 这个单词本身是拼写错误,但也麻烦你拼写正确下!
    opengps
        13
    opengps  
       2020-12-21 13:26:13 +08:00
    @acr0ss 感谢指正
    ysc3839
        14
    ysc3839  
       2020-12-21 15:30:02 +08:00 via Android
    GitHub 好像是直接传密码的。
    http 本地加密传输也只能防止抓包,防不了中间人攻击。
    twg
        15
    twg  
       2020-12-21 16:00:42 +08:00
    @acr0ss 买的证书都是可信的吧?
    ZSeptember
        16
    ZSeptember  
       2020-12-21 16:05:30 +08:00
    https 一般不用加密
    加密应该是为了反爬吧。
    刚发现 GIthub 的登录竟然真的是 POST 一个 session,这个很 RESTful 。。
    codehz
        17
    codehz  
       2020-12-21 16:11:54 +08:00   ❤️ 1
    (但是其实如果说为了防止本地的问题或者中间人的话,人家完全可以直接替换掉你的脚本,或者直接在提交之前拿到你输入的东西。。。所以主要还是证明服务端没有原文存你的密码(
    chinvo
        18
    chinvo  
       2020-12-21 16:13:45 +08:00
    @opengps #4 但是, 但是, 我自己抓包我自己的请求, 看到密码明文又咋了

    说白了, 是为了反爬虫, 和"密码明文"没太大关系
    chinvo
        19
    chinvo  
       2020-12-21 16:14:57 +08:00   ❤️ 1
    @codehz #15 实际上如果他在登陆时使用不可逆的算法, 比如摘要算法, 那才更说明他们存了明文密码, 因为通常注册的时候没有前端加密这一步.
    kop1989
        20
    kop1989  
       2020-12-21 16:20:34 +08:00
    为什么加密:1 、防止中间人直接看到明文密码(增加破译成本)。2 、反爬虫
    加密主流规则:没有主流规则,越非主流,越难逆向越好。
    chinvo
        21
    chinvo  
       2020-12-21 16:23:27 +08:00
    @kop1989 #18 根本不防中间人, 中间人直接用加密后的结果或者登陆后的 cookie 就是了

    防中间人只能用 TLS
    kop1989
        22
    kop1989  
       2020-12-21 16:27:19 +08:00
    @chinvo #21 所以我并没有说能杜绝中间人攻击。而是“不能让中间人直接看到明文密码”。
    另外,既然是“加密”而不是“编码”,那么必然 encode 之后的结果是一次性,且是时间相关的。

    这些都能增加中间人操作的难度,而不是“杜绝”。

    这就跟门锁一样。门锁对于锁匠而言都是玩具,那并不代表所有人就可以门户洞开。
    GIntonic
        23
    GIntonic  
       2020-12-21 16:35:04 +08:00
    我认为除了防止中间人得到明文密码,使用散列还可以证明服务器没有存储明文密码,被脱裤的适合减少危害性,毕竟明文泄露比散列泄露危害更大。
    我理解的国内的各种加密、签名相当于在 https 里又实现了一遍 https,不知道对不对,希望大佬指正。我也很疑惑这似乎是国内特色,大多国外公司和开发者都没有在 https 内再加密,不知道有没有一个定论,到底是否有必要 https 内的数据再次加密。
    zwpaper
        24
    zwpaper  
       2020-12-21 16:51:36 +08:00 via iPhone
    @xuanbg 咨询一下,用 hash 作 key 的优势是什么呢?
    zwpaper
        25
    zwpaper  
       2020-12-21 16:53:55 +08:00 via iPhone
    @xuanbg 咨询一下,用 hsah 作 key 的优势是什么呢?
    crab
        26
    crab  
       2020-12-21 16:57:27 +08:00
    @Mitt 国外大网站也多数加密的。
    xuanbg
        27
    xuanbg  
       2020-12-21 17:05:54 +08:00
    @zwpaper 就是防止中间人攻击而已。密码 hash 保密的原理就是利用服务器 /用户和中间人信息不对称。但由于有彩虹表的存在,所以需要加盐来保证不被破解出 hash 对应的明文。
    xuanbg
        28
    xuanbg  
       2020-12-21 17:09:32 +08:00
    @xuanbg 因为这个 hsah 是临时的,存在时间非常短暂,使用后立即失效,不使用也只会存在几秒钟。所以在一定程度上可以有效防范爆破。
    Veneris
        29
    Veneris  
       2020-12-21 17:21:07 +08:00
    @xuanbg 这么做意义是什么,没理解什么场景需要用 密码加盐后的 hash 去找 用户 id
    Mitt
        30
    Mitt  
       2020-12-21 17:54:59 +08:00 via iPhone
    @crab 据我所知,Apple Google Facebook Twitter 均没有二次加密
    h2xai111
        31
    h2xai111  
       2020-12-21 18:03:09 +08:00
    告诉你们一个秘密,ins 可以用来爆破用户密码,啥限制都没做那种
    unixeno
        32
    unixeno  
       2020-12-21 19:23:10 +08:00 via Android
    历史遗留+反爬
    xuanbg
        33
    xuanbg  
       2020-12-21 20:04:39 +08:00
    @Veneris 没什么意义,就是登录时没有用户名,除了只有这个 hash,啥都没有。。。但对我来说信息已经足够了,我用这个 hash 能在 redis 里面找到用户 id,就表明暗号对上了,密码验证成功。
    xuanbg
        34
    xuanbg  
       2020-12-21 20:07:07 +08:00
    @Veneris 登录本质上就是客户端和服务器对暗号,我只是不直接用用户名 /密码对暗号,而是用一个临时的 hash 对暗号而已。
    qinxi
        35
    qinxi  
       2020-12-21 20:52:31 +08:00
    还有一个防 log 啊,包括 cdn/nginx.
    原本 cdn/nginx 运维不该有权限接触密码的.但是日志记录明文.那不就白瞎了
    acr0ss
        36
    acr0ss  
    OP
       2020-12-21 21:47:12 +08:00
    @codehz 非明文只要 md5 就行,何必大张旗鼓。是否明文我不关注,我只关注加密的方式是否又通用规则?
    GIntonic
        37
    GIntonic  
       2020-12-22 09:15:32 +08:00
    @xuanbg 请教一下 如果是密码加盐 hash 如何处理相同密码的问题,而且是否每次都要用不同的盐对所有密码做一次 hash ?最近也见到过登录只有一个 hash 的情况
    xuanbg
        38
    xuanbg  
       2020-12-22 09:48:17 +08:00
    @GIntonic 是的,盐是随机的。客户端要先用登录账号获取这个随机的盐。然后才能登录时只用传一个除了客户端和服务端,谁都不知道是啥的 hash 。中间人拿到这个 hash 只能一脸懵逼,尝试重放也没效果,因为这个 hash 是一次性的,当你抓到包的时候就已经失效了。
    xuanbg
        39
    xuanbg  
       2020-12-22 09:51:59 +08:00
    @GIntonic 啊,没仔细看。不是对所有用户的密码做一次 hash,而是对当前登录账号的密码加盐做一次 hash,然后也不需要保存到数据库,验证完就没用了。
    acr0ss
        40
    acr0ss  
    OP
       2020-12-22 09:54:14 +08:00
    @unixeno 反爬怎么理解?
    acr0ss
        41
    acr0ss  
    OP
       2020-12-22 10:02:41 +08:00
    @xuanbg 如果多端登录,是否多端用相同的逻辑呢?
    acr0ss
        42
    acr0ss  
    OP
       2020-12-22 10:05:57 +08:00
    @westoy 个人认为还是需要明文密码的。要不然全站多来源登录,都得统一一个加密方式,而且加密之后、效力等同于数据库密码。
    GIntonic
        43
    GIntonic  
       2020-12-22 11:37:36 +08:00
    @xuanbg 谢谢 我傻了,我一开始理解成连账号都不需要传,直接在服务端确定登录的是哪个账号
    xuanbg
        44
    xuanbg  
       2020-12-22 11:54:43 +08:00
    @acr0ss 多端肯定要逻辑一致的呀
    S4m
        45
    S4m  
       2020-12-22 12:02:37 +08:00
    客户端用的大部分是 RSA,还有一些是 RSA+AES (有点像自己重写了 SSL )
    janus77
        46
    janus77  
       2020-12-22 14:17:47 +08:00
    我个人觉得加密方式是不会统一和通用的,毕竟这是涉及安全的事,各家的考虑角度都不完全相同
    acr0ss
        47
    acr0ss  
    OP
       2020-12-22 15:32:38 +08:00
    @janus77 你这是太绝对。

    HTTPS 使用统一的加密方式,
    OAuth 授权流程大致相同
    ……

    如果登录采用数字证书类似的公私钥加密,那是可以存在通用加密规则,而且服务端还能破译密文。
    acr0ss
        48
    acr0ss  
    OP
       2020-12-22 15:33:54 +08:00
    @xuanbg 请问贵司是这种方式吗?

    个人认为还一点小问题。例如需要转发登录信息的场景。
    Veneris
        49
    Veneris  
       2020-12-22 16:39:40 +08:00
    @xuanbg 我尝试复述一下逻辑。当用户尝试登录时候,首先通过 用户名 /手机号 等方式调用一个接口,该接口取出用户的密码,生成了随机的一个盐,加起来做 hash 运算,然后在 redis 中存储了{ hash(pwd+salt) : id },然后把 salt 返回到了前端,此时前端将 用户输入的密码 +返回的盐 做一次同样的 hash 运算,然后再调用登录接口,如果此时根据前端计算的值,在 redis 中拿到了用户 id,即为登录成功,同时清除 redis 该键值对,否则,密码错误。您看,是这个逻辑吗?
    fishCulturer
        50
    fishCulturer  
       2020-12-22 17:46:55 +08:00
    之前和公司老哥讨论过这个问题,当时讨论结果是防止内部人员作恶或者是提高内部人作恶成本
    不止这个思路是否正确
    xuanbg
        51
    xuanbg  
       2020-12-22 22:01:11 +08:00
    @Veneris 是的
    EminemW
        52
    EminemW  
       2020-12-22 22:10:19 +08:00
    我之前发现很多网站是传原文的。现在所有密码都是用密码生成器生成的
    YouLMAO
        53
    YouLMAO  
       2020-12-22 23:28:35 +08:00 via Android
    加密为啥是服务端生成盐?直接客户端发送 1 版本号 2 盐 3 精盐加密后信息, 服务端对称解码,解出密码,按照数据库的真盐跟数据库精盐加密比对
    YouLMAO
        54
    YouLMAO  
       2020-12-22 23:39:57 +08:00 via Android
    避免重放很简单,一般是对用户提交信息加上 session cookie,做一次 js 签名, 如果 session 都被偷了,只能加上来源 ip 了
    lap510200
        55
    lap510200  
       2020-12-23 09:13:50 +08:00
    密码对外是加密后的明文 你说的是对客户端请求数据的加密吗 一般是让客户端根据请求数据按约定的加密方式生成签名 服务端验签,或者有的网关服务生成客户端指纹和数据包加密 验证在网关那就可以拦截
    Veneris
        56
    Veneris  
       2020-12-23 09:29:57 +08:00
    @xuanbg 这样的话,我想了想可能会有些许的问题
    1.因为每次都是与不同盐值做 hash,所以你们数据库是存了密码的明文吗,不考虑被脱裤或者内部人员作恶吗?
    2.两个使用相同密码的人,随机到了同一个盐值,会导致获取到错误的 id,虽然几率小,但是是可能存在的,因为密码与盐值都不具备唯一性;
    3.这种方式会有 hash 碰撞的可能,原则上不考虑,但比其他方式风险要高一点点;
    感觉有些过度设计了。
    hehe12980
        57
    hehe12980  
       2020-12-23 10:57:31 +08:00
    @xuanbg 你这玩意不就是对称加密么 不过秘钥是后端给的
    hehe12980
        58
    hehe12980  
       2020-12-23 10:59:10 +08:00
    @YouLMAO 服务端生成 应该怕人爬到原始 js 代码 破解了
    YouLMAO
        59
    YouLMAO  
       2020-12-23 13:12:49 +08:00
    @hehe12980 服务端生成随机盐的话, 服务端必须有明文密码呀, 这违反国际准则会被外交部谴责的
    hehe12980
        60
    hehe12980  
       2020-12-23 13:45:06 +08:00
    @YouLMAO 前端密码每次密码提交 md5 加密的结果不就行了 明文密码不做传输只做映射 基本的吧
    YouLMAO
        61
    YouLMAO  
       2020-12-23 14:44:39 +08:00 via Android
    @hehe12980 后端的数据库一般 save 加盐后的 hash,从来没有直接 md5 的,因为裸 md5 直接拿常见密码 md5 碰撞即可
    hehe12980
        62
    hehe12980  
       2020-12-23 16:15:44 +08:00
    @YouLMAO 注册的时候就是加密过的 也就是在客户端那一层再做一层加密 后面传输就不是明文了 后面服务端还是该怎么做就怎么做
    YouLMAO
        63
    YouLMAO  
       2020-12-23 16:31:30 +08:00 via Android
    大哥,这是散列那是加密呀,注册不传原文,闻所未闻,可以设计,但是 p9 架构师不批准
    hehe12980
        64
    hehe12980  
       2020-12-23 16:47:59 +08:00
    @YouLMAO 注册不传原文的好处 即使密码被中间人嗅探 那也是拿到一个串 如果传原文, 现在大部分用户都是一个密码通用, 一旦被截获, 得 所有平台通用
    xuanbg
        65
    xuanbg  
       2020-12-24 09:31:37 +08:00
    @Veneris #56 数据库怎么可能存明文???加盐哈希只不过不希望数据库存的密码 hash 直接在网络上传输罢了,数据库存的密码 hash 被抓到基本等同于密码被抓到。随机到相同盐是不可能的,这个盐你可以用雪花 id 、uuid……。至于哈希碰撞的可能性是存在的,但无限接近于 0 。因为正常情况下,这个加盐后的临时密码 hash 只存在几十个毫秒的时间。这么短的生命周期,都能碰上,那也是没办法的事情。

    这么做唯一的目的就是:不希望数据库存的密码 hash 直接在网络上传输。这也算过度设计的话,安全方面的加固,就啥都不用干了,干了就是过度设计。
    xuanbg
        66
    xuanbg  
       2020-12-24 09:40:16 +08:00
    @YouLMAO 注册为啥要传原文?传 MD5 不行吗?数据库为啥要存原文?存 md5(id+MD5)不行吗?我就告诉你吧,我的临时 hash 就是 md5(uuid+md5(id+MD5)),然后返回给客户端 uuid 。客户端计算 md5(uuid+md5(id+md5(用户输入密码))),就得到了和服务端一样的 hash 值了。这样就可以避免密码原文、密码的 MD5 值,还有数据库存的密码值暴露在网络上面。
    LostPrayers
        67
    LostPrayers  
       2020-12-24 11:19:14 +08:00
    @YouLMAO Bcrypt 加密了解一下,各种语言都有实现方案,比如 Spring Security 之类的都会内置它
    YouLMAO
        68
    YouLMAO  
       2020-12-24 11:32:29 +08:00 via Android
    @LostPrayers 为了达到不传原文,这样真的过度设计了,你点一下登录,居然要先根据 username 问后端拿盐,然后前端 hash 再回传。fb 三十亿月活看到这直摇头
    hehe12980
        69
    hehe12980  
       2020-12-24 14:30:25 +08:00
    @YouLMAO 你有相对 安全的,不所谓过度设计,月活三十亿的登录具体设计方案么
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3135 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 13:45 · PVG 21:45 · LAX 05:45 · JFK 08:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.