生产事故-走近科学之消失的JWT

news2025/2/28 5:46:27

0x01 事故背景

2021年11月26日01时10分,P公司正在进行某业务系统的生产环境部署操作,但其实早在00时30分的时候,他们已经完成过一次部署了,但是奇怪的是无论如何都通不过验证,无奈只好推倒重来,如此反复了有若干次。为何反复尝试,却不尝试去寻找问题呢?问题就在于该系统同一份代码在开发环境和 UAT 环境均一切正常,唯独部署到生产环境上面就不行。这是一个前后端分离的业务系统,前端与后端接口基于 JWT 而不是传统 Session 进行鉴权认证。故障的现象也很简单,就是无法登录——准确的说,是登录后不能维持登录状态,一访问其他需要鉴权的资源立马又被重定向到登录页面。2020年10月25日02时30分,在运维人员多次尝试无果,开发人员排查代码也未发现问题后,P公司不得不直呼见鬼。那么真相究竟是什么呢?

0x02 事故分析

在 RFC 7519 规范中对于 JWT 是这样描述的:

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code(MAC) and/or encrypted.

JWT (JSON Web Token) 是一种紧凑、URL 安全的表示方式,用于表达要在两个参与方之间传输的安全声明。JWT 中的声明被编码为 JSON 对象,作为 JSON Web Signature (JWS) 结构的有效载荷或 JSON Web Encryption (JWE) 结构的明文,使得声明可以使用消息认证码 (MAC) 进行数字签名或完整性保护和/或加密。

说人话呢意思就是 JWT 是一种安全令牌的标准化实现,用于参与双方之间的可信交互认证。既然不好定位是环境还是代码的问题,不妨先捋一捋 JWT 鉴权认证的过程,看看问题可能发生在哪一步:

JWT鉴权认证流程

  1. 从故障现象来看,步骤①出问题的可能性基本被排除,从前端请求和后端日志来看账号和密码的验证过程已经正确完成;
  2. 那么步骤②有没有可能出问题呢?当时也是怀疑过的,但是使用浏览器的 F12 开发者工具,看到 login 的网络请求响应中已经将后端生成的 JWT 返回来了;
  3. 莫非是步骤③没有将 JWT 正确携带,导致后续验证不通过?但是查看登陆后,对其他接口的请求,里面确实已经携带了步骤②中提供的 JWT,而且数值也一致;
  4. 验证JWT的代码逻辑会不会有问题呢?可能性不大,因为在测试环境和 UAT 环境已经反复验证过。

那么问题还是出在步骤③携带 JWT 这一步。前面分析过前端发起请求时,已经携带了 JWT,那么有没有可能是后端没收到或者收到的值不正确呢?很可惜,后端收到 JWT 后没有打印相关的日志……只有简单的提示验证失败的信息。但其实到这里,已经可以怀疑是环境的问题了,因为同样的代码只在生产环境出错。

随机抽取一个运维小伙子,让他说说生产的系统结构,从他口中得知,生产上除了为了部署多个节点,使用了 Nginx 作为负载均衡和反向代理外,其他地方没有区别。凭借往常的经验呢,P公司的员工们首先呢就没有怀疑过反代和负载会影响这个业务功能,但是我们的理性分析又提示我们问题很有可能出在这里。

不妨找个机器验证一下,安装和生产环境相同版本的 Nginx,然后配置一下反代和负载。对了,这回啊,在后端把打印 JWT 的Debug日志加上。然后果不出所料,前端虽然在请求头中携带了 JWT,但是到了后端,却显示没有这个信息,这个头,它丢到哪里去了呢?

0x03 事故原因

前端在步骤③请求头中携带的 JWT 如下,HTTP_HEADER_NAME 为 “JWT_TOKEN”,HTTP_HEADER_VALUE 为 JWT 的值:

JWT_TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjpbb2x0...

在后端日志中,除了 JWT_TOKEN 以外,其他的头部信息都正常传递,我们注意到,它的 HTTP_HEADER_NAME 包含了下划线,这是它与众不同的地方。难道是被 Nginx 过滤了?

在 Nginx 的官方文档里,有这么一段话:

Missing (disappearing) HTTP Headers

If you do not explicitly set underscores_in_headers on;, NGINX will silently drop HTTP headers with underscores (which are perfectly valid according to the HTTP standard). This is done in order to prevent ambiguities when mapping headers to CGI variables as both dashes and underscores are mapped to underscores during that process.

消失的 HTTP Headers

如果你没有显式设置 underscores_in_headers on;,NGINX 会静悄悄地干掉带有下划线的 HTTP 请求头(虽然它们符合 HTTP 规范,毁灭你与你何干……)。这样做是为了防止在将请求头映射到 CGI 变量时出现歧义,因为在此过程中,短划线和下划线都映射到下划线。

在 ngx_http_parse.c 中,这个开关是这样处理的:

/* header name */
case sw_name:
    c = lowcase[ch];

    if (c) {
        hash = ngx_hash(hash, c);
        r->lowcase_header[i++] = c;
        i &= (NGX_HTTP_LC_HEADER_LEN - 1);
        break;
    }

    if (ch == '_') {
        if (allow_underscores) {
            hash = ngx_hash(hash, ch);
            r->lowcase_header[i++] = ch;
            i &= (NGX_HTTP_LC_HEADER_LEN - 1);

        } else {
            r->invalid_header = 1;
        }

        break;
    }
    // ……(太长只截取关键部分)
    break;

如果没有开启underscores_in_headers开关,对应变量allow_underscores,则默认情况下,带有下划线的 HTTP_HEADER 会被标记为 INVALID_HEADER.而标记为 INVALID_HEADER 的信息默认情况下,会被忽略掉,为什么说默认呢?因为这个行为同时还受到另一个开关ignore_invalid_headers控制,如果它被开启,那么带有下划线的 HTTP_HEADER 就真的神秘消失了。

关于 underscores_in_headers 选项:

Syntax: underscores_in_headers on | off;

Default: underscores_in_headers off;

Context: http, server

Enables or disables the use of underscores in client request header fields. When the use of underscores is disabled, request header fields whose names contain underscores are marked as invalid and become subject to the ignore_invalid_headers directive.

关于 ignore_invalid_headers 选项:

Syntax: ignore_invalid_headers on | off;

Default: ignore_invalid_headers on;

Context: http, server

Controls whether header fields with invalid names should be ignored. Valid names are composed of English letters, digits, hyphens, and possibly underscores (as controlled by the underscores_in_headers directive).

可以看到underscores_in_headers选项默认情况下是关闭的,而ignore_invalid_headers选项默认情况下是开启的,这也就导致了我们 JWT_TOKEN 的神秘失踪,至此问题已经定位完毕。

0x04 事故复盘

这次可以说是纯纯的意外,但是这个意外本可以发现的更早:

  • 再穷也好,至少也要申请一个与生产环境相同/相仿的复刻环境。
  • 统一且规范的命名,或许可以避免很多不必要的麻烦。
  • 所谓Debug日志就是,没事的时候,你看到它嫌它烦;出事的时候,你烦看不到它……
  • 排查问题时,还是大意了,没有去看 Nginx 的日志,因为通过源码可以发现 INVALID_HEADER 默认情况下是会触发 ERROR 日志的:
    if (rc == NGX_OK) {
    
        r->request_length += r->header_in->pos - r->header_name_start;
    
        if (r->invalid_header && cscf->ignore_invalid_headers) {
    
            /* there was error while a header line parsing */
    
            ngx_log_error(NGX_LOG_INFO, c->log, 0,
                          "client sent invalid header line: \"%*s\"",
                          r->header_end - r->header_name_start,
                          r->header_name_start);
            continue;
        }
        // ……(太长只截取关键部分)
    }
    

0x05 事故影响

使P公司新业务系统上线时间延长了3小时,相关人员连夜跟老板申请服务器经费。(知道了,下次还是不批)。

  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/862331.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

opencv实战项目 实现手势跟踪并返回位置信息(封装调用)

OpenCV 是一个基于 Apache2.0 许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上。 需要提前准备opencv 和 mediapipe库 pip --default-timeout5000 install -i https://pypi.tuna.tsi…

腾讯云服务器使用教程_手把手图文详细介绍

腾讯云服务器使用教程包括注册账号实名认证、选择云服务器CVM或轻量应用服务器CPU内存带宽和系统盘配置、安全设置和云服务器远程连接、安全组端口开通教程、云服务器环境部署以搭建网站为例手把手网站上线,云服务器文件传输和数据备份以及技术支持等详细说明&#…

【Linux】用户和权限

文章目录 前言什么是 root 用户su 命令和 exit 命令sudo 命令为普通用户配置 sudo 认证 用户、用户组管理什么是Linux 用户和用户组用户组管理用户管理创建用户删除用户查看用户所属组将指定用户添加到指定用户组中 查看当前系统的用户和用户组 权限控制权限信息 修改权限控制修…

MyBatisX自动和数据库的字段关联

先下个插件 右键数据库,点MybatisX-Generator 在根据自己需求勾选 actual column:保证数据库的驼峰命名生效

第10集丨Vue 江湖 —— 表单输入绑定

目录 一、v-model1.1 基本用法1.2 值绑定1.3 修饰符1.3.1 .lazy1.3.2 .number1.3.3 .trim 二、总结2.1 案例2.2 效果 一、v-model 1.1 基本用法 功能&#xff1a; v-model指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件…

【人工智能前沿弄潮】——生成式AI系列:扩散模型及稳定扩散模型

VAE、GAN的出现&#xff0c;使得生成式AI越发火热&#xff0c;如今扩散模型的出现与兴起&#xff0c;更是将AIGC推到了人工智能风口&#xff0c;被视作如今人工智能生成艺术领域取得突破的主要因素。相较于VAE和GAN,扩散模型生成的图片质量更好。随着transformer架构的出现和pr…

Uniapp当中使用腾讯位置路线规划插件保姆教学

首先我们在使用腾讯地图插件之前我们需要先做几点准备 1&#xff1a;我们需要在腾讯地图位置服务当中注册账号以及在控制台当中创建应用和创建key 这里在创建应用当中应用类型一定要选出行类型&#xff0c;否则后期可能会出现问题。 我们创建完应用之后&#xff0c;点击创建…

elementUi表单恢复至初始状态并不触发表单验证

elementUi表单恢复至初始状态并不触发表单验证 1.场景再现2.解决方法 1.场景再现 左侧是树形列表&#xff0c;右侧是显示节点的详情&#xff0c;点击按钮应该就是新增一个规则的意思&#xff0c;表单内容是没有改变的&#xff0c;所以就把需要把表单恢复至初始状态并不触发表单…

线性代数(三) 线性方程组向量空间

前言 如何利用行列式&#xff0c;矩阵求解线性方程组。 线性方程组的相关概念 用矩阵方程表示 齐次线性方程组&#xff1a;Ax0&#xff1b;非齐次线性方程组&#xff1a;Axb. 可以理解 齐次线性方程组 是特殊的 非齐次线性方程组 如何判断线性方程组的解 其中R(A)表示矩阵A的…

Hugging News #0414: Attention 在多模态情景中的应用、Unity API 以及 Gradio 主题构建器

社区动向 Attention 在视觉领域的应用 注意力机制改变了许多学科的深度学习研究&#xff0c;从 NLP 开始扩展到视觉、语音等。注意力机制的使用在深度学习研究中变得越来越流行&#xff0c;理解和解释注意力机制的内部工作是至关重要的。 我们发布了一个教程&#xff0c;介绍…

面试官:前面我们聊了主从和哨兵,那今天来聊一聊集群吧

目录 秃顶面试官&#xff1a;简单介绍下什么是Redis Cluster呢? 秃顶面试官&#xff1a;那集群的缺点有哪些呢&#xff1f; 秃顶面试官&#xff1a;说说如何搭建集群呢&#xff1f; 秃顶面试官&#xff1a;集群内部是如何通信的呢&#xff1f; 秃顶面试官&#xff1a;线上…

three.js上传模型文件并加载显示

效果大概这样&#xff0c;这个宝箱模型是直接初始化就显示的&#xff0c;人物模型是自己本地添加上去的&#xff0c;代码如下。 <template><div class"container" ref"container"><el-row><el-col :span"24"><div c…

固态硬盘恢复数据,5步搞定!

“不知咋回事&#xff0c;我的固态硬盘突然就有问题了&#xff0c;很多重要的文件也一起丢失了。我正在很努力的解决这个问题&#xff0c;但可惜我对电脑的使用了解比较少&#xff0c;有没有电脑高手可以帮帮我呀&#xff1f; 固态硬盘&#xff0c;通常被称为SSD&#xff0c;它…

stable-diffusion 模型效果+prompt

摘自个人印象笔记&#xff0c;图不完整可查看原笔记&#xff1a;https://app.yinxiang.com/fx/55cda0c6-2af5-4d66-bd86-85da79c5574ePrompt运用规则及技巧 &#xff1a; 1. https://publicprompts.art/&#xff08;最适用于OpenArt 线上模型 https://openart.ai/&#xff09;…

近地面无人机植被定量遥感与生理参数反演技术

遥感&#xff08;RS-Remote Sensing&#xff09;——不接触物体本身&#xff0c;用传感器收集目标物的电磁波信息&#xff0c;经处理、分析后&#xff0c;识别目标物&#xff0c;揭示其几何、物理性质和相互关系及其变化规律的现代科学技术。 换言之&#xff0c;即是“遥远的感…

领克08,开创「芯」时代

中国汽车产业&#xff08;自主品牌&#xff09;的持续向上&#xff0c;正带动本土智能化核心供应链&#xff0c;尤其是关键算力芯片&#xff08;SoC&#xff09;的本土创新。 高工智能汽车研究院监测数据显示&#xff0c;今年1-6月中国市场&#xff08;不含进出口&#xff09;自…

Unity游戏源码分享-精品即时战略游戏_官网60美刀素材

Unity游戏源码分享-精品即时战略游戏_官网60美刀素材 下载地址&#xff1a;https://download.csdn.net/download/Highning0007/88204017

visual studio 2022安装本地的nuget包

工具->选项->Nuget包管理器->程序包源 然后右击解决方案->管理解决方案的Nuget包

探秘Java的Map集合:键值映射的奇妙世界

文章目录 1. 单列集合 vs. 双列集合2. Map接口&#xff1a;键与值的契约3. 深入探索HashMap3.1 特性与构造方法3.2 常用方法3.3 遍历HashMap 4. 美妙的LinkedHashMap 在Java编程中&#xff0c;集合是不可或缺的重要部分&#xff0c;它为我们提供了各种数据结构和算法的实现。其…

(一)创建型设计模式:3、建造者模式(Builder Pattern)

目录 1、建造者模式含义 2、建造者模式的讲解 3、使用C实现建造者模式的实例 4、建造者模式的优缺点 5、建造者模式VS工厂模式 1、建造者模式含义 The intent of the Builder design pattern is to separate the construction of a complex object from its representatio…