news 2026/9/30 7:29:52

Authentication / JWT 实战:从登录令牌到敏感信息泄露分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Authentication / JWT 实战:从登录令牌到敏感信息泄露分析

本文实验均在个人本地部署、合法授权的 OWASP Juice Shop 靶场环境中完成,仅用于安全学习与漏洞分析。

实际生产文档中不得保留真实 Token、Cookie、邮箱、密码、用户 ID、Basket ID 或其他敏感信息。

一、实验目标与环境

1.1 实验目标

本次实验针对 OWASP Juice Shop 的登录认证流程与 JWT 使用方式进行分析。

主要关注:

  1. 登录成功后服务端如何返回认证令牌。
  2. 客户端如何通过 Bearer Token 表示登录身份。
  3. JWT Header / Payload / Signature 的基本结构。
  4. JWT Payload 中是否包含不应暴露的敏感字段。
  5. Authentication 与 Authorization 的区别。

1.2 实验环境

项目说明
实验目标本地部署的 OWASP Juice Shop 授权靶场
目标地址http://127.0.0.1:3000
测试工具Burp Suite
测试账号test1@test.com
漏洞类型Authentication / JWT

二、正常登录流程

2.1 捕获登录请求

在登录界面输入测试账号:test1@test.com 测试密码:test1。开启Burp Suite拦截:

POST /rest/user/login HTTP/1.1 Host: 127.0.0.1:3000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: application/json, text/plain, */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7ImlkIjoyNCwidXNlcm5hbWUiOiIiLCJlbWFpbCI6InRlc3QxQHRlc3QuY29tIiwicGFzc3dvcmQiOiI1YTEwNWU4YjlkNDBlMTMyOTc4MGQ2MmVhMjI2NWQ4YSIsInJvbGUiOiJjdXN0b21lciIsImRlbHV4ZVRva2VuIjoiIiwibGFzdExvZ2luSXAiOiIwLjAuMC4wIiwicHJvZmlsZUltYWdlIjoiL2Fzc2V0cy9wdWJsaWMvaW1hZ2VzL3VwbG9hZHMvZGVmYXVsdC5zdmciLCJ0b3RwU2VjcmV0IjoiIiwiaXNBY3RpdmUiOnRydWUsImNyZWF0ZWRBdCI6IjIwMjYtMDktMjQgMDc6Mzg6NTUuMTQyICswMDowMCIsInVwZGF0ZWRBdCI6IjIwMjYtMDktMjQgMDc6Mzg6NTUuMTQyICswMDowMCIsImRlbGV0ZWRBdCI6bnVsbH0sImJpZCI6OSwiaWF0IjoxNzkwMjM1NTc2fQ.v1s4e3XaH-0vvYvpDxgrSDprwzQTdJ1TzMZbhgG6b3-WIB2TTjBK9X77O4tL7D3_fUuUBUPdIkjaY3yRPulQTZLstS7vtUuYEjTpWUOow6-OjIaRfdjXZHLjH-h9AYGgPo2On6xTBKy-Ot7TGCzFZf042OKnRXZeZVWAsKbHoGM Content-Type: application/json Content-Length: 45 Origin: http://127.0.0.1:3000 Connection: keep-alive Referer: http://127.0.0.1:3000/ Cookie: language=zh_CN; welcomebanner_status=dismiss; cookieconsent_status=dismiss; continueCode=P32pqXyQJYZbEekj1dKXIMSnnhXMc83TqXFR8tYRcknGn9B4Ol6VLvrWwM7x; continueCodeFindIt=JEnej6XmL2MbOGK5q1BNpgyZ0yytrzTEquDP4lJQ7DVr0WwaRdPkvx3oY9z1; continueCodeFixIt=7r7BdZOzW026GnqpYQJyvDjxbKKhBXTePuJOAwK3RME5klmgV4b98XLeoNPp Sec-Fetch-Dest: empty Sec-Fetch-Mode: cors Sec-Fetch-Site: same-origin Priority: u=0 {"email":"test1@test.com","password":"test1"}

从捕获到的登录请求可以看出,客户端在登录时向后端发送了一个 POST /rest/user/login 请求,请求体采用 JSON 格式提交用户邮箱和密码:

{ "email": "test1@test.com", "password": "test1" }

该请求的核心作用是向服务端提交用户凭证,由服务端判断账号密码是否正确。请求头中的 Content-Type: application/json 表明请求体数据格式为 JSON,后端会按照 JSON 格式解析其中的 email 和 password 字段。

需要注意的是,本次抓包中登录请求头里已经出现了 Authorization: Bearer <JWT_TOKEN> 字段。这说明当前浏览器环境中可能已经存在旧的登录状态,或者 Burp 捕获的是一次已有登录态下再次发送的登录请求。严格来说,普通登录请求本身并不依赖已有的 Bearer Token,认证身份主要依赖请求体中的邮箱和密码。

此外,请求中的 Cookie 主要包含语言、欢迎横幅、挑战进度等状态信息,例如 language、welcomebanner_status、continueCode 等。这些字段更多用于前端状态记录或靶场挑战进度维护,并不是本次登录认证的核心凭证。

综上,登录请求阶段的核心数据是请求路径、请求方法、JSON 请求体中的邮箱和密码。服务端会根据这些凭证完成 Authentication,即身份认证过程。

2.2 分析登录响应

将捕获得到得登录请求发送至Repeater模块。发送后查看相应:

HTTP/1.1 200 OK Access-Control-Allow-Origin: * X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN Feature-Policy: payment 'self' X-Recruiting: /#/jobs Content-Type: application/json; charset=utf-8 Content-Length: 787 ETag: W/"313-ixEfE1QZFnlZIWG3BLvZA/t8FFk" Vary: Accept-Encoding Date: Tue, 29 Sep 2026 08:05:15 GMT Connection: keep-alive Keep-Alive: timeout=5 {"authentication":{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJkYXRhIjp7ImlkIjoyNCwidXNlcm5hbWUiOiIiLCJlbWFpbCI6InRlc3QxQHRlc3QuY29tIiwicGFzc3dvcmQiOiI1YTEwNWU4YjlkNDBlMTMyOTc4MGQ2MmVhMjI2NWQ4YSIsInJvbGUiOiJjdXN0b21lciIsImRlbHV4ZVRva2VuIjoiIiwibGFzdExvZ2luSXAiOiIwLjAuMC4wIiwicHJvZmlsZUltYWdlIjoiL2Fzc2V0cy9wdWJsaWMvaW1hZ2VzL3VwbG9hZHMvZGVmYXVsdC5zdmciLCJ0b3RwU2VjcmV0IjoiIiwiaXNBY3RpdmUiOnRydWUsImNyZWF0ZWRBdCI6IjIwMjYtMDktMjQgMDc6Mzg6NTUuMTQyICswMDowMCIsInVwZGF0ZWRBdCI6IjIwMjYtMDktMjQgMDc6Mzg6NTUuMTQyICswMDowMCIsImRlbGV0ZWRBdCI6bnVsbH0sImJpZCI6OSwiaWF0IjoxNzkwNjY5MTE2fQ.ZeNr9GwjClOcy_exp60SOm30oNDaUS5roImseWC9YxdWsoHuuuOdUs78GXAgxvLxgDyShbfH6HaAKCO9xKQh-uicGLBN-PvudsOSf_XAbI-7WVIAU81cw35Yd1Wcpl5RAL31FuNkYpj-Iuc0uScG4kLherv-1s01GsrFFSNJjFg","bid":9,"umail":"test1@test.com"}}

将登录请求发送至 Repeater 后,服务端返回 HTTP/1.1 200 OK,说明账号密码验证通过,登录请求被成功处理。

响应体中最关键的字段是 authentication 对象:

{ "authentication": { "token": "<JWT_TOKEN>", "bid": 9, "umail": "test1@test.com" } }

其中,token 字段是服务端签发给客户端的 JWT。客户端后续访问需要登录身份的接口时,会将该 Token 放入请求头中,例如:

Authorization: Bearer <JWT_TOKEN>

这表示客户端正在使用该 Token 声明自己的登录身份。

JWT 通常由三部分组成:

Header.Payload.Signature

Header 部分用于说明令牌类型和签名算法;Payload 部分用于存放用户相关声明信息;Signature 部分用于校验 Token 是否被篡改。

在本次实验中,将 Token 解码后可以看到 Payload 中包含用户 ID、邮箱、角色、购物车 ID、头像路径、创建时间等信息(解码后文本在后文揭晓)。需要特别注意的是,Payload 中还出现了 password 字段,虽然这里保存的是哈希值而不是明文密码,但仍然属于不应暴露给客户端的敏感字段。

JWT 的 Payload 只是经过 Base64URL 编码,并不是加密。任何拿到 Token 的人都可以解码查看 Payload 内容。因此,不应在 JWT Payload 中存放密码哈希、密钥、隐私数据或其他敏感字段。

从响应结果可以看出,登录成功后,服务端不仅返回了 JWT,还返回了 bid 和 umail 字段。其中 bid 可以理解为当前用户对应的购物车 ID,umail 表示当前登录用户邮箱。这些字段会被前端用于后续业务请求。

2.3 初步结论

结合登录请求和登录响应可以看出,OWASP Juice Shop 的正常登录认证流程大致如下:

客户端向 /rest/user/login 接口提交邮箱和密码。 服务端校验用户凭证是否正确。 如果认证成功,服务端生成并返回 JWT。 客户端保存 JWT,并在后续请求中通过 Authorization: Bearer <JWT_TOKEN> 携带该令牌。 服务端根据 Token 识别当前用户身份,并决定是否允许其访问对应资源。

因此,JWT 在该流程中承担的是“登录成功后的身份凭证”作用。它不是用户密码本身,而是服务端签发给客户端的认证令牌。

需要区分的是,Authentication 和 Authorization 并不是同一个概念。

Authentication 解决的是“你是谁”的问题,例如用户通过邮箱和密码登录,服务端确认该用户身份。

Authorization 解决的是“你能访问什么”的问题,例如当前用户是否有权限访问某个购物车、订单、后台管理接口或其他用户的数据。

本次实验中,登录流程主要体现的是 Authentication。用户登录成功后拿到 JWT,说明身份认证通过。但这并不意味着该用户可以访问所有资源。后续接口仍然需要在服务端进行权限校验,否则就可能产生越权访问问题。

另外,本次实验也暴露出一个 JWT 设计上的安全问题:Token Payload 中包含了过多用户信息,甚至包含密码哈希字段。由于 JWT Payload 可以被客户端直接解码查看,因此服务端在设计 Token 内容时应遵循最小化原则,只放入必要的身份标识信息,例如用户 ID、角色、签发时间、过期时间等,不应放入密码哈希、隐私字段或其他敏感数据。

综上,Juice Shop 的登录流程可以概括为:账号密码完成身份认证,JWT 作为后续请求的身份凭证,Bearer Token 负责在请求头中传递该凭证,而真正的资源访问安全还依赖服务端后续的权限校验。

三、JWT 结构分析

3.1 JWT 三段结构

JWT 的基本结构由三部分组成:

Header.Payload.Signature

本次登录响应中返回的 Token 同样符合该结构。按照.进行分割后,可以得到三段内容:

部分观察结果
HeadereyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
PayloadeyJkYXRhIjp7ImlkIjoyNCwidXNlcm5hbWUiOiIiLCJlbWFpbCI6InRlc3QxQHRlc3QuY29tIiwicGFzc3dvcmQiOiI1YTEwNWU4YjlkNDBlMTMyOTc4MGQ2MmVhMjI2NWQ4YSIsInJvbGUiOiJjdXN0b21lciIsImRlbHV4ZVRva2VuIjoiIiwibGFzdExvZ2luSXAiOiIwLjAuMC4wIiwicHJvZmlsZUltYWdlIjoiL2Fzc2V0cy9wdWJsaWMvaW1hZ2VzL3VwbG9hZHMvZGVmYXVsdC5zdmciLCJ0b3RwU2VjcmV0IjoiIiwiaXNBY3RpdmUiOnRydWUsImNyZWF0ZWRBdCI6IjIwMjYtMDktMjQgMDc6Mzg6NTUuMTQyICswMDowMCIsInVwZGF0ZWRBdCI6IjIwMjYtMDktMjQgMDc6Mzg6NTUuMTQyICswMDowMCIsImRlbGV0ZWRBdCI6bnVsbH0sImJpZCI6OSwiaWF0IjoxNzkwNjY5MTE2fQ
SignatureZeNr9GwjClOcy_exp60SOm30oNDaUS5roImseWC9YxdWsoHuuuOdUs78GXAgxvLxgDyShbfH6HaAKCO9xKQh-uicGLBN-PvudsOSf_XAbI-7WVIAU81cw35Yd1Wcpl5RAL31FuNkYpj-Iuc0uScG4kLherv-1s01GsrFFSNJjFg

其中,Header 和 Payload 可以通过 Base64URL 解码直接查看内容;Signature 是服务端使用私钥对 Header 和 Payload 计算得到的签名值,主要用于校验 Token 是否被篡改,不能像普通 JSON 一样直接解码成可读字段。


3.2 Header 解码

对 JWT 第一段 Header 进行 Base64URL 解码后,可以得到如下内容:

{"typ":"JWT","alg":"RS256"}

其中:

  • typ: JWT表示该令牌类型为 JWT。
  • alg: RS256表示该 JWT 使用 RS256 签名算法。

RS256 属于非对称签名算法,服务端使用私钥生成签名,验证方可以使用对应公钥验证签名是否正确。这里需要注意,Header 中的算法字段只说明该 Token 声称使用的签名算法,真正判断 Token 是否可信,还需要服务端在验证阶段正确校验签名。


3.3 Payload 解码

对 JWT 第二段 Payload 进行 Base64URL 解码后,可以得到如下内容:

{"data":{"id":24,"username":"","email":"test1@test.com","password":"5a105e8b9d40e1329780d62ea2265d8a","role":"customer","deluxeToken":"","lastLoginIp":"0.0.0.0","profileImage":"/assets/public/images/uploads/default.svg","totpSecret":"","isActive":true,"createdAt":"2026-09-24 07:38:55.142 +00:00","updatedAt":"2026-09-24 07:38:55.142 +00:00","deletedAt":null},"bid":9,"iat":1790669116}

可以看到,Payload 中主要包含三类信息:

第一类是用户身份信息,例如id、email、role。这些字段用于表示当前登录用户是谁,以及该用户在系统中的角色。

第二类是业务相关信息,例如bid。结合前文登录响应中的"bid": 9可以判断,该字段表示当前用户对应的 Basket ID,也就是购物车 ID。

第三类是用户账户状态与扩展字段,例如isActive、createdAt、updatedAt、deletedAt、profileImage、lastLoginIp、totpSecret等。这些字段并非每次接口鉴权都必须使用,但仍被放入了 JWT Payload 中。

其中,iat表示 issued at,即 Token 签发时间。这里的1790669116对应的时间约为2026-09-29 08:05:16 UTC,与前文响应头中的时间Tue, 29 Sep 2026 08:05:15 GMT基本一致,说明该 Token 是本次登录成功后由服务端新签发的。

需要重点注意的是,Payload 中出现了password字段,值为:

5a105e8b9d40e1329780d62ea2265d8a

虽然这里不是明文密码,而是密码哈希值,但仍然不应该出现在 JWT Payload 中。因为 JWT 的 Payload 只是 Base64URL 编码,不是加密。任何拿到 Token 的人都可以直接解码查看其中内容。


3.4 敏感字段观察

字段是否出现风险说明
用户 ID是,id: 24用户 ID 属于身份标识信息,暴露后可能被用于后续越权测试、用户枚举或接口参数猜测。
邮箱是,email: test1@test.com邮箱属于用户身份信息,暴露后可能造成隐私泄露,也可能被用于撞库、钓鱼或用户枚举。
角色是,role: customer角色字段会暴露当前用户权限级别。如果服务端错误信任客户端可控的角色字段,可能引发权限绕过。
Basket ID是,bid: 9Basket ID 属于业务对象标识。若后端接口未校验购物车归属关系,可能引发水平越权访问。
密码哈希是,password: 5a105e8b9d40e1329780d62ea2265d8a即使不是明文密码,密码哈希也不应返回给客户端。攻击者拿到哈希后可能尝试离线破解或彩虹表查询。
TOTP / 二次验证字段是,totpSecret: ""当前值为空,但字段本身不应暴露。如果真实环境中该字段存在有效值,会直接影响二次验证安全性。
其他敏感字段是,lastLoginIp、deluxeToken、createdAt、updatedAt等这些字段会暴露用户登录状态、账户时间信息或业务扩展信息。虽然部分字段当前为空,但仍不建议全部放入 JWT。

3.5 本节小结

通过对 JWT 的 Header 和 Payload 进行解码可以发现,Juice Shop 登录成功后返回的 Token 中包含了较完整的用户对象信息。

从认证流程角度看,该 JWT 可以作为客户端后续请求的身份凭证。客户端访问需要登录态的接口时,只需要在请求头中携带:

Authorization: Bearer <JWT_TOKEN>

服务端即可根据该 Token 识别当前用户身份。

但是,从安全设计角度看,该 JWT Payload 中包含的信息过多,尤其是password密码哈希字段不应返回给客户端。JWT 的 Payload 只是编码,不是加密,因此不能把它当成安全存储空间。

更合理的做法是,JWT Payload 中只保留必要的最小身份声明,例如:

{"id":24,"role":"customer","iat":1790669116,"exp":1790672716}

其中:

  • id用于标识用户身份。
  • role用于辅助权限判断。
  • iat表示签发时间。
  • exp表示过期时间。

密码哈希、二次验证密钥、邮箱、登录 IP、完整用户对象、购物车 ID 等信息都不应直接放入 JWT Payload 中。

因此,本节可以得出初步结论:JWT 可以用于登录后的身份认证,但 JWT Payload 不应存放敏感数据。服务端应遵循最小化原则设计 Token 内容,并在后续业务接口中继续进行严格的权限校验。

四、Bearer Token 使用验证

本节选择当前登录用户的购物车接口作为验证目标:

GET /rest/basket/9 HTTP/1.1 Host: 127.0.0.1:3000

其中,9来自前文 JWT Payload 中的bid字段,表示当前用户对应的 Basket ID。

为了验证服务端到底依赖哪个位置的 Token 识别登录身份,本节设计四组对照实验:

测试组Authorization Bearer TokenCookie 中的 token测试目的
第一组有有正常登录状态基线
第二组无无验证无 Token 时是否被拒绝
第三组有无验证 Authorization 头是否可单独完成认证
第四组无有验证 Cookie 中的 token 是否可单独完成认证

需要说明的是,请求中的其他 Cookie,例如language、welcomebanner_status、continueCode等,主要与前端状态或靶场挑战进度有关,不作为本节认证测试的核心对象。本节重点观察的是Authorization: Bearer <JWT>和Cookie: token=<JWT>。


4.1 第一组:同时携带 Authorization 与 Cookie Token

第一组保留浏览器正常请求中的两处 Token:

GET /rest/basket/9 HTTP/1.1 Host: 127.0.0.1:3000 Authorization: Bearer <JWT_TOKEN> Cookie: ...; token=<JWT_TOKEN>

服务端响应结果如下:

HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8

响应体中返回了购物车资源:

{"status":"success","data":{"id":9,"UserId":24,"Products":[{"id":51,"name":"浆果汁 (1000ml)","BasketItem":{"ProductId":51,"BasketId":9,"id":28,"quantity":1}}]}}
检查项结果
HTTP 状态码200 OK
是否返回用户资源是
返回资源归属Basket ID 为9,UserId 为24
结论同时携带 Authorization 和 Cookie Token 时,请求可以正常访问当前用户购物车资源。

该组属于正常登录态下的基线请求,用于确认目标接口和 Token 本身有效。


4.2 第二组:不携带 Authorization,也不携带 Cookie Token

第二组删除Authorization请求头,同时删除 Cookie 中的token=<JWT>字段,仅保留其他普通 Cookie:

GET /rest/basket/9 HTTP/1.1 Host: 127.0.0.1:3000 Cookie: language=zh_CN; welcomebanner_status=dismiss; cookieconsent_status=dismiss; ...

服务端响应结果如下:

HTTP/1.1 401 Unauthorized Content-Type: application/json; charset=utf-8

响应体中返回错误信息:

{"error":{"message":"No Authorization header was found","name":"UnauthorizedError","code":"credentials_required","status":401,"inner":{"message":"No Authorization header was found"}}}
检查项结果
HTTP 状态码401 Unauthorized
是否返回用户资源否
错误信息No Authorization header was found
结论不携带有效认证凭证时,服务端拒绝访问购物车资源。

该结果说明/rest/basket/9不是公开接口,访问该接口需要认证凭证。服务端错误信息明确指出缺少Authorization请求头。


4.3 第三组:只携带 Authorization Bearer Token

第三组保留Authorization: Bearer <JWT>,但删除 Cookie 中的token=<JWT>字段:

GET /rest/basket/9 HTTP/1.1 Host: 127.0.0.1:3000 Authorization: Bearer <JWT_TOKEN> Cookie: language=zh_CN; welcomebanner_status=dismiss; cookieconsent_status=dismiss; ...

服务端响应结果如下:

HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8

响应体中同样返回了当前用户购物车资源:

{"status":"success","data":{"id":9,"UserId":24,"Products":[{"id":51,"name":"浆果汁 (1000ml)","BasketItem":{"ProductId":51,"BasketId":9,"id":28,"quantity":1}}]}}
检查项结果
HTTP 状态码200 OK
是否返回用户资源是
返回资源归属Basket ID 为9,UserId 为24
结论仅携带Authorization: Bearer <JWT>时,请求可以通过认证并访问当前用户资源。

该结果说明,对于该接口而言,Authorization请求头中的 Bearer Token 可以单独作为登录身份凭证使用。


4.4 第四组:只携带 Cookie Token

第四组删除Authorization请求头,仅保留 Cookie 中的token=<JWT>字段:

GET /rest/basket/9 HTTP/1.1 Host: 127.0.0.1:3000 Cookie: language=zh_CN; ...; token=<JWT_TOKEN>

服务端响应结果如下:

HTTP/1.1 401 Unauthorized Content-Type: application/json; charset=utf-8

响应体中返回错误信息:

{"error":{"message":"No Authorization header was found","name":"UnauthorizedError","code":"credentials_required","status":401,"inner":{"message":"No Authorization header was found"}}}
检查项结果
HTTP 状态码401 Unauthorized
是否返回用户资源否
Cookie 中是否存在 token是
错误信息No Authorization header was found
结论仅 Cookie 中存在token=<JWT>时,服务端仍然拒绝访问,说明该接口没有使用 Cookie token 完成认证。

该组实验比较关键。虽然请求中确实携带了Cookie: token=<JWT>,但是服务端仍然返回401 Unauthorized,并提示No Authorization header was found。这说明在当前接口的认证逻辑中,后端主要检查的是Authorization请求头,而不是 Cookie 中的 token 字段。


4.5 四组结果汇总

测试组Authorization Bearer TokenCookie tokenHTTP 状态码是否返回购物车资源结论
第一组有有200 OK是正常登录态请求成功
第二组无无401 Unauthorized否无认证凭证,请求被拒绝
第三组有无200 OK是Authorization Bearer Token 可以单独完成认证
第四组无有401 Unauthorized否Cookie token 不能单独完成该接口认证

4.6 本节小结

通过四组对照实验可以得出以下结论:

第一,/rest/basket/9是需要认证后才能访问的用户资源接口。不携带有效认证凭证时,服务端会返回401 Unauthorized。

第二,Authorization: Bearer <JWT>可以单独完成该接口的身份认证。当请求头中存在有效 Bearer Token 时,服务端能够识别当前用户身份,并返回对应的购物车资源。

第三,Cookie 中的token=<JWT>不能单独完成该接口认证。第四组实验中,即使 Cookie 中存在 JWT,服务端仍然返回No Authorization header was found,说明当前接口的后端认证逻辑主要依赖Authorization请求头。

第四,第一组同时携带 Authorization 和 Cookie Token 能够请求成功,但结合第三组和第四组结果可以判断,请求成功的关键因素是Authorization: Bearer <JWT>,而不是 Cookie 中的token=<JWT>。

因此,在本实验中,Bearer Token 的作用可以概括为:客户端在登录成功后,将服务端签发的 JWT 放入Authorization请求头中,后端通过该 Token 识别当前登录用户。Cookie 中即使保存了 token,也不代表后端一定会使用它进行接口认证,具体是否生效取决于服务端认证中间件的实现方式。

这里也进一步说明了 Authentication 与 Authorization 的区别:

  • Authorization请求头是 HTTP 中传递认证凭证的位置。
  • Bearer Token 是客户端提交给服务端的身份凭证。
  • Authentication 解决“你是谁”的问题。
  • Authorization 解决“你是否有权限访问该资源”的问题。

在本节实验中,服务端首先通过 Bearer Token 完成 Authentication,识别当前用户为UserId: 24;随后返回该用户对应的Basket ID: 9资源。

五、Authentication 与 Authorization 区分

在分析 JWT 和 Bearer Token 时,需要区分两个概念:Authentication 和 Authorization。

Authentication:身份认证,解决“你是谁”的问题。 Authorization:权限校验,解决“你能访问什么”的问题。

虽然请求头名称是Authorization,但其中携带的Bearer Token首先用于让服务端识别当前用户身份。服务端识别出用户之后,还需要继续判断该用户是否有权限访问具体资源。


5.1 Authentication

Authentication 指身份认证,即服务端确认当前请求来自哪个用户。

在本实验中,身份认证主要体现在两处:

第一,用户通过登录接口提交邮箱和密码,服务端校验成功后返回 JWT:

{"authentication":{"token":"<JWT_TOKEN>","bid":9,"umail":"test1@test.com"}}

第二,客户端在访问购物车接口时携带:

Authorization: Bearer <JWT_TOKEN>

第四章实验中,携带有效 Bearer Token 时,请求/rest/basket/9返回200 OK,并返回UserId: 24、Basket ID: 9等用户相关资源;不携带Authorization请求头时,服务端返回401 Unauthorized,错误信息为:

{"message":"No Authorization header was found","code":"credentials_required"}

因此,本实验中可以判断:服务端通过Authorization: Bearer <JWT_TOKEN>识别当前登录用户。这个过程属于 Authentication。


5.2 Authorization

Authorization 指权限校验,即服务端判断当前用户是否有权访问某个具体资源。

认证成功只说明“当前请求来自哪个用户”,并不代表该用户可以访问所有资源。

例如,当前 JWT Payload 中可以观察到:

{"data":{"id":24,"email":"test1@test.com","role":"customer"},"bid":9}

这说明当前登录用户是UserId: 24,角色为普通用户,对应购物车为Basket ID: 9。

当用户访问自己的购物车时:

GET /rest/basket/9 HTTP/1.1 Authorization: Bearer <JWT_TOKEN>

服务端返回对应资源:

{"status":"success","data":{"id":9,"UserId":24}}

这说明当前用户不仅完成了身份认证,而且访问的是与自己身份匹配的资源。

但是,如果将请求中的资源 ID 修改为其他用户的 Basket ID,例如:

GET /rest/basket/<OTHER_BASKET_ID> HTTP/1.1 Authorization: Bearer <JWT_TOKEN>

此时服务端不能只检查 Token 是否有效,还必须继续判断:

当前 Token 对应的 UserId,是否有权访问这个 Basket ID?

如果服务端只验证“用户已登录”,却没有校验“资源是否属于该用户”,就可能产生越权访问问题。

因此,Authorization 的核心不是有没有登录,而是:

登录用户是否有权限访问当前请求的具体资源。

5.3 二者区别总结

对比项AuthenticationAuthorization
中文含义身份认证权限校验
解决的问题你是谁你能访问什么
本实验中的体现Bearer Token 让服务端识别当前用户为UserId: 24服务端应判断UserId: 24是否有权访问Basket ID: 9
失败时常见状态码401 Unauthorized403 Forbidden或业务层权限拒绝
典型风险Token 泄露、JWT 敏感字段暴露、签名校验错误水平越权、垂直越权、IDOR、角色权限绕过

5.4 本节小结

本实验中,Bearer Token 主要用于身份认证。服务端通过Authorization: Bearer <JWT_TOKEN>识别当前用户身份。

但身份认证成功并不等于拥有所有资源的访问权限。对于购物车、订单、用户信息、后台管理等接口,服务端还必须继续进行权限校验,确认当前用户是否有权访问目标资源。

可以简单概括为:

Authentication:证明“我是 UserId 24”。 Authorization:证明“UserId 24 可以访问 Basket ID 9”。

如果系统只做 Authentication,而忽略 Authorization,就可能导致越权访问漏洞。

六、实验总结

本次实验围绕 OWASP Juice Shop 的登录认证流程和 JWT 使用方式展开,主要分析了登录成功后服务端如何返回 Token、客户端如何通过 Bearer Token 表示登录身份,以及 JWT Payload 中是否存在敏感字段。

通过实验可以确认,用户登录成功后,服务端会返回 JWT。客户端后续访问需要登录身份的接口时,需要在请求头中携带:

Authorization: Bearer <JWT_TOKEN>

在/rest/basket/9接口的四组对照实验中,只有携带Authorization: Bearer <JWT_TOKEN>的请求可以正常返回购物车资源;不携带 Authorization 请求头时,即使 Cookie 中存在token=<JWT>,服务端仍然返回401 Unauthorized,并提示:

{"message":"No Authorization header was found","code":"credentials_required"}

因此可以判断,在该接口中,请求成功的关键因素是Authorization请求头中的 Bearer Token,而不是 Cookie 中的 token 字段。

同时,通过 JWT 解码可以发现,JWT Payload 中包含了用户 ID、邮箱、角色、Basket ID、账户状态字段以及密码哈希字段。由于 JWT Payload 只是 Base64URL 编码,并不是加密,任何获得 Token 的人都可以解码查看其中内容。因此,JWT 中不应存放密码哈希、TOTP Secret、完整用户对象等敏感信息。

本实验还进一步说明了 Authentication 和 Authorization 的区别。Bearer Token 主要用于身份认证,即让服务端识别“当前请求来自哪个用户”;但用户完成认证并不代表可以访问所有资源。对于购物车、订单、用户信息、后台管理等接口,服务端仍然需要继续进行权限校验,判断当前用户是否有权访问目标资源。

综上,本次实验可以得出以下结论:

1. JWT 可以作为登录后的身份凭证。 2. Bearer Token 通过 Authorization 请求头传递。 3. JWT Payload 可以被解码查看,不应存放敏感信息。 4. Cookie 中存在 token 不代表接口一定会使用它完成认证。 5. Authentication 只解决“你是谁”的问题。 6. Authorization 还需要判断“你能访问什么”。 7. 只做身份认证、不做资源级权限校验,可能导致越权访问漏洞。

针对上述问题,实际开发中应遵循以下安全原则:

1. JWT Payload 只保留必要字段,例如用户 ID、角色、签发时间和过期时间。 2. 不在 JWT 中存放密码哈希、二次验证密钥、完整用户对象等敏感信息。 3. 服务端必须校验 JWT 签名,不能只解码 Payload 后直接信任其中内容。 4. Token 应设置合理过期时间,降低泄露后的风险。 5. 每个敏感业务接口都应进行资源归属校验和权限校验。

本次实验的核心收获是:JWT 和 Bearer Token 解决的是登录后的身份识别问题,但接口安全不能只依赖“用户已登录”。真正安全的后端接口还需要在认证之后继续进行严格的权限校验。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 7:29:50

Kinect骨骼估计精度提升:从误差分析到后处理算法实践

简介&#xff1a;这是一篇源自捷克马萨里克大学、发表于ACIVS 2015的学术论文PDF&#xff0c;面向从事Kinect动作捕捉、骨骼追踪与姿态估计研究的开发者、算法工程师&#xff0c;以及康复医疗、步态识别和人机交互等领域的应用人员。论文针对微软Kinect v2真实场景下骨骼比例估…

作者头像 李华
网站建设 2026/9/30 7:29:47

MongoDB+Spark Streaming实时交通预测课程设计实战

简介&#xff1a;本资源是一份面向大数据初学者与课程设计实践者的非关系型数据库综合实训项目&#xff0c;聚焦交通拥堵预测场景&#xff0c;适用于本科课程设计、工程实训或毕业设计选题。项目采用Kafka模拟实时交通数据流&#xff0c;经预处理后存入Redis等NoSQL存储&#x…

作者头像 李华
网站建设 2026/9/30 7:29:47

用扣子COZE搭建企业官网智能客服:知识库、多轮对话与工作流实践指南

简介&#xff1a;面向企业官网需要自动应答客户咨询的落地需求&#xff0c;这份基于扣子COZE平台的智能客服开发资料&#xff0c;完整呈现了多轮对话助手的设计思路与应用配置方式&#xff0c;适合有一定编程基础、希望低成本构建客服系统的开发者或企业技术人员参考。资源共1个…

作者头像 李华
网站建设 2026/9/30 7:28:50

基于JSP的服装商城交易管理系统设计与实现

简介&#xff1a;一份围绕基于JSP的服装商城交易管理系统设计与实现的答辩演示文稿&#xff0c;面向计算机相关专业毕业生及需要进行系统类课程设计或毕业答辩的学生。资源从选题意义、课题背景、系统功能目标到技术方案逐步展开&#xff0c;重点覆盖JSP与Servlet在业务逻辑处理…

作者头像 李华
网站建设 2026/9/30 7:27:48

KonopkaControls WinForm 高 DPI 圆角与布局优化方案

简介&#xff1a;本资源是面向Delphi中高级开发者的一套完整可视化控件源码库&#xff0c;专为适配Delphi 12.3环境优化设计&#xff0c;继承自经典Raize Components体系&#xff0c;由Konopka公司持续维护升级。它提供高度可定制的VCL界面组件&#xff08;如增强型按钮、网格、…

作者头像 李华
网站建设 2026/9/30 7:27:14

四平信誉好的考研寒假特训营机构用户力荐

2026四平信誉好的考研寒假特训营机构用户力荐考研寒假集训是基础夯实的关键窗口&#xff0c;但不少考生会陷入自学效率低、择校无方向、缺乏系统规划的困境。所谓考研寒假特训营&#xff0c;是指利用寒假7-10天的连续假期&#xff0c;通过封闭式面授、闭环督学、针对性基础训练…

作者头像 李华