服务器session和jwt之争

理解JWT与Cookie在身份验证中的优劣
本文深入探讨了JWT(JSON Web Token)与Cookie在身份验证过程中的使用场景、安全性和性能表现,强调了JWT在跨域访问、无状态设计、安全性提升以及移动端应用中的优势。

1. session


session和cookie的目的相同,都是为了克服http协议无状态的缺陷,但完成的方法不同。session通过cookie,在客户端保存session id,而将用户的其他会话消息保存在服务端的session对象中,与此相对的,cookie需要将所有信息都保存在客户端。因此cookie存在着一定的安全隐患,例如本地cookie中保存的用户名密码被破译,或cookie被其他网站收集(例如:1. appA主动设置域B cookie,让域B cookie获取;2. XSS,在appA上通过javascript获取document.cookie,并传递给自己的appB)。

2. jwt:


真正讲明白的一篇文章: https://scotch.io/tutorials/the-ins-and-outs-of-token-based-authentication


The Ins and Outs of Token Based Authentication


0. 

JSON Web Tokens (JWT) 用于用户验证

jwt 不仅可用于验证用户还可用于 server 间通信验证

传统验证方式(目前大部分网站使用的方式):

现代网页应用验证用户时面临的困难

  1. app server 可能是分布式的, 有很多 server, 在一个 server 上登录了,
    其他的没登陆, 需要额外工具来解决这个问题(sticky sessions)
  2. app 使用 RESTfull api 来获取数据, RESTful api 的原则是 stateless, 但使用 session, 使用 session 和 cookies 会引入 state; 另外, 当 API server 与 app server
    可能是两个 server, 需要 允许 CORS(Cross-Origin Resource Sharing), 但是 cookies 只能在同一个 domain 中使用
  3. app 可能需要下游服务, 每个 server 都要处理 cookie(???)

解决办法: 使用 JWT 方式来验证用户

JWT 方案不使用 session 基于 token.
用户注册之后, 服务器生成一个 JWT token返回给浏览器, 浏览器向服务器请求
数据时将 JWT token 发给服务器, 服务器用 signature 中定义的方式解码
JWT 获取用户信息.

一个 JWT token包含3部分:
1. header: 告诉我们使用的算法和 token 类型
2. Payload: 必须使用 sub key 来指定用户 ID, 还可以包括其他信息
比如 email, username 等.
3. Signature: 用来保证 JWT 的真实性. 可以使用不同算法


1. 和Session方式存储id的差异

Session方式存储用户id的最大弊病在于要占用大量服务器内存,对于较大型应用而言可能还要保存许多的状态。一般而言,大型应用还需要借助一些KV数据库和一系列缓存机制来实现Session的存储。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。除了用户id之外,还可以存储其他的和用户相关的信息,例如该用户是否是管理员、用户所在的分桶(见[《你所应该知道的A/B测试基础》一文](/2015/08/27/introduction-to-ab-testing/)等。

虽说JWT方式让服务器有一些计算压力(例如加密、编码和解码),但是这些压力相比磁盘I/O而言或许是半斤八两。具体是否采用,需要在不同场景下用数据说话。


2. http://blog.rainy.im/2015/06/10/react-jwt-pretty-good-practice/



区别(仔细揣摩)

##1.

 这么基础的问题,居然还是没人说到点子上,最关键的一点是: 
* Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端 

其它细枝末节的区别,全部是由这一点造成的。 


就没人想过为什么token-based的authentication需要一堆secret key来干嘛么? 
因为状态信息全部是放在客户端,为了避免被篡改,于是需要用密码学的方法来签名/加密。 

可以自己去这里玩玩JWT的Debugger: 
http://jwt.io/ 
一进去你就会注意到两点: 
1. Token解码后就包含所有登陆信息 
2. Token你随便改一位都会提示无效 

##2.

 
session 和 token 就是个词而已…… 广义来说一切 维护用户状态的技术都是session,一切动态生成的服务端有能力 鉴别真假而本身无涵义的字符串都是token 



更多的详见: 
http://www.slideshare.net/derekperkins/authentication-cookies-vs-jwts-and-why-youre-doing-it-wrong


Goodbye PHP Sessions, Hello JSON Web Tokens

 17332 views

 on Jun 20, 2014

REST API's are meant to be stateless. What that means is that each request from a client should include all the information needed to process the request.In other words, if you are writing a REST API in PHP then you should not be using $_SESSION to store data about the client's session. But then how do we remember if a client is logged in or anything else about their state?The only possibility is that the client must be tasked with keeping track of the state.How could this ever be done securely? The client can't be trusted!

Enter JSON web tokens. A JSON web token is a bit of JSON, perhaps something that looks like this:

{
    "user": "alice",
    "email": "test@nospam.com"
}

Of course, we can't just give this to a client and have them give it back to us without some sort of assurance that it hasn't been tampered with. After all, what if they edit the token as follows:

{
    "user": "administrator",
    "email": "test@nospam.com"
}

The solution to this is that JSON web tokens are signed by the server. If the client tampers with the data then the token's signature will no longer match and an error can be raised.

The JWT PHP class makes this easy to do. For example, to create a token after the client successfully logs in, the following code could be used:

$token = array();
$token['id'] = $id;
echo JWT::encode($token, 'secret_server_key');

And then on later API calls the token can be retrieved and verified by this code:

$token = JWT::decode($_POST['token'], 'secret_server_key');
echo $token->id;

If the token has been tampered with then $token will be empty there will not be an id available. The JWT class makes sure that invalid data is never made available. If the token is tampered with, it will be unusable. Pretty simple stuff!






其余参考资料:

0. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/


What are the benefits of using a token-based approach?

  • Cross-domain / CORS: cookies + CORS don't play well across different domains. A token-based approach allows you to make AJAX calls to any server, on any domain because you use an HTTP header to transmit the user information.
  • Stateless (a.k.a. Server side scalability): there is no need to keep a session store, the token is a self-contanined entity that conveys all the user information. The rest of the state lives in cookies or local storage on the client side.
  • CDN: you can serve all the assets of your app from a CDN (e.g. javascript, HTML, images, etc.), and your server side is just the API.
  • Decoupling: you are not tied to a particular authentication scheme. The token might be generated anywhere, hence your API can be called from anywhere with a single way of authenticating those calls.
  • Mobile ready: when you start working on a native platform (iOS, Android, Windows 8, etc.) cookies are not ideal when consuming a secure API (you have to deal with cookie containers). Adopting a token-based approach simplifies this a lot.
  • CSRF: since you are not relying on cookies, you don't need to protect against cross site requests (e.g. it would not be possible to <iframe>your site, generate a POST request and re-use the existing authentication cookie because there will be none).
  • Performance: we are not presenting any hard perf benchmarks here, but a network roundtrip (e.g. finding a session on database) is likely to take more time than calculating an HMACSHA256 to validate a token and parsing its contents.
  • Login page is not an special case: If you are using Protractor to write your functional tests, you don't need to handle any special case for login.
  • Standard-based: your API could accepts a standard JSON Web Token(JWT). This is a standard and there are multiple backend libraries (.NET,RubyJavaPythonPHP) and companies backing their infrastructure (e.g. FirebaseGoogleMicrosoft). As an example, Firebase allows their customers to use any authentication mechanism, as long as you generate a JWT with certain pre-defined properties, and signed with the shared secret to call their API.

1. http://www.slideshare.net/derekperkins/authentication-cookies-vs-jwts-and-why-youre-doing-it-wrong

2. JSON Web Token - 在Web应用间安全地传递信息  http://blog.leapoahead.com/2015/09/06/understanding-jwt/
3. JWT 在前后端分离中的应用与实践 http://ju.outofmemory.cn/entry/188871
为什么选jwt?

To say a few problems…

  • Sessions: We need to store our sessions somewhere. By default they are just stored on server’s memory and having thousand of them doesn’t help. Redis does help but without sessions there are no problems then :P
  • Mobile: Native mobile apps seems to have problems working with cookies so if we need to query a remote API, maybe session auth is not the best solution.
  • CSRF: If we go down the cookies way, you really need to do CSRF to avoid cross site requests. That is something we can forget when using JWT as you will see.
  • CORS: Have you fight with CORS and cookies? I hope it went right because when it doesn’t, we have a problem.


2016.7.2
golang 与jwt 
https://xiequan.info/go%E4%B8%8Ejson-web-token/
### 区别 #### 存储方式 - **Session**:会话数据存储在服务器端,通常使用 Redis 或数据库等持久化存储。客户端只存储一个 Session ID(通常保存在 Cookie 中)[^4]。 - **JWT**:会话数据直接存储在客户端,通过加密签名的 Token 携带用户信息权限数据。Token 通常存储在 LocalStorage、Cookie 或其他前端存储中 [^5]。 #### 状态管理 - **Session**:是一种有状态机制,服务器需要维护用户的会话状态,并且在分布式环境中可能需要额外工具(如 Spring Session)来同步状态 [^4]。 - **JWT**:是无状态机制,服务器不需要维护用户的会话状态,所有必要的信息都包含在 Token 中 [^5]。 #### 性能开销 - **Session**:每次请求需要从服务器查询 Session 数据,消耗 I/O 数据库连接资源 [^1]。 - **JWT**:每次请求需要解析并验证 Token 的签名,消耗 CPU 资源 [^1]。 #### 安全性 - **Session**:依赖于 Session ID 的随机性保密性,Session ID 泄露可能导致会话劫持 [^4]。 - **JWT**:依赖于 Token 的签名算法密钥保护,Token 泄露可能导致身份冒充,因此需要更严格的存储传输保护 [^3]。 #### 数据大小与传输效率 - **Session**:Session ID 是较短的字符串,HTTP 请求头部较小 [^2]。 - **JWT**:由于携带了较多用户信息,Token 可能较长,导致 HTTP 请求头部较大,增加网络传输负担 [^2]。 --- ### 使用场景 #### Session 的适用场景 1. **传统单体应用**:前后端紧密耦合的应用中,Session 易于实现管理 [^4]。 2. **需要频繁修改会话数据**:例如购物车、实时更新的用户偏好设置等场景,因为 Session 在服务端存储,修改起来更方便 [^4]。 3. **安全性要求较高的系统**:Session ID 较短且易于更换,适合需要频繁刷新或强制注销的场景 [^3]。 #### JWT 的适用场景 1. **分布式系统与微服务架构**:JWT 的无状态特性使其非常适合跨多个服务的认证授权 [^5]。 2. **一次性授权令牌**:如密码重置链接、临时访问令牌等,JWT 可以有效避免服务器状态管理的复杂性 [^1]。 3. **移动端与前后端分离架构**:前端可以轻松存储传递 JWT,无需依赖 Cookie,更适合 RESTful API 的设计 [^5]。 4. **跨域认证**:JWT 支持跨域请求的身份验证,而不会受到同源策略的限制 。 --- ### 优缺点对比 | 特性 | Session | JWT | |------|---------|-----| | **存储位置** | 服务端存储会话数据,客户端仅存储 Session ID | 所有数据存储在客户端 | | **状态管理** | 有状态 | 无状态 | | **性能影响** | 消耗 I/O 数据库资源 | 消耗 CPU 解析资源 | | **扩展性** | 需要共享存储(如 Redis)支持分布式 | 天然支持分布式 | | **安全性** | Session ID 泄露风险 | Token 泄露风险更大 | | **传输效率** | 请求头部小 | 请求头部大 | --- ### 示例代码:JWT 生成与验证(Python) ```python import jwt from datetime import datetime, timedelta # 密钥 SECRET_KEY = "your-secret-key" # 生成 JWT def generate_jwt(user_id): payload = { "user_id": user_id, "exp": datetime.utcnow() + timedelta(hours=1) # 过期时间 } token = jwt.encode(payload, SECRET_KEY, algorithm="HS256") return token # 验证 JWT def verify_jwt(token): try: payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"]) return payload["user_id"] except jwt.ExpiredSignatureError: return "Token 已过期" except jwt.InvalidTokenError: return "无效 Token" # 示例 token = generate_jwt(123) print("生成的 Token:", token) user_id = verify_jwt(token) print("验证结果:", user_id) ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值