在一个公众号外包项目里,与前同事不期而遇,他后端我前端。jwt 竟然被这样应用,想问:
1、这种使用姿势好处在哪里?感觉如果不验证 token 只读库比对的话,也许自己生成个 uuid 与 userId 做关联就可以了,为什么要用 jwt ?
2、验证 jwt 有这么耗时吗?之前用 nodejs 写过 jwt 的 demo,没有察觉到解码 jwt 的开销。
3、是否 secret 写的简短一些,token 就会短一些,解码耗时就少一些?
1
xxxy 2019-08-09 08:12:29 +08:00 via Android
你是对的
|
2
tt67wq 2019-08-09 08:22:07 +08:00
这个后端是真的菜!
|
3
justfindu 2019-08-09 08:22:24 +08:00
解码损失几乎可以忽略, 如果需要黑名单就需要缓存 jwt.
|
4
jaskle 2019-08-09 08:25:07 +08:00 via Android
jwt 黑名单是真的恶心
|
5
dk7952638 2019-08-09 08:29:50 +08:00
不懂瞎 JB 用的典型,jwt 对他而言可能只是因为很帅~
|
6
KuroNekoFan 2019-08-09 08:31:16 +08:00 via iPhone 1
还是 cookie session 好
|
7
yamedie OP 细思极恐的是:这个项目 [还] 这么做。
他走以前公司项目就是这样用 jwt 的,现在仍是。所有“我的订单 /我的某某列表”接口都需要传入 userId,jwt 形同虚设,只作为合法登录用户的凭证,接口随意篡改 userId 就能看到其他人的信息。 为此后端们研制了一种接口入参签名,把所有入参用 sha1 之类的摘要算法算出一个签名,追加到入参里,服务端检验入参有没有被篡改过。问题是前端需要把 sha1 的密钥写死在代码里。我对这种自己骗自己的行为表示过鄙视,劝过,无效。现在接口仍然这样传,累觉不爱。 |
8
xuanbg 2019-08-09 08:48:51 +08:00
这个后端对安全简直是一无所知,前端传的 userId 你也敢信?如果是 uuid 还好点,毕竟不好猜。自增 id 就等着哭吧,我随便换一个,就能对别的用户的数据为所欲为了。
|
10
greatsir 2019-08-09 08:50:56 +08:00
干他
|
11
vance 2019-08-09 08:53:38 +08:00
他原 JWT 为什么会出来都搞不懂,这样用的话
|
12
xuanbg 2019-08-09 08:53:50 +08:00 41
@yamedie 我一后端表示:这个参数验证完全是形同虚设,不说密钥能看得到,就是直接改了数据让你合法地传回去又有何难。
作为后端,基础的三不信还是要有的。三不信是: 1、前端的数据不可信 2、第三方的文档不可信 3、产品经理的承诺不可信 |
15
frantic 2019-08-09 09:01:59 +08:00
这样的人又菜又自己为是,对自己的水平一无所知,遇到过很多次。
|
16
leo108 2019-08-09 09:02:12 +08:00 3
外包项目还在考虑性能问题,真是良心(
|
17
feilaoda 2019-08-09 09:07:04 +08:00
他的理解是错的
|
18
ViewerBuc 2019-08-09 09:08:12 +08:00
哈哈,他连为什么用 JWT 都不知道
|
19
way2create 2019-08-09 09:08:59 +08:00
典型的做都没做好就考虑性能 还搞错了
|
20
ksco 2019-08-09 09:11:01 +08:00
如果项目负责人不懂技术,你可以将此事类比成一些通俗的例子说给他听听。
........或者就干脆退出这个项目吧。不要跟这种人共事,到时候出了问题说不定还要把锅推到前端头上呢 |
21
liyihang 2019-08-09 09:11:34 +08:00 2
真的讨厌你们这种有啥问题不当面沟通解决,去网上发帖的
|
22
yejinmo 2019-08-09 09:12:03 +08:00
问下
如果使用 jwt 而不存储的话,当此用户权限更改后,如何确保之前的 jwt 失效? |
23
lemonEssence 2019-08-09 09:12:34 +08:00
公司一 Java 用自增 ID 做订单号你敢信
|
24
abcbuzhiming 2019-08-09 09:13:06 +08:00
jwt 是为了让服务器没有状态,才采用的一种安全性较低,成本也较低的方案,如果一定要用服务器校验,那 jwt 就毫无意义,不如不用
|
25
yamedie OP @lemonEssence 用户 id 和订单 id 是自增的, 流水号是年月日时分秒+随机数
|
26
ksco 2019-08-09 09:15:55 +08:00
|
29
jinliming2 2019-08-09 09:20:09 +08:00 via iPhone 2
JWT 用来做短时间的认证没问题,比如超时时间 5 秒认证一次就作废,防止泄漏……
JWT 做 session 本身就有问题,一旦泄漏没办法直接吊销…… 要做吊销,只能存黑名单,但是既然都存黑名单了,又何必用 JWT 这么庞大的东西呢,一个密码安全随机数或是 UUID 就好啊,又短,还省去了 JWT 的合法性验证过程…… 所以,JWT 真的不适合做 session,只适合做临时的令牌…… |
30
meepo3927 2019-08-09 09:20:16 +08:00
干他 + 1
|
31
yejinmo 2019-08-09 09:20:31 +08:00
|
32
Bramblex2 2019-08-09 09:23:16 +08:00 via iPhone 1
@yejinmo 所以 jwt token 有时效,比如两个小时,超时了去找账户服务重新核发(不是重新登陆),虽然会有两个小时延迟,但问题还是能解决的。一些核心服务可以在业务层建权限系统,而不是靠账户服务发权限。
|
33
ksco 2019-08-09 09:25:51 +08:00
@yejinmo #31
1. 如果不知道要屏蔽哪些 Token,只知道用户 ID,那你黑名单里面就存用户 ID 和一个时间戳。所有该用户 ID,且 Token 里的时间戳在此之前的,全部拒绝掉。 2. 不允许多地登录这个之前没遇到过。临时想了一下,或许你可以在 Token 里面记录一下对应的地区,如果 Token 的地区和用户的实际地区不一样,就拒绝掉。 |
34
AlvaIM 2019-08-09 09:29:10 +08:00
哈哈哈, 这个问题就跟著名的空档滑行省油还是带档滑行省油问题一个样子, 新技术遇到了不思进取的老司机。用起来大致上是没有差了, 但是失去了 stateless 的意义, 把 Webserver 校验的压力转嫁给了数据库。
@abcbuzhiming jwt 的安全性并不是低, 签名能够防止篡改了,也就无法跨域脚本攻击了 @xuanbg 你对安全的理解有误, 直接存数据库然后对比 jwt 的 token 并没有安全上的问题, 因为你如果改了任何一个部分字符串就变了, 数据库判断就通不过了,如何篡改?这么做安全上没问题, 只是失去了 jwt 的意义而已 |
36
coang 2019-08-09 09:34:40 +08:00
@jinliming2 jwt 丢 redis 里边当 session.. 超时清除清除就好 而且 jwt 本身可以设置超时时间.. 具体怎么用都是 filter 都能做到
|
37
AlvaIM 2019-08-09 09:34:50 +08:00
楼主那位前同事应该只是复用了原来写好的鉴权部分的代码而已, 估计整个项目的代码框架都是直接用了之前的项目模板, 甚至直接老项目删删就直接拿来用了, 外包嘛, 最求成本效益最大化,谁管你代码质量, 安全性效率什么的
|
38
des 2019-08-09 09:35:18 +08:00 via Android
前端传 userId,笑死了
|
40
Bramblex2 2019-08-09 09:37:26 +08:00 via iPhone
@yejinmo
账户服务发 token,具体的业务服务根据 token 建 session 就行了啊。 如果你们就一台服务器,一个服务一把梭,当我没说过。当你有 40 台服务器,20 多个服务,还需要在不同的云不同区上有灾备的时候,你就知道 jwt 有多香了。 |
42
xomix 2019-08-09 09:46:35 +08:00
要传递 userid 就要利用用户基本信息做 hash 的 sgin,要用 jwt 就用 jwt,这两个一起传着走的是不了解认证机制吧。
|
43
wfd0807 2019-08-09 09:48:32 +08:00
你这个前端跟我们公司的前端完全不是一个水平啊
我们公司的客户端要求认证完成后返回 token 的同时,还要返回 userId,甚至所有 payload 里面的内容都要和 token 同级别返回 而每次请求的时候,还必须把 userId 传给接口,虽然服务端早特么不用 userId |
44
arrow8899 2019-08-09 09:50:58 +08:00 1
尽量别去外包吧,去外包待过一段时间,里面的人水平参差不齐,讨论问题心累 :sad:
|
45
jhhhh 2019-08-09 09:53:14 +08:00
他这做法,没有给服务器降低什么压力,倒是给数据库造成了不小的压力,token 校验的时候
|
46
unco020511 2019-08-09 09:57:24 +08:00
跟我上一个项目遇到的后端一模一样;我看到接口文档问他为啥都要传 token+userId+loginName,在 header 里传 token 不就完了吗,他说避免每次去查...
|
47
Bramblex2 2019-08-09 09:58:02 +08:00 via iPhone
@ksco
1. 有且只有账户服务统一核发 token,任何域名下面的任何服务都只认这个 token 作为「用户身份认证」,不带任何权限。并且账户服务可能需要支持各式各样的登录。 2. 如果不需要集中式的权限管理,那么权限管理直接下放到各个业务服务来处理。如果需要集中式的权限管理,那么要做的是建立集中式的服务。其他服务需要验证权限的时候直去权限服务验证权限 3. 如果建立状态,由业务服务自己跟客户端建立状态不,自行维护 |
48
abcbuzhiming 2019-08-09 09:58:34 +08:00 1
@AlvaIM jwt 的安全问题在于从基础设计上来说,缺少安全设计的最后一环:主动失效。它无法直接吊销——要吊销必须在服务器保存状态,就失去了 jwt 本来的设计目的。当然,不是所有场合都需要如此高的安全性的
|
49
Kilerd 2019-08-09 09:58:55 +08:00
1. 并不是说用了 JWT 就不需要用数据库了, 不用数据库的话 black list 是没法设计的,到头来还是要去数据库(或者是 redis ) 查一遍是否在 black list 里面。
2. JWT 就是明文传 userId 进来的(如果你存了进去的话),验证靠的是 SECRETKEY 的 HMAC 3. SECRETKEY 和 PAYLOAD 的大小没有形成明显的量级,所以最影响性能的应该是 HMAC 的算法。 4. 验证 jwt 有这么耗时吗?之前用 nodejs 写过 jwt 的 demo,没有察觉到解码 jwt 的开销。 说实话,你能说出这样的话,证明你的水平其实也不高,demo 来测试消耗怎么看都不靠谱,而是应该通过专业的 benchmark 框架进行测试。 |
50
lifeintools 2019-08-09 09:59:14 +08:00
违法了 json web token 的初衷了。。。
|
51
zr8657 2019-08-09 10:03:26 +08:00
你没必要教他,心里知道他菜就行了,毕竟他又没给你交学费,你教他干啥?
|
52
yamedie OP @Kilerd
1. 没有问题, 特殊需求下需要吊销 token 当然需要上数据库或者 redis; 2. jwt 有 decode 和 verify 两种方法, 这个区别我是知道的; 3. 我还是想知道 jwt 的密钥如果很长的话,会对验证 token 的开销造成很大影响吗? (我应该自己去实验一下, 打印一下毫秒数, 看看 cpu 负载..) 4. 我只是觉得以解码开销为理由很站不住脚, 如果 jwt 作为一个广为人知的解决方案, 在解码 /验证上存在很大 cpu 开销以至于在性能上导致 jwt 不可用, 那为什么还有这么多人在用 jwt, 另外我不是开发测试, 没有用过什么 benchmark, 最多只用过 puppeteer. |
53
g8287694 2019-08-09 10:17:05 +08:00
我记得 jwt 里面就有 time 的字段啊,而且 jwt 本身也不是永久的吧,到期过期,重新申请不就行了
|
54
luozic 2019-08-09 10:19:53 +08:00
benchmark 一下?
|
55
ResidualWind 2019-08-09 10:20:15 +08:00
怼他
|
56
linxl 2019-08-09 10:20:20 +08:00
哈哈哈 骚操作啊, 果真是菜无关乎语言. 照他这样每次都传账号密码验证算了.
|
57
Allianzcortex 2019-08-09 10:22:38 +08:00 via iPhone
jwt 注销用户从前端 window.localStorage.removeItem( ) 就好...担心复制粘贴 token 到另一台电脑上只要设置 JWT 过期时间很短就可以满足大部分需求。如果一定要求权限秒生效那就不是 jwt 的初衷,JWT Blacklist 只是权宜办法... G 上搜"JWT logout" 有很多文章和 SO 上的讨论,这个问题是有最佳实践的( :
|
58
AlvaIM 2019-08-09 10:22:57 +08:00 1
@yamedie verify 的目地是防篡改, 数据库对比字符串本身就防篡改了,这是其一, 验签是 CPU 开销而读数据库(或者是 redis )是 iO 开销,CPU 开销不容易优化,而 IO 开销一旦异步的话很容易优化。但是 jwt 的签名只不过是排列一下字符串重新 sha1 一次再判断是否相等, 对于 java 来说开销可以忽略。
有一个原则可以思考一下, 如果前端的 webserver 很多,且可以扩展,就尽量考虑让前端的 server 多耗点 CPU,降低 IO。 如果前端机器少, 那么就考虑省点 CPU, 用 IO 来换。系统的任何优化都是要有数据指标的,你的整个系统内的 CPU 核数, 决定了系统的总处理能力, 而分布式系统内带宽是有限的,总 IO 处理能力是有限的,是耗 CPU 还是耗 IO, 应该由系统的结构和业务类型来决定, 而不是仅仅针对单个功能点来看。 |
59
deepdark 2019-08-09 10:23:03 +08:00 via Android
你是对的,他连 jwt 的应用场景都不知道
|
60
jay4497 2019-08-09 10:25:23 +08:00
我寻思着这不是就拿 JWT 来做了个普通 token 的生成么,传 userid 然后比对这个用户的 token 有什么问题么,怎么会随便改个 userid 就对别人账户为所欲为呢,token 会对不上吧?求指教。。。
|
63
passerbytiny 2019-08-09 10:35:42 +08:00 3
前面几位认为 JWT 没用的,你们基本不知道 JWT 是什么。JWT 全称是 JSON Web Tokens,是 Token Token Token,只参与认证阶段,从来不参与授权。你们硬把它拿来当 Session,自然没用。
安全控制首先要分为认证和授权两个阶段,JWT 是一种很流行的认证手段,而用户权限更改后禁止原 JWT 登录(因为授权配置变更而提前吊销认证 Token )、不允许多端登录(给后来者做授权同时取消先到者的授权,或者若已给先到者授权则禁止后来者的授权,等同于同一份认证同时最多只能被授权一次)是授权阶段的处理,JWT 原本就没打算涉及到这些。 你们甚至不知道 Session 是什么,Session 是会话,其主业是会话跟踪,安全控制只是顺便做了一下。Session 做安全控制时:sessionId (由生命周期为内存的 cookie,或者 URL 会写,作为存储介质)当 Token,Session 容器做认证,Session 附带的属性用来辅助授权。 JWT 和 Session 应该同时用,JWT 最多只能替代掉 sessionId。 |
64
g8287694 2019-08-09 10:36:17 +08:00
@inwar 是的啊,LZ 这贴的勇士想法有点奇怪,多大的量还在乎这点 CPU 开销,后端的基本原则不就是不能信任前端的数据吗?如果传过的数据还和数据库对比一下,那么这不是压力往 DB 放了吗
|
66
passerbytiny 2019-08-09 10:51:56 +08:00
@abcbuzhiming #46
@g8287694 #51 @Allianzcortex #55 @inwar #59 吊销,或者说提前终止,这玩意要想生效只靠认证方是实现不了的,必须要吊销方与认证方同步数据才行。比如吊销营业执照,要是工商(吊销方)只宣布吊销而不收回营业执照,则没看到吊销声明的人(认证方)仍然会相信这个营业执照。又比如身份证丢失后的重办,如果银行系统没跟身份证系统联网,则旧证(已被吊销的 Token )仍然会被银行当成有效的身份证。(所以银行一般不会把身份证当成唯一的认证依据。) |
67
passerbytiny 2019-08-09 10:53:25 +08:00
接上,JWT 只参与认证,所以“吊销”这种操作光靠它自身,是永远解决不了的。
|
68
danmu17 2019-08-09 11:13:41 +08:00
@passerbytiny 把 JWT 拿来当 session id 用就已经是安全漏洞的范畴了。 @yamedie secret 写的简短一些,也是安全漏洞的一种,因为 HMAC 就是 MD5/SHA,所以一样可以弄个彩虹表来光速爆破。
|
69
arthas2234 2019-08-09 11:22:29 +08:00
JWT 都没理解是啥意思真水,订单列表还传 userId 也是骚操作
我们都想尽办法降低数据库的压力,能放服务器的绝不放数据库,这小老弟牛逼 |
70
zichen 2019-08-09 11:23:47 +08:00
数据库比对,jwt 的防重放功能是不是也废了?
|
71
orqzsf1 2019-08-09 11:24:16 +08:00
@passerbytiny 比如我在发廊开了一张卡,发廊消了我的卡,我的卡就失效了。这算不算只靠认证方实现注销功能?
|
72
yinjy 2019-08-09 11:34:41 +08:00
没准他以后会在简历里加一条“熟悉 JWT ”
|
73
twohappy 2019-08-09 11:43:20 +08:00
@orqzsf1 jwt 如果是 server 是发廊的话,你开的只能是不记名的储值卡,它是销不了的。logout 最简单的就是你自己把卡剪了。也就是你卡丢了,只要里面还有钱,我拣上一样可以去大宝剑。
|
74
lizhenda 2019-08-09 11:51:09 +08:00
jwt 存 redis 啊,顺便做了超时验证
|
75
phpcxy 2019-08-09 11:51:54 +08:00
他验证 token 时候不用查询数据库么,这数据库压力也被增加了啊
|
76
343382140 2019-08-09 11:53:46 +08:00
@abcbuzhiming 可以主动失效的,手动将 token 加入黑名单就可以了
|
77
Vegetable 2019-08-09 11:55:07 +08:00
真·彩笔
|
78
wingyiu 2019-08-09 11:58:28 +08:00
sql 不是一种语言吗?楼主真菜
|
79
augustpluscn 2019-08-09 12:03:43 +08:00
外包不应该实现就行,质保期内不出问题???
考虑太多了。随他怎么用呗 |
80
xuanbg 2019-08-09 12:16:55 +08:00
|
81
oneisall8955 2019-08-09 12:25:22 +08:00 via Android
@yamedie 这么恐怖还要啥 jwt🙃
|
82
gam2046 2019-08-09 12:33:04 +08:00
业务系统上没用过,自己的私下项目有用过 JWT。
对于多点登录,我简单的做法是 payload 中有签发时的客户端 IP,请求时 IP 与签发时 IP 不一致就觉得,一定程度上避免了多点登录与 JWT 泄露的风险 至于凭证吊销,我当时的做法是签发时,JWT 具有较短的有效期,当时设计为 5 分钟。也就是说权限变更或吊销,最长有 5 分钟的延迟。这种设计就需要看具体的业务系统是否能够承受这样的延迟带来的潜在风险。 换而言之,我之前的私下项目,并不支持主动吊销凭证,只能被动的等待到期,然后重新核发。 |
83
clf 2019-08-09 12:33:23 +08:00 1
emmm,我这边使用 jwt 是这样的:
1.userid 作为内容存储在 token 里。 2.服务器使用 redis 对 token 进行存储与管理,token 入数据库。 3.验证时先检验是否存在于 redis 中,再检验 token 是否合法,合法者通过,过期的清理 redis,将要过期的考虑是否再签发。(顺序可换) |
84
cigarzh 2019-08-09 12:43:05 +08:00
传说中的马拉火车
|
85
vkhsyj 2019-08-09 13:02:07 +08:00
把 jwt 当 session 用本来就很傻逼,但是现在很多人就是这么用的
|
86
reus 2019-08-09 13:19:25 +08:00 2
jwt 本质就是服务器放在客户端的一些数据,这个数据,只要可以正确解码,就可以信任。
因为只有服务器才能从原始数据构造出可以正确解码的数据,客户端不能篡改,不能伪造。 所以不是说用了 jwt 就不能有状态,例如有一些计算,开销比较大,我计算一次,放在 jwt 里,这样就不用每个请求又计算一次,直接用 jwt 里的。这种场景,也适合用 jwt。 不用那么死板的。 |
88
alian 2019-08-09 13:38:52 +08:00
jwt 网上很多资料存在误导。
需要拉黑啥的还是要存,而且如果是用到移动端的话会相对友好。 两年前折腾过一段时间,感觉如果是 web 应用不考虑扩展性,完全不需要 jwt,session 简单直接。 |
89
yulgang 2019-08-09 13:45:04 +08:00
说点不相关的,我这还有在 A 数据库里存 B 数据库的连接信息的呢!!!!迁移换环境坑死爹了。
|
90
koebehshian 2019-08-09 14:13:59 +08:00
这种项目基本没几个用户,所以漏洞敞开着也没人来。
|
91
szandy6 2019-08-09 16:25:49 +08:00
jwt 本来是 stateless 的,用来做 session 是观念还没转过来。
|
93
abcbuzhiming 2019-08-09 17:53:41 +08:00
@343382140 你的黑名单保存在哪里?服务器上吧,你这不等于服务器有了状态?你再去把 jwt 的设计思路仔细读一遍,人家用 jwt 就是为了在客户端保存数据,让服务器无状态,如果要服务器保存状态我干嘛要用 jwt,用 session,cookie 不是更好?
所有用了 jwt 还要在服务器保存状态的设计都是有问题的,jwt 的使用场合就是无状态服务器 |
94
way2create 2019-08-09 18:24:24 +08:00
@abcbuzhiming 估计很多人用框架没留意具体实现细节 现在有些框架的确给 jwt 加了白名单黑名单的功能 这玩意不用看源码也知道 要主动过期肯定要存的
|
95
chinvo 2019-08-09 18:39:10 +08:00
jti 存数据库里,需要验证有效性的时候核对 jti
至于 user id 原则上应该从 sub 取 因为 jwt 生成过程在后端,签名、加密的过程不对外暴露,所以不用担心篡改 |
96
chinvo 2019-08-09 18:40:35 +08:00
@abcbuzhiming #89 虽然初衷是无状态,但是无状态的应用场景下泄漏不能及时封堵,只能被动等待过期,这是不符合安全原则的
|
97
chinvo 2019-08-09 18:41:28 +08:00
而 session、cookie 是可以篡改的,所以折衷一下使用 jwt + jti 黑白名单,这样的设计可以提升系统的安全性
|
98
tyrealgray 2019-08-09 19:29:22 +08:00
JWT 的 renew token 的确是存 DB 的啊。 其他的不做评论
|
99
abcbuzhiming 2019-08-09 21:03:32 +08:00
@way2create 如果你要存,那就别用 jwt,既然服务器要保存状态,那就不如让客户端轻松点,而且 jwt 每次那么长一串在 http header 对带宽是个压力,本来这就是让客户端保存状态的代价。付出这个代价,没得到点好处,岂不是为了用 jwt,而用 jwt。
@chinvo session 和 cookie 能不能篡改只取决于你往它里面放什么,你要放明码的 id 肯定很容易篡改。但是我放个 uuid,来吧,篡改吧。狠一点的我照样给数据加个签名再放进去。篡改?呵呵 在数据防篡改上 jwt 并不比 session 和 cookie 更安全,至少从设计级别上 jwt 并不更安全,jwt 的全部意义就在于让客户端保存状态以让服务器无状态,这就是 jwt 设计意义 |
100
way2create 2019-08-09 21:23:03 +08:00
@abcbuzhiming 你搞错了。。。我不是对你说我要存 我是在说有些人可能框架用多了以为不用存就能主动过期了
|