应用程序开发中的Session Token — 它是什么、工作原理及与JWT的区别

作者: IT Sectr 发布日期: 2026-04-05 阅读时间: 9 分钟

Session Token — 是服务器在用户成功身份验证后创建的唯一标识符,用于标识后续请求。与自包含令牌(JWT)不同,session token 是一个随机字符串,本身不包含数据:所有关于会话的信息都存储在服务器的内存或数据库中。根据 OAuth.com,2025 的数据,session token 仍然是服务器端 Web 应用程序和混合移动架构中最常见的身份验证机制。

要点

  • Session Token — 引用服务器会话数据的随机标识符
  • Stateful — 服务器在 Redis、Memcached 或数据库中存储会话状态
  • 简单撤销 — 只需删除服务器上的会话记录,令牌即失效
  • 安全性 — 数据不存储在令牌中,排除了通过解码泄露的可能性
  • Cookie — 在 Web 应用程序中传输 session token 的传统方式,带有 HttpOnly、Secure 和 SameSite 标志

什么是 Session Token?

Session Token(会话标识符)— 是服务器生成并在用户身份验证后与会话数据相关联的唯一字符串。令牌不包含任何关于用户的信息 — 它只是服务器上存储数据的键。这种方法称为 stateful 身份验证:服务器存储每个活动会话的状态,并在每次请求时进行检查。

会话数据包括:用户标识符、登录时间、IP 地址、user-agent、权限列表(permissions)、最后活动时间。当客户端发送带有 session token 的请求时,服务器在会话存储中找到相应的记录,验证其有效性,并提取数据以处理请求。如果会话记录不存在或已过期,服务器返回身份验证错误并要求重新登录。

根据 OWASP,2025 的数据,session token 仍然是需要即时撤销访问权限的应用程序的标准 — 例如在银行系统和企业门户中,管理员必须能够立即终止用户的会话。在此类系统中,session token 提供对访问的完全控制,这是 stateless 令牌在没有额外阻塞机制的情况下无法实现的。

Session Token 如何工作

工作过程始于客户端向身份验证服务器发送凭据。服务器检查用户名和密码,在存储中(通常是 Redis 或数据库)创建会话记录,并向客户端返回唯一的 session token。客户端保存令牌并在每个后续请求中发送它,服务器每次都检查会话的存在和有效性。

服务器会话和存储

Redis — 由于内存存储和对 TTL(生存时间)的支持,是最流行的会话存储。每个会话存储为键值对,其中键是 session token,值是包含会话数据的 JSON 对象。TTL 自动删除过期的会话。替代方案:Memcached(仅内存,不保存到磁盘)、PostgreSQL/MySQL(持久性但较慢)和 DynamoDB(用于 AWS 基础设施)。

Redis 中会话结构的示例:session:{token}{“userId”: 42, “role”: “admin”, “createdAt”: 1812345678, “lastAccess”: 1812345678}。服务器在每个请求时更新 lastAccess,这允许实现不活动超时 — 在不活动期后自动终止会话。

Cookie 与 Header

Session Token 可以通过两种方式传输:通过 HTTP cookie 或通过 HTTP Authorization 标头。Cookie — 针对 Web 应用程序的传统方式:服务器设置带有 HttpOnly(JavaScript 无法访问)、Secure(仅 HTTPS)和 SameSite(防止 CSRF)标志的 cookie。对于移动应用程序,更常使用 Authorization: Bearer <session_token> 标头,因为 cookie 机制在本地客户端中并不总是方便。

Session Token 的生命周期

Session token 的生命周期包括三个阶段:创建、维护活动会话和终止。每个阶段都需要正确的安全配置以防止令牌泄露或拦截。

创建、存储和删除

创建 — 服务器生成长度为 128–256 位的加密安全随机字符串(例如,通过 Java 中的 SecureRandom 或 Python 中的 os.urandom)。令牌必须是不可预测的 — 不允许使用没有熵的 UUID 或时间戳。存储在客户端:在 iOS 中 — Keychain,在 Android 中 — EncryptedSharedPreferences,在 Web 中 — HttpOnly cookie。删除在注销时发生:客户端从存储中删除令牌,服务器从 Redis 中删除会话记录。注销后,session token 变得无用 — 服务器将找不到相应的记录。

根据 SANS Institute,2025 的数据,正确实现会话终止(在服务器上清理的注销)可以防止高达 70% 的利用被盗令牌的攻击。关键不仅要在客户端删除令牌,还要在服务器上撤销会话。

Session Token 与 JWT

Session Token 和 JWT 代表了两种不同的身份验证方法。Session Token — stateful(服务器存储状态),JWT — stateless(数据在令牌内部)。两者之间的选择取决于应用程序的架构和安全要求。

标准Session TokenJWT
模型Stateful(数据在服务器上)Stateless(数据在令牌中)
撤销即时 — 从 Redis 中删除会话需要黑名单或短 TTL
大小16–64 字节500–2000 字节
数据存储仅在服务器上(安全)在令牌内(base64,未加密)
扩展性需要共享存储(Redis)不需要 — 令牌本地验证
CSRF 保护需要 SameSite cookie + CSRF token不需要(令牌在标头中)

何时选择 Session Token

Session Token 在以下情况下更可取:需要即时撤销会话(银行业务、管理面板),应用程序在一个或多个共享 Redis 的服务器上运行,会话数据较大且无法容纳在 JWT 中,或者团队想要将通过令牌解码泄露数据的风险降至最低。在此类场景中,session token 在可疑活动时提供即时访问阻止 — 只需从 Redis 中删除一条记录,用户的所有会话就会失效。

根据 Redis,2025 的数据,在会话密钥级别使用 TTL(EXPIRE 命令)会自动清理过期的会话,而无需增加后台任务的成本。对于 TTL 为 1 小时且负载为 10,000 名并发用户(会话大小为 1 KB)的会话,Redis 消耗约 1 GB 的 RAM,这使得它对大多数应用程序来说具有经济高效性。

Session Token 的安全性

Session token 的安全性基于两个原则:令牌必须是不可预测的,并且在传输和存储过程中受到保护。主要威胁 — 令牌拦截(中间人攻击、XSS)、令牌预测(弱生成)和会话固定(session fixation)。

防止令牌被盗

保护包括:对所有带有令牌的请求使用 HTTPS,设置较短的会话 TTL(15–60 分钟不活动),将会话绑定到 IP 和 user-agent(每次请求时额外检查),对 cookie 使用 Secure 和 HttpOnly 标志,在敏感操作(更改密码、提升权限)后定期轮换 session token。OWASP 还建议在登录后创建新会话时实现旧会话无效化的 会话管理 — 这可以防止会话固定。

根据 OWASP ASVS,2025 的数据,会话应至少绑定两个因素:令牌本身(客户端拥有的)和 IP/user-agent(服务器知道的)。如果这些因素不匹配,服务器应终止会话并要求重新身份验证。

Kotlin 中的实现示例

以下是在 Kotlin 中使用 Spring Boot 和 Redis 的服务器端 session token 实现示例。服务器通过 SecureRandom 生成加密安全的令牌,将会话存储在 Redis 中并设置 TTL,并在每个请求时对其进行验证。代码演示了三个主要操作:创建会话、验证和无效化。

kotlin
data class Session(
    val userId: Long,
    val role: String,
    val createdAt: Long,
    val lastAccess: Long
)

object SessionManager {
    private val redis = JedisPool("localhost", 6379)

    fun createSession(userId: Long, role: String): String {
        val token = generateSecureToken()
        val session = Session(userId, role, now(), now())
        redis.resource.use { conn ->
            conn.setex("session:$token", 3600, toJson(session))
        }
        return token
    }

    fun validateSession(token: String): Session? {
        redis.resource.use { conn ->
            val json = conn.get("session:$token") ?: return null
            return fromJson(json)
        }
    }

    fun invalidateSession(token: String) {
        redis.resource.use { it.del("session:$token") }
    }

    private fun generateSecureToken(): String {
        val bytes = ByteArray(32)
        SecureRandom().nextBytes(bytes)
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes)
    }
}

此实现使用 JedisPool 进行线程安全的 Redis 连接。createSession 方法设置 1 小时(3600 秒)的 TTL — 此后 Redis 将自动删除记录。validateSession 方法对不存在或已过期的会话返回 null,允许服务器正确处理带有无效令牌的请求并返回 HTTP 401。

常见问题解答

Session token 与 access token 有何不同?

Session token — 是服务器会话的标识符(stateful)。Access token — 是用于访问 API 的凭据(可以是 JWT 或 opaque)。Session token 通常用于 Web 会话,access token 用于移动和 SPA 应用程序中的 API 请求。它们可以共存:session token 用于 Web,access token 用于 API。

如何保护 session token 免受 XSS 攻击?

主要保护是在带有会话令牌的 cookie 上设置 HttpOnly 标志。此标志禁止从 JavaScript 访问 cookie,从而使 XSS 攻击无法窃取令牌。此外,SameSite=Strict 标志可防止 cookie 随跨站请求一起发送,从而防范 CSRF。

Session token 应该存活多长时间?

建议设置两个超时时间:绝对超时(8–24 小时 — 会话的最长生命周期)和相对超时(15–30 分钟不活动 — 之后会话终止)。对于银行应用程序,绝对超时缩短至 1–2 小时,对于电子邮件客户端,最长可达 7 天。

什么是会话固定(session fixation)?

Session fixation — 一种攻击,攻击者强迫用户使用已知的会话标识符。保护措施:成功身份验证后,服务器应创建新的 session token,而不是继续使用客户端发送的令牌。旧令牌无论其来源如何都应被无效化。

Session token 可以在 REST API 中使用吗?

可以,如果客户端在 Authorization 标头(而非 cookie)中传递它,session token 适用于 REST API。对于移动应用程序,这是常见做法。缺点:在扩展到多台服务器时,将需要共享会话存储(Redis),这会在架构中增加一个故障点。

总结

  • Session Token — 引用服务器会话数据的 stateful 标识符
  • 优势 — 即时撤销和对服务器上会话的完全控制
  • 存储 — Redis、Memcached 或带有 TTL 的数据库用于自动清理
  • 安全性 — SecureRandom 生成、HTTPS、HttpOnly + SameSite cookie
  • Session 与 JWT — Session 更容易撤销,JWT 更容易扩展
  • 超时 — 绝对(8–24 小时)和相对(15–30 分钟不活动)
  • 会话固定 — 通过在登录后创建新令牌来防止

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读