前陣子在教學一篇 Base64 及 Base64Url 編碼 的方法,有提到可以將網址上傳送的資料採用 Base64 編碼。
但今天遇到一個特別的問題,因為網站上某些網址已經被搜尋引擎收錄,偶爾會有一些爬蟲程式到我的頁面上,而爬蟲程式使用的網址竟然全改為小寫,而我原本使用大小寫有別的 Base64 參數,造成解碼錯誤。
例如我原網址為: /Index/StraInfo/MTk0
參數 MTk0 可被 Base64 解碼
可是爬蟲程式呼叫網址為: /index/straInfo/mtk0
程式收到的參數為 mtk0 經過 Base64 解碼就無法正確還原了。
為了讓爬蟲程式使用全小寫網址可以正常瀏覽我的網站,我將原本 Base64 編碼的方式改為 Base32 編碼。
Base32 編碼為不分大小寫的編碼方式,編碼後可用的字母為
abcdefghijklmnopqrstuvwxyz234567
使用 Base32 編碼結果放在網址上當參數,也不會因為對方更改大小寫而造成解碼錯誤
以下是我使用 Base32 編碼與解碼的方法
/// <summary>
/// Base 32 編碼
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public string EncodeBase32(string value)
{
if (string.IsNullOrEmpty(value)) return null;
string Alphabet = "abcdefghijklmnopqrstuvwxyz234567";
var valueBytes = Encoding.UTF8.GetBytes(value);
var encodedBuilder = new StringBuilder();
var position = 0;
var left = 0;
for (var i = 0; i < valueBytes.Length * 8 / 5 + (valueBytes.Length * 8 % 5 == 0 ? 0 : 1); i++)
{
var encodedByte = default(byte);
if (left > 0)
{
encodedByte |= (byte)(valueBytes[position] << (8 - left));
if (left <= 5 && position < valueBytes.Length - 1)
{
position++;
if (left < 5) encodedByte |= (byte)(valueBytes[position] >> left);
}
}
else
{
encodedByte |= valueBytes[position];
}
encodedBuilder.Append(Alphabet[(byte)(encodedByte >> 3)]);
left = 8 * (position + 1) - 5 * (i + 1);
}
return encodedBuilder.ToString();
}
/// <summary>
/// Base 32 解碼
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public string DecodeBase32(string value)
{
if (string.IsNullOrEmpty(value)) return null;
string Alphabet = "abcdefghijklmnopqrstuvwxyz234567";
value = value.ToLower().TrimEnd('=');
var decodedBytes = new byte[value.Length * 5 / 8];
var position = 0;
var available = 0;
for (var i = 0; i < value.Length; i++)
{
var symbol = (byte)(Alphabet.IndexOf(value[i]) << 3);
if (available > 0)
{
decodedBytes[position] |= (byte)(symbol >> (8 - available));
if (available <= 5 && position < decodedBytes.Length - 1)
{
decodedBytes[++position] |= (byte)(symbol << available);
}
}
else
{
decodedBytes[position] |= symbol;
}
available = 8 * (position + 1) - 5 * (i + 1);
}
return Encoding.UTF8.GetString(decodedBytes);
}
程式碼中的語法string Alphabet = "abcdefghijklmnopqrstuvwxyz234567";
可以修改為string Alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
這樣編碼結果字母就可以為全大寫。
使用 Base32 當網址參數有幾個好處
而缺點的話包含
有關 Base32 的編碼說明可以參考維基百科
[C#] Convert.ToBase64String 基本轉碼及適用網址參數轉碼延伸應用