记录--P0事故预警
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
背景
某一天,前端小余同学和后端别问我小哥在做登录业务接口对接,出于业务的特殊性和安全性的考虑,她和后端小哥约定“user”相关信息参数需要通过HTTP协议的header传递过来,利用HTTPS协议的头部中的参数可以通过加密传输,从而保证数据的安全性。
开发阶段
确定技术方案之后,小余同学在注册发起请求函数的headers中新增user属性:
export type User = { username: string; password: string; }; const handleRequest = async (userInfo: User, params: Object) => { try { await axios.post('/register-login-secure', params, { headers: { ...userInfo } }); } catch (e) { console.error(e); } };
这段代码看起来是没有任何问题,对吗?
再看一下前端代码的逻辑:
const Register = () => { const handleRequest = () => { // ... }; return ( <Form> <Form.Item field="username" label="用户名"> <Input placeholder="请输入用户名" /> </Form.Item> <Form.Item field="password" label="密码"> <Input.Password placeholder="请输入密码" /> </Form.Item> <Form.Item noStyle> <Button onClick={handleRequest} /> </Form.Item> </Form> ); };
整体看下来没什么问题,但是可以发现username是对用户输入没有做任何校验的,也就是说:无论用户输入什么都可以存在数据库的,这里我们忽略xss攻击。
由于这次的技术方案user信息是通过headers传递的,跟之前的传参有一些出入以及在本地测试的时候,前端和后端在用户名部分随便输入了一串英文字符串作为用户名用于测试,发现没问题于是就提测了。
测试阶段
进入提测阶段之后,测试同学把测试用例甩了过来:
场景一:注册用户名ashui,是否注册成功
场景二:重复注册用户名ashui,是否注册成功
...
测试同学也顺利的通过了所有测试用例,所以就上线了,线上验收也没什么问题,所以大家都早早下班,各回各家,各找各妈。看到这里,大家有发现什么问题?如果有的话,请继续往下看,看看猜想和后续遇到的问题是不是一直的。
事故阶段
距离这次上线已经过去三天了,忽然小余晚上三点半被P0加急电话吵醒,看到群里反馈有用户无法注册,小余瞬间清醒打开电脑复现了一下,发现没问题,群里大家复现都说没问题,但运营同学跟客户反复沟通后,发现客户确实无法注册,于是小余就去sentry监控查看了一下,忽然发现了之前从来没有遇到的报错:
Failed to read the 'headers' property from 'RequestInit': String contains non ISO-8859-1 code point.
小余从这个报错中窥探到一点信息是headers,程序员天生的直觉告诉她可能跟这次上线的技术方案有关,所以她去看了一下HTTP
协议的文档.
解决阶段
文档里面有这样一段话:
By default, message header parameters in HTTP ([RFC2616]) messages can not carry characters outside the ISO-8859-1 character set ([ISO-8859-1]). RFC 2231 ([RFC2231]) defines an escaping mechanism for use in MIME headers. This document specifies a profile of that encoding for use in HTTP.
翻译过来就是HTTP headers
中不能包含ISO-8859-1以外的字符集。小余恍然大悟,用户输入的是中文的名字,所以赶紧试了一下,发现果然是这个问题,于是跟产品确定用户名的用户输入的规范,以及跟后端小哥修改技术方案。
什么是ISO-8859-1字符集
用于表示文本字符的编码方案。它是国际标准化组织(ISO)制定的字符集之一,于1987年发布。
ISO-8859-1 字符集包含了来自拉丁字母表的字符,主要用于表示西欧语言,如英语、法语、德语、西班牙语等。它是一个单字节字符集(Single-Byte Character Set,SBCS),其中的每个字符都可以用一个字节(8位)进行表示。ISO-8859-1 字符集共定义了256个字符,编号从0到255。
ISO-8859-1 字符集的编码方案被广泛应用于计算机系统和互联网中的文本传输和存储。在该字符集中,ASCII 字符(0-127)与 ASCII 字符集相同,因此 ISO-8859-1 是 ASCII 的一个超集。此外,ISO-8859-1 还包括了其他特定于欧洲语言的字符,如重音符号、希腊字母、货币符号等。
例如,ISO-8859-1 中的一些常见字符包括:
- 字母:A-Z、a-z
- 数字:0-9
- 标点符号:. , ; : ! ? ' " ( ) [ ] { } < > | / \ - + * = # @ $ % & _
- 特殊字符:© ® ° µ Æ æ Ø ø Å å
ISO-8859-1 字符集的编码方案被广泛支持,包括在操作系统、编程语言、文本编辑器、浏览器等软件和工具中。然而,它仅适用于西欧语言,对于其他非西欧语言的字符,如中文、日文、韩文等,ISO-8859-1 并不适用。对于这些语言,通常使用其他字符集和编码方案,如 UTF-8、UTF-16 等。
需要注意的是,ISO-8859-1 字符集与 Unicode 字符集是不同的概念。Unicode 是一种字符编码标准,旨在为世界上所有的字符提供唯一的标识符,而 ISO-8859-1 是其中的一种字符集,只覆盖了一部分字符。
后续
经过这次事故之后,小余也加强了对HTTP新的理解,在HTTP协议中headers是需要遵循ISO-8859-1字符集规范,也为后续小余成长做了一个警示。