如何於MVC/Web API路由中傳送Base64編碼
之前提到過如何使用路由傳遞含"+"符號到ASP.NET Web API 2有二種方式,一是使用QueryString,一是修改allowDoubleEscaping,不過allowDoubleEscaping的修改會降低系統安全性,是個不得以的選項。重覆的問題又活生生出現在面前,只是這一次必須把這個含+符號的值放在路由中。怎麼辦?有無更好的方式解決這個問題呢?
+號+號你為什麼會出現
首先,第一次處理如何使用路由傳遞含"+"符號到ASP.NET Web API 2問題時,那是一段對稱加密的程式,因為是中間接手處理,沒有細看實作細節,我們以DESCryptoServiceProvider (DES 的實作)為例來說明:
private string Encryption(string plainText) { if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("cipherText"); byte[] b = Encoding.UTF8.GetBytes(plainText); DESCryptoServiceProvider des = new DESCryptoServiceProvider(); ICryptoTransform ict = des.CreateEncryptor(des.Key, des.IV); byte[] desData = ict.TransformFinalBlock(b, 0, b.Length); return Convert.ToBase64String(desData); }
看出問題點了嗎?
我們先看看這個的字串如果使用在路由上會產生什麼問題,以/{controller}/{action}/{id}路由為例:/home/index/EZ7+/+wvla4=,怎麼+號(加號)都還沒處理就馬上出事了?
看的出來了嗎?
有在寫MVC或Web API的人,第二個問題很直覺就能看出來了,多了一個「/」符號,此時就算設置allowDoubleEscaping讓路由能正常處理+號,id透過ModelBinding後還是不正常的。
回到問題一,看出問題了嗎?
Base64
問題在我們把加密的結果使用Base64編碼轉換並進行回傳,用URL傳送Base64編碼會碰到一些問題,看看Base64編碼使用的符號:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
。黑大的討論是把Base64編碼放在QueryString之中的解決辦法。還是無法解決我需要把Base64編碼值放在路由中的需求。
用於URL的改進Base64編碼
原來解決方式早已經列在wiki的文章之中,以下引述自wiki:
然而,標準的Base64並不適合直接放在URL裡傳輸,因為URL編碼器會把標準Base64中的「/」和「+」字符變為形如「%XX」的形式,而這些「%」號在存入數據庫時還需要再進行轉換,因為ANSI SQL中已將「%」號用作通配符。
為解決此問題,可採用一種用於URL的改進Base64編碼,它不在末尾填充'='號,並將標準Base64中的「+」和「/」分別改成了「-」和「_」,這樣就免去了在URL編解碼和數據庫存儲時所要作的轉換,避免了編碼信息長度在此過程中的增加,並統一了數據庫、表單等處對象標識符的格式。
簡言之,找兩個非+、/、=的符號來Replace即可。依照wiki的說明,我們實作以下程式碼:
public static class UrlBase64 { public static string ToUrlReplace(string base64String) { return base64String.Replace("+", "-").Replace("/", "_"); } public static string FromUrlReplace(string base64String) { return base64String.Replace("-", "+").Replace("_", "/"); } }
加密回傳之前把+與/給取代,解密之前則反向給取代回來。
這樣取代之後,不論是QueryString或使用在路由(Route)上都不會再發生+或\符號造成的問題。
沒有留言:
張貼留言
感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。