2012-08-06 157 views
2

我有一個構建HTML電子郵件的應用程序。包含在內容中的是編碼的URL參數,例如可能包含促銷代碼或產品參考。該電子郵件由Windows服務(本質上是一個控制檯應用程序)生成,並且該鏈接在被點擊時由MVC網站處理。下面是用於創建電子郵件鏈接的代碼:無法解碼Base-64 URL

string CreateLink(string domain, string code) { 
    // code == "xyz123" 
    string encrypted = DES3Crypto.Encrypt(code); // H3uKbdyzrUo= 
    string urlParam = encrypted.EncodeBase64(); // SDN1S2JkeXpyVW890 
    return domain + "/" + urlParam; 
} 

的MVC控制器上的操作方法構造如下:

public ActionResult Index(string id) { 
    string decoded = id.DecodeBase64(); 
    string decrypted = DES3Crypto.Decrypt(decoded); 
    ... 
} 

在我們所有的測試,這一機制曾擔任預期,但是,現在我們已經走了,我們正在看到大約有4%的錯誤率,其中base-64的轉換失敗,但有以下例外:

輸入不是有效的Base-64字符串,因爲它包含非基本64性格,超過兩個填充字符ers或填充字符中的非空白字符。

來自url的id參數'看起來'確定。這個問題似乎與EncodeBase64/DecodeBase64方法失敗,因爲DecodeBase64方法在失敗時返回一個'亂碼'字符串,例如「 nl 」「」鏈接。

此外,大部分錯誤都來自IE6用戶代理,導致我認爲這是一個字符編碼問題,但我不明白爲什麼。

作爲參考,這裏是我的基-64的URL編碼的代碼:

public static string EncodeBase64(this string source) 
    { 
    byte[] bytes = Encoding.UTF8.GetBytes(source); 
    string encodedString = HttpServerUtility.UrlTokenEncode(bytes); 
    return encodedString; 
    } 

    public static string DecodeBase64(this string encodedString) 
    { 
    byte[] bytes = HttpServerUtility.UrlTokenDecode(encodedString); 
    string decodedString = Encoding.UTF8.GetString(bytes); 
    return decodedString; 
    } 

任何建議,將不勝感激。

+0

當你得到異常時,我會在你的控制器中記錄「id」值,看看你是否可以發現一個模式。我的猜測是,來到你身份證有一些無效字符或被截斷(可能是由用戶的郵件客戶端) – 2012-08-07 13:26:34

+0

嗨Hector,我一直這樣做,但我看不出任何明顯的問題與字符串 - 這裏是一個失敗的字符串的例子「ywhar0xznxpjdnfnddc0yxzbk2jnqt090」。我注意到的一件事是,大多數用戶代理被報告爲IE6.0 - 但我不明白爲什麼應該如此。 – Neilski 2012-08-07 13:49:22

+0

我想我可能找到了問題! IE6(或其關聯的電子郵件客戶端)似乎將url轉換爲小寫 - 使用base-64派生編碼進行編碼時,大小寫字符具有不同的含義,因此在網站上解碼時會出現問題。所以,我只需要找到一種只使用小寫字母數字字符來編碼url的方法!想法任何人? – Neilski 2012-08-07 16:39:39

回答

2

回顧一下,我創建了一個URL,使用一個base-64編碼參數,它本身就是一個Triple DES加密字符串。因此,URL看起來像http:// [Domain_Name]/SDN1S2JkeXpyVW890該鏈接引用了MVC網站上的控制器操作。

然後將該URL插入HTML格式的電子郵件中。查看錯誤日誌,我們看到大約5%的響應鏈接的公共用戶正在拋出「無效的base-64字符串錯誤」。大多數(但不是全部)這些錯誤都與IE6用戶代理有關。

在嘗試了許多基於字符和URL編碼的可能解決方案之後,發現客戶端進程中的某處URL正在轉換爲小寫 - 這當然破壞了base-64編碼(因爲它是使用大寫和小寫編碼字符)。

無論是客戶端瀏覽器,電子郵件客戶端還是本地防病毒軟件造成的案件腐敗,我都無法確定。

不要使用任何的標準的基本-64的編碼方法,而不是使用一個基-32或zBase-32編碼代替 - 這兩者都是不區分大小寫的。

請參見以下鏈接瞭解更多詳情

Base-32 - Wikipedia

MyTenPennies Base-32 .NET Implementation

這個故事的寓意是,BASE-64 URL編碼可以在一些公共環境是不可靠的。 Base-32雖然略爲冗長,但是更好的選擇。

希望這會有所幫助。

+0

我們也看到Base-64數據有時會被轉換爲小寫字母。無法隔離造成這種情況的原因(電子郵件客戶端或瀏覽器?) – Spongeboy 2014-08-12 07:13:03

+0

我們已經使用ZBase-32編碼運行了幾年,現在它已經非常可靠 - 請參閱http:// mytenpennies。 wikidot.com/blog:base-32-encoder – Neilski 2014-08-12 10:33:23

+0

總的來說,我們使用TripleDES來加密值,然後使用ZBase32進行編碼。在另一端,我們將解碼ZBase-32的流程解碼,並使用TripleDES解密結果。爲了簡化生活,我們創建了幾個字符串擴展方法ToZBase32()FromZBase32()。 – Neilski 2014-08-12 10:38:55

1

看起來你真的很接近。您從encyrpted.EncodeBase64()函數中返回了一個額外的零。

試試這個:

string data = "H3uKbdyzrUo="; 
string b64str = Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(data)); 
string clearText = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(b64str)); 
+0

我最初使用Convert.ToBase64String方法,但在作爲URL的一部分使用時遇到同樣的問題。我改爲HttpServerUtility.UrlTokenEncode,希望它能解決這個問題,但事實上似乎沒有任何區別。這兩種方法似乎都不使用任何東西,只能使用純數字,所以我無法弄清楚URL的改變位置/原因。 – Neilski 2012-08-07 16:23:44

0

這是一個有趣的問題。我的猜測是,IE 6正在吃一些人物。

例如,你列入「ywhar0xznxpjdnfnddc0yxzbk2jnqt090」字符串的長度四的倍數(這是FromBase64要求工作http://msdn.microsoft.com/en-us/library/system.convert.frombase64string.aspx

但是,如果你要墊弦,直到它的長度是四的倍數(「ywhar0xznxpjdnfnddc0yxzbk2jnqt090」+「a12」),那麼這是有效的。

MSDN文檔說,一個(「=」)或兩個(「==」)等號字符用於填充to/fromBase64方法,我懷疑IE 6正在從您發送的字符串中截斷該字符。

這是總推測,但我希望它有幫助。

+0

也許,但我不明白爲什麼...... HttpServerUtility.UrlTokenEncode()方法應該只使用純字母數字字符,所以雖然url是非英文的,但如果你明白我的意思? http:// [my_domain]/SDN1S2JkeXpyVW890甚至沒有那麼長。 – Neilski 2012-08-07 16:29:51