October 7, 2012

網址查詢字串的驗證與排序

在某個專案中和third-party廠商所開發的API做介接。對方提供的API是以Key Value Pair (KVP)來實作,所以當我們呼叫對方的API時是直接呼叫某個網址如http://thirdparty/api?key1=value1&key2=value2&key3=value3&VerificationCode=4a66f0dfc4234cf6972353fd169fdb08。VerificationCode是所謂的驗證碼,用來確認查詢字串在傳送過程中是否被修改過。它的計算方式是將查詢字串key1=value1&key2=value2&key3=value3先做排序後,加上某個只有我們和third-party知道的安全碼,再以特定的演算法做hash(如MD5)來取得此驗證碼。所以當對方收到API呼叫請求時,只要以相同的方式來計算出驗證碼便可知道查詢字串是否有偽造。

在.NET中如果要對KVP做排序可以使用SortedList<TKey, TValue>或是SortedDictionary<TKey, TValue>兩個泛型集合類別。我們選用SortedList<TKey, TValue>來加入KVP,如此SortedList<TKey, TValue>便會幫我們自動排序好這些KVP,而SortedList<TKey, TValue>預設排序出來的結果是小寫字母會排在大寫字母前面。
            SortedList<string, string> list = new SortedList<string, string>();
            list.Add("key1", "value1");
            list.Add("key2", "value2");
            list.Add("key3", "value3");
接來下我們只要把這些KVP用&串接起來計算出驗證碼後加入原本的查詢字串即大功造成。

不過在測試介接時,我們計算出的驗證碼與對方所計算出的驗証碼不一樣,這可能有幾個原因。
  1. 漏了某個KVP
  2. KVP的大小寫不正確
  3. KVP的排序不正確
在排除了1與2兩種可能性後,我們和對方比對了一下兩方排序出來的查詢字串,發現對方排序出來的Key,只要是首字大寫的字母都被排在首字小寫的字母前面,原來對方排序的方式是使用ASCII值的排序方式,而大寫字母的ASCII值比小寫小,所以排序結果便與我們相反。不過規格書上的不明確(或是我們誤解)也是個問題,上面寫著in an ascending order(由小到大),這ascending order被我們理解成alphabetical order(字母由小到大)。要解決這個問題,我們只要修改SortedList<TKey, TValue>預設的排序方式即可。
            SortedList<string, string> list = new SortedList<string, string>(StringComparer.Ordinal);
            list.Add("key1", "value1");
            list.Add("key2", "value2");
            list.Add("key3", "value3");
StringComparer.Ordinal會讓SortedList<TKey, TValue>排序時是以字母實際的byte值去做比較,如此大寫字母便會比小寫字母小而排在前面了。

參考
  1. SortedList<TKey, TValue>
  2. SortedDictionary<TKey, TValue>
  3. StringComparer.Ordinal

No comments: