超碰人人人人人,亚洲AV午夜福利精品一区二区,亚洲欧美综合区丁香五月1区,日韩欧美亚洲系列

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

深入剖析Base64加解密中遇到的坑點(diǎn)

freeflydom
2025年2月11日 9:29 本文熱度 912

前言

最近開(kāi)發(fā)過(guò)程中遇到了關(guān)于使用base64加密傳輸遇到的神奇問(wèn)題。需求就是用戶(hù)的id在鏈接上露出時(shí)需要加密處理,于是后端把下發(fā)的用戶(hù)id改成了base64加密處理后下發(fā)了,前端只需要把加密后的用戶(hù)id原樣傳給后端就行。就是這個(gè)看似簡(jiǎn)單的流程,前端啥也沒(méi)干只是原樣透?jìng)鳎蠖擞懈怕誓玫降挠脩?hù)id不對(duì)。

問(wèn)題描述

本地寫(xiě)個(gè)后端服務(wù)模擬當(dāng)時(shí)的情景:

后端框架:nest

@Get('getUserInfo') 
getUserInfo(@Req() req) {
  const query = req.query
  const cookie = req.cookies
  console.log('cookie', cookie)
  // 優(yōu)先取參數(shù)中的userId,沒(méi)有則取cookie中的uid
  const userId = query.userId || cookie.uid
  // base64加密
  const token = Buffer.from(userId).toString('base64')
  console.log('加密后的token', token)
  // 返回base64加密后的token
  return {
    code: 0,
    data: {
      userId,
      // base64加密
      token
    }
  }
}

前端請(qǐng)求后:

服務(wù)這邊能夠正常拿到cookie并使用base64加密,然后把加密后的token返回給前端

前端也正常拿到了后端返回的加密后的token

最后前端只需要在用戶(hù)分享時(shí)把加密的token帶在鏈接上,從這個(gè)鏈接進(jìn)入時(shí)再把鏈接上加密的token帶給后端即可,中間不需要做任何處理。

就是這個(gè)過(guò)程,出現(xiàn)了奇怪的現(xiàn)象,絕大多數(shù)用戶(hù)都是OK,但是會(huì)有一些用戶(hù)的token帶給后端時(shí),后端解不出來(lái)了。

心想這跟前端好像沒(méi)啥關(guān)系,因?yàn)榍岸藟焊鶝](méi)處理后端返回的token,后端給我啥,我只是原樣給他傳了啥。

經(jīng)排查發(fā)現(xiàn),所有有問(wèn)題的用戶(hù)id都是加密后的token中包含了+符號(hào)

比如這樣的:zm+3DQ/gYeMzQ/HM2L76+CA==傳到后端時(shí),所有的+都變成了空格,導(dǎo)致后端解出來(lái)是錯(cuò)的

URL是如何進(jìn)行編碼的

這個(gè)問(wèn)題的主要原因還是因?yàn)閁RL被編碼造成的,由于請(qǐng)求是get請(qǐng)求,所以最終所有的參數(shù)都是拼接在鏈接上的,最開(kāi)始前端傳給后端的token是沒(méi)有經(jīng)過(guò)編碼的,那它為什么自己編碼了?并且編碼后與預(yù)期的還不一致?

由于種種歷史原因,RFC與W3C都定義過(guò)URL的編碼標(biāo)準(zhǔn)

RFC規(guī)范

在RFC3986中提到:除了 數(shù)字 、 字母 、-_.~ 不會(huì)被轉(zhuǎn)義,其他字符都會(huì)被以百分號(hào)(%)后跟兩位十六進(jìn)制數(shù) %{hex} 的方式進(jìn)行轉(zhuǎn)義。在這個(gè)規(guī)則中空格會(huì)被轉(zhuǎn)為%20,而+會(huì)被轉(zhuǎn)為%2B

W3C規(guī)范

在W3C規(guī)范中卻又說(shuō)空格可以被編碼為+%20

為什么會(huì)同時(shí)存在兩種規(guī)范,這不是在挖坑嗎?

因?yàn)閁RL中不能存在空格,所以在URL中的空格會(huì)自動(dòng)替換成+%20

這就是上面出現(xiàn)+變空格的原因,在你不確定正在以哪一個(gè)規(guī)范進(jìn)行編解碼時(shí),就很容易出現(xiàn)這個(gè)問(wèn)題。它可能是瀏覽器造成的,也可能是開(kāi)發(fā)語(yǔ)言的規(guī)范不同造成的。

比如Google搜索:

當(dāng)我們搜索s+2時(shí),地址欄出現(xiàn)的是s%2B2

當(dāng)我們搜索s 2時(shí),地址欄出現(xiàn)的卻是s+2

這里就是空格被編碼為+了,你要是不了解W3C這條規(guī)范,是不是覺(jué)得匪夷所思了??

前端編碼規(guī)范

在JS中對(duì)字符串進(jìn)行編碼的方法有三個(gè):escape、encodeURI、encodeURIComponent

escape已經(jīng)被廢棄了,不再推薦使用,所以我們這里只需要關(guān)注后面兩個(gè)的區(qū)別

encodeURI

該函數(shù)只會(huì)編碼URI中完全禁止的字符。該函數(shù)的目的是對(duì)URI進(jìn)行完整的編碼,因此對(duì)以下在URI中具有特殊含義的 ASCII 標(biāo)點(diǎn)符號(hào),encodeURI是不會(huì)進(jìn)行轉(zhuǎn)義的(;/???&=+$,#)

所以對(duì)于encodeURI來(lái)說(shuō),空格會(huì)被編碼為%20,但是+并不會(huì)編碼。因?yàn)榭崭袷荱RI中禁止的字符,而+不是

總結(jié)來(lái)說(shuō)就是:

encodeURL除了這些A-Z a-z 0-9 ; , / ? : @ & = + $ – _ . ! ~ * ‘ ( ) # 不會(huì)被編碼,其余字符都會(huì)被編碼

encodeURIComponent

功能與encodeURI類(lèi)似,但是encodeURIComponent編碼的范圍更廣,并且該函數(shù)一般用于對(duì)URI的參數(shù)部分進(jìn)行編碼

對(duì)于encodeURIComponent來(lái)說(shuō),空格會(huì)被編碼為%20+會(huì)被編碼為%2B

總結(jié)來(lái)說(shuō)就是:

encodeURLComponent除了這些A-Z a-z 0-9 - _ . ! ~ * ' ( ) 不會(huì)被編碼,其余字符都會(huì)被編碼

兩者使用場(chǎng)景的差異

  • 當(dāng)encode的內(nèi)容不作為URI參數(shù)時(shí),使用encodeURI進(jìn)行編碼
const url = encodeURI('https://www.qidian.com')
// 'https://www.qidian.com'
  • 當(dāng)encode的內(nèi)容作為URI參數(shù)時(shí),使用encodeURIComponent進(jìn)行編碼
const deepLink = `weixin://webview?url=${encodeURIComponent('https://www.baidu.com')}`
//  weixin://webview?url=https%3A%2F%2Fwww.baidu.com

結(jié)論

對(duì)于JS的編碼方法來(lái)說(shuō),只有encodeURIComponent會(huì)對(duì)+進(jìn)行編碼,并且編碼規(guī)范是RFC3986,也就是說(shuō)使用這個(gè)方法空格會(huì)被轉(zhuǎn)為%20,而+會(huì)被轉(zhuǎn)為%2B。從而也就不會(huì)出現(xiàn)+變空格或空格變+的問(wèn)題。

上述問(wèn)題是如何產(chǎn)生的?

上面分別介紹了URL的編碼規(guī)范,以及前端編碼方法應(yīng)用的規(guī)范。總結(jié)下來(lái)就是空格不會(huì)在前端產(chǎn)生,前端應(yīng)用的編碼規(guī)范不會(huì)將空格編碼成+,也不會(huì)把+解碼成空格。

并且特意寫(xiě)了個(gè)node服務(wù)來(lái)模擬當(dāng)時(shí)的場(chǎng)景。

結(jié)論是:只要傳給后端的base64字符串在前端經(jīng)過(guò)了編碼就不會(huì)有問(wèn)題。因?yàn)樯厦嫖覀兘榻B過(guò)瀏覽器的編碼規(guī)范,確實(shí)是會(huì)存在+變空格的問(wèn)題。所以我們需要主動(dòng)編碼,不要把編碼的機(jī)會(huì)留給瀏覽器。

  1. 前端編碼了,后端拿到的也是正常的

  1. 沒(méi)編碼,后端拿到的+變成空格了

所以當(dāng)時(shí)前端未進(jìn)行編碼時(shí),從CURL中就能看到+已經(jīng)變成了空格,但后面前端編碼后,curl看是正常的,后端解碼出來(lái)卻還是有問(wèn)題的。

我這邊怎么都復(fù)現(xiàn)不了當(dāng)時(shí)傳給后端是編碼過(guò)的base64字符串,后端拿到的卻還是+變成了空格

沒(méi)辦法,只好找后端同學(xué)問(wèn)問(wèn)他當(dāng)時(shí)是怎么解碼的...

經(jīng)過(guò)一番驗(yàn)證后,結(jié)論是他那邊多解碼了一次,他們框架層有一次自動(dòng)解碼

'zm%2B3DQ%2FgYeMzQ%2FHM2L76CA%3D%3D'   ---->  'zm+3DQ/gYeMzQ/HM2L76CA=='

實(shí)際上這里就已經(jīng)是正確的了,但后端同學(xué)又自己解碼了一次,按理來(lái)說(shuō)再次解碼應(yīng)該也不會(huì)有問(wèn)題

但是?。?!這是因?yàn)?code style="font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace, sans-serif; padding: 0px 5px; line-height: 1.8; margin: 0px 3px; display: inline-block; overflow-x: auto; vertical-align: middle; border-radius: 3px; background-color: rgb(251, 229, 225); color: rgb(192, 52, 29); border: none !important;">javascript遵循的是RFC3986規(guī)范,但java好像并不是

java自帶的decode方法底層是這樣實(shí)現(xiàn)的

這里是按W3C的規(guī)范,由于URL中不能存在空格,所以URL Encode 會(huì)把空格替換成+,然后解碼也同樣會(huì)將+替換成空格。真相了....

解決方案

  • 按理來(lái)說(shuō)我們只需要保證傳給后端的+字符按RFC3986規(guī)范編碼成了%2B就不會(huì)有問(wèn)題,不要把編碼的機(jī)會(huì)留給瀏覽器,在JS中只需調(diào)用encodeURIComponent即可
  • 后端接收到帶空格的base64字符串時(shí),通過(guò)正則將空格替換為+,因?yàn)?code style="font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace, sans-serif; padding: 0px 5px; line-height: 1.8; margin: 0px 3px; display: inline-block; overflow-x: auto; vertical-align: middle; border-radius: 3px; background-color: rgb(251, 229, 225); color: rgb(192, 52, 29); border: none !important;">base64中不會(huì)出現(xiàn)空格
  • 由于標(biāo)準(zhǔn)Base64編碼包含64個(gè)字符A-Z, a-z,0-9,+,/,=,有一種URL safe的base64格式,把其中的+,/換成-,_,也能夠解決上面的問(wèn)題。

?https://www.cnblogs.com/songyao666/p/18707544


該文章在 2025/2/11 9:29:25 編輯過(guò)
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶(hù)的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved