现在貌似大多数网站用户认证都是基于 session 的,即在服务端生成用户相关的 session 数据,而发给客户端 sesssion_id 存放到 cookie 中,这样用客户端请求时带上 session_id 就可以验证服务器端是否存在 session 数据,以此完成用户认证。这种认证方式,可以更好的在服务端对会话进行控制,安全性比较高(session_id 随机),但是服务端需要存储 session 数据(如内存或数据库),这样无疑增加维护成本和减弱可扩展性(多台服务器)。 CSRF 攻击一般基于 cookie 。另外,如果是原生 app 使用这种服务接口,又因为没有浏览器 cookie 功能,所以接入会相对麻烦。
基于 token 的用户认证是一种服务端无状态的认证方式,服务端不用存放 token 数据。用户验证后,服务端生成一个 token(hash 或 encrypt)发给客户端,客户端可以放到 cookie 或 localStorage 中,每次请求时在 Header 中带上 token ,服务端收到 token 通过验证后即可确认用户身份。这种方式相对 cookie 的认证方式就简单一些,服务端不用存储认证数据,易维护扩展性强, token 存在 localStorage 可避免 CSRF , web 和 app 应用这用接口都比较简单。不过这种方式在加密或解密的时候会有一些性能开销(好像也不是很大),有些对称加密存在安全隐患(aes cbc 字节翻转攻击)。
假如现在我想做一个适用于 web 和 native app 的 api 服务,该如何选择认证方式?还有如果使用基于 token 的认证方式, token 的设计有没有什么比较好的解决方案?
1
murmur 2016-05-04 11:26:25 +08:00
这两个实际上不冲突 就算是基于 token 也可以在登录的时候访问你所有的子系统把上面的 session 激活了 oauth 一样可以 session
想不泄露只能 https 传输 session id 都被偷了那就没办法了 以前 ecshop 的 session 是绑了 ip 的 pc 端无所谓 移动端可能会有问题 我不知道跨信号区时 ip 会不会变 还有见过的 神级办公室 一个办公室 2 个接入商(大概是电信联通双接入?) 但是策略没配置好 自己没事切 ip 玩 |
2
neutrino 2016-05-04 11:26:53 +08:00
|
4
shiji 2016-05-04 11:43:28 +08:00
外加:
http://security.stackexchange.com/questions/19676/token-based-authentication-securing-the-token 不过有 jwt 这种现成的,还是直接拿来用更安全一些 |
5
SmiteChow 2016-05-04 11:55:38 +08:00
为什么说 token 不需要存储?
|
6
jimrok 2016-05-04 12:03:50 +08:00
token 的方式更适合 api 使用,原理上和 session 使用的 cookie 没有太大的差别,但 token 更加简单, token 可以从后端应用发放。而 session 的 cookie 必须在 web 层产生和发放。
|
7
hxsf 2016-05-04 12:18:34 +08:00 via Android
token 你也要存的 原理和 session+cookies 一样的。
|
9
chaegumi 2016-05-04 12:24:59 +08:00
最近刚搞好了 jasig cas
|
10
tabris17 2016-05-04 12:25:43 +08:00
这两个有本质区别么?
|
12
qurioust OP @neutrino @shiji @bobuick jwt 确实是基于 token 认证的一种比较好的实现方法,而且是行业标准 rfc7519 ,可以通过解码确认用户身份,这个我之前不知道,学习了。
我看到的 token 实现方式有多种,主要参考了这个: http://security.stackexchange.com/questions/81756/session-authentication-vs-token-authentication |
13
Niphor 2016-05-04 14:21:41 +08:00
想起最近 搭个 node 渲染服务,后台 java 同学非要来 token 认证来取数...
我是蛋疼的不要不要的,同一内网机子,还来 设备认证 + token 认证 + csrf... |
14
guotie 2016-05-04 14:31:48 +08:00
用 jwt , token 不还是要保存?
|
15
CodingWorker 2016-05-04 14:37:57 +08:00
学到了
|
16
realpg 2016-05-04 14:39:00 +08:00
为啥只有我觉得 token 和 session 就是一回事……
token 不就是 sessionid 么…… |
18
GavinHao 2016-05-04 14:47:39 +08:00 via Android
jwt 的服务端实现是无状态的,在服务器端不需要保存 session 的,对于客户端而言倒类似于 session ID ,但不是去服务端找对应 session ,而是解码后校验。如有理解错误请指正。
|
19
realpg 2016-05-04 14:49:22 +08:00
@julyclyde
未必。而且 session 未必是 cookie 承载。现在已经没有人禁用 cookies 了,所以大家忘记了当年 session 的基本约定俗成规范是啥样的了。 说 token 是 session 的一种都不为过。不就是 sessionid=xxx 变成了 token=xxx 么 如果你写 java 版客户端,比如类似 android 客户端,使用 session 比使用 token 更省事,我指的 cookie 实现的 session , httpclient 之类直接外挂个储存的 cookiejar ,代码比 token 处处需要动传输数据结构更干净,而且可以实现 HEAD ,这对于 post/get 字串的方式来说,对于高性能系统优势明显 |
20
julyclyde 2016-05-04 14:55:33 +08:00
@realpg 我也没说 session 是 cookie 承载啊,你这不是竖个靶子自己打么; java 派似乎更偏好 querystring 承载。
状态的“内容”是保存在服务器端的,提供服务器端使用 session 数组读出内容的能力。 token 是 不承诺 提供这个的 |
21
jhdxr 2016-05-04 14:55:42 +08:00
@jimrok 可是 session 不一定非得基于 cookie 的(当然时至今日大家大多使用 cookie ),例如各种 WAP 版一般直接使用 query string 来储存 session id
|
22
softgoto 2016-05-04 15:02:04 +08:00
如果在基于 Token 的用户认证机制场景下,攻击者在客户端通过抓包工具获取到 Token 后,在 Token 的有效期内是不是就可以随便玩。
如果换成 https 是不是就能解决这个问题 |
25
zorrox 2016-05-04 15:35:25 +08:00
这两个都不是同一个层次的。。。
|
26
orvice 2016-05-05 00:34:48 +08:00
@softgoto oauth2/token 很依赖 https
@GavinHao 考虑被截取没有什么意义,推荐下知乎这个问题 http://zhihu.com/question/20274730/answer/57877844 |
27
owt5008137 2016-05-05 09:44:50 +08:00 via Android
如果要深究的话, session id 不就是 session 的 token 吗?也就是 session 自带服务端缓存而已。
如果你只提供 API ,不需要长时间的交互(类似 OAuth 那样),那就不要用 session 缓存,否则就直接用 session 呗。其实 OAuth 更多考虑的是大量客户端时候的安全问题和性能问题,所以如果没必要的话,简单最好 |
28
flyingghost 2016-05-05 10:21:59 +08:00
说 token 等于 sessionid 的真是误人子弟。
虽然确实都是“客户端记录,每次访问携带”,但 token 很容易设计为自包含的,也就是说,后端不需要记录什么东西,每次一个无状态请求,每次解密验证,每次当场得出合法 /非法的结论。这一切判断依据,除了固化在 CS 两端的一些逻辑之外,整个信息是自包含的。这才是真正的无状态。 而 sessionid ,一般都是一段随机字符串,需要到后端去检索 id 的有效性。万一服务器重启导致内存里的 session 没了呢?万一 redis 服务器挂了呢? 方案 A :我发给你一张身份证,但只是一张写着身份证号码的纸片。你每次来办事,我去后台查一下你的 id 是不是有效。 方案 B :我发给你一张加密的身份证,以后你只要出示这张卡片,我就知道你一定是自己人。 就这么个差别。 |
29
qurioust OP @flyingghost 同意!我觉得这个才是基于 session 和 token 两种认证的最大区别,你这里说的更加清楚。那些说 token 也要在服务端存储的其实讲的还是 session 的思想,并没有理解这种区别。
|
30
Jakesoft 2016-05-05 10:38:25 +08:00
session 不是 20 分钟过期吗?如果今天登陆明天怎么能做到自动登录?小白求解答
|
31
julyclyde 2016-05-05 10:56:40 +08:00
@flyingghost 你这个是不对的。对于 oauth2 场景, token 生成之后、有效期以内,如果修改了 password ,则要求 oauth2 服务器吊销已经生成的 token ,即提前使其过期。如果是自包含就不能完成这个功能了
|
32
flyingghost 2016-05-05 11:19:40 +08:00
@julyclyde 我的意思是“ token 很容易设计成自包含”,不是“所有的 token 都自包含”。主要针对的也是 lz 说的场景范围。
OAuth 的 token 确实如你所说,以及还有很多设计都可以冠以“ token ”的名字,不是吗?: ) |
33
qurioust OP @julyclyde 服务器可以吊销 token ,是不是意味着要以用户 id 作为 key 来存储,这样是不是就没法实现一个账户多处登录?
|
35
julyclyde 2016-05-05 20:57:25 +08:00
@flyingghost 如果你把“还有很多设计都可以冠以“ token ”的名字”这种话都说出来,那就没啥讨论的基础了……
|
36
qurioust OP @julyclyde user 对 token 是一对多关系并且不是自包含的,那么 token 可以是一个随机字符串并作为 key , user id 作为 value ,服务端把这种 key-value 关系存储下来。这样子可以实现一对多关系,并且也不是自包含的。但是这样子服务端吊销某个用户的 token 该如何实现?因为一般缓存总不能根据 value 去查询。不太明白,还望讲解一些。或者不应该是这种 key-value 的实现方式?
|
37
julyclyde 2016-05-06 15:46:33 +08:00
@qurioust 放数据库里?我印象中常见的 oauth2 provider 都提供“列出已签发的 token ”并提供单独吊销功能的
|
38
qurioust OP @julyclyde 觉得这样要再单独存储一层关系吧,比如 user id 对应的 token 列表。当要吊销的时候再根据 user id 找到下面的所有 token ,把他们从服务端清除。
|
39
qurioust OP @julyclyde
如果直接使用数据库存储 token 的话那会方便吊销 token ,但是这种把不该持久化的东西持久化,总觉的不太好吧。 我看到一个修改密码后吊销 token 的解决方案: http://stackoverflow.com/questions/28759590/best-practices-to-invalidate-jwt-while-changing-passwords-and-logout-in-node-js 自包含的这种 token 实现吊销功能也是要单独再存储一个类似 InvalidTokenDB 的关系,觉得这个可以用 redis 来存储,方便处理过期 token 。 |
41
markocen 2016-05-07 09:51:16 +08:00
token 的优点是 web server 上不需要保存用户的信息,更容易做分布式或者 web farm
|
42
chaegumi 2016-08-16 09:55:43 +08:00
我是搞 php 的,我看不懂官网的 jwt 示例
```java import org.pac4j.http.profile.HttpProfile; import org.pac4j.jwt.profile.JwtGenerator; ... JwtGenerator<HttpProfile> g = new JwtGenerator<>("<SIGNING_SECRET>", "<ENCRYPTION_SECRET>"); HttpProfile profile = new HttpProfile(); profile.setId("<PRINCIPAL_ID>"); final String token = g.generate(profile); System.out.println(token); ``` 那几个尖括号里边的内容,能帮我举例子吗? |
43
xuxueli 2018-04-11 14:32:38 +08:00
基于 sesssion 常用于 web 接入(登陆凭证存储在 cookie 中);基于 Token 常用于 APP 接入(登陆凭证需要主动存储,如 sqlite 中);
可以了解下 XXL-SSO 啊,支持两种接入方式: http://www.xuxueli.com/xxl-sso/ |