2025-08-08

Javascript 使用 atob() 解密 base64 字串遇到的問題

這裡記錄我在使用 js 的 base64 解密功能時,因為 UTF-8 編碼與 base64 格式,會遇到的問題

這是我要進行 base64 加密的字串

{"id":"e0405f3f-e0b3-4eb8-a1ed-b9cc63dfe6de","userName":"司馬曉明","account": "sma","email": "light.sma@example.foo.org","iat": 1754621860,"exp": 1754622760}

這是該字串用 Go 各種 base64 加密方式加密後的結果

base64.RawStdEncoding
eyJpZCI6ImUwNDA1ZjNmLWUwYjMtNGViOC1hMWVkLWI5Y2M2M2RmZTZkZSIsInVzZXJOYW1lIjoi5Y+46aas5puJ5piOIiwiYWNjb3VudCI6ICJzbWEiLCJlbWFpbCI6ICJsaWdodC5zbWFAZXhhbXBsZS5mb28ub3JnIiwiaWF0IjogMTc1NDYyMTg2MCwiZXhwIjogMTc1NDYyMjc2MH0
base64.RawURLEncoding
eyJpZCI6ImUwNDA1ZjNmLWUwYjMtNGViOC1hMWVkLWI5Y2M2M2RmZTZkZSIsInVzZXJOYW1lIjoi5Y-46aas5puJ5piOIiwiYWNjb3VudCI6ICJzbWEiLCJlbWFpbCI6ICJsaWdodC5zbWFAZXhhbXBsZS5mb28ub3JnIiwiaWF0IjogMTc1NDYyMTg2MCwiZXhwIjogMTc1NDYyMjc2MH0
base64.StdEncoding
eyJpZCI6ImUwNDA1ZjNmLWUwYjMtNGViOC1hMWVkLWI5Y2M2M2RmZTZkZSIsInVzZXJOYW1lIjoi5Y+46aas5puJ5piOIiwiYWNjb3VudCI6ICJzbWEiLCJlbWFpbCI6ICJsaWdodC5zbWFAZXhhbXBsZS5mb28ub3JnIiwiaWF0IjogMTc1NDYyMTg2MCwiZXhwIjogMTc1NDYyMjc2MH0=
base64.URLEncoding
eyJpZCI6ImUwNDA1ZjNmLWUwYjMtNGViOC1hMWVkLWI5Y2M2M2RmZTZkZSIsInVzZXJOYW1lIjoi5Y-46aas5puJ5piOIiwiYWNjb3VudCI6ICJzbWEiLCJlbWFpbCI6ICJsaWdodC5zbWFAZXhhbXBsZS5mb28ub3JnIiwiaWF0IjogMTc1NDYyMTg2MCwiZXhwIjogMTc1NDYyMjc2MH0=

而這幾個方式得到的 base64 加密字串,base64.RawStdEncoding和base64.StdEncoding是可以用 javascript 的 atob() function 解密的

只是解密出來的字串,由於編碼的關係,非 ASCII 字元都會出錯

以上述例子來說,userName 會變成 "å\u008f¸é¦¬æ\u009b\u0089æ\u0098\u008e"

解決

要使這四種都能正常解密

首先,先將 URL safe 的Base64 字串改成一般的

function(base64Str: string): string{
	let result = base64Str.replace(/-/g, '+').replace(/_/g, '/')

	while (result.length % 4 !== 0) {
		result += '='
	}
	return result
}

然後處理解密後的文字,改成 UTF-8 編碼

function(base64Str: string): string{
	const decodedData: string = atob(base64Str)
	// 轉成 byte array
	const bytes = new Uint8Array(
		decodedData.split("").map(function(ch){ // 如果是 ES2015 以上的版本,也可以寫成 [...decodedData].map(...)
			return ch.charCodeAt(0)
		})
	)
	return new TextDecoder('utf-8').decode(bytes)
}

這樣四種字串都能正常運作了

參考資料

Josefsson, S. (2006). The Base16, Base32, and Base64 Data Encodings. RFC Editor. https://doi.org/10.17487/RFC4648
Window: atob() method - Web APIs. (2025, June 24). MDN Web Docs. https://developer.mozilla.org/en-US/docs/Web/API/Window/atob
JavaScript 中的 Base64 編碼字串細微差異. (2023, October 17). web.dev. https://web.dev/articles/base64-encoding?hl=zh-tw

沒有留言:

張貼留言