2010-10-04 15 views
1

我的Web應用程序通過JSON協議與服務器通信。在從Web應用程序發送每條JSON消息之前,我對它運行一個hmac-sha1函數(在已編碼的對象上),並將生成的HMAC插入到JSON請求的標頭中。PHP中的哈希JSON不會產生與Javascript中的unicode字符相同的結果

在服務器端,我用PHP解碼JSON消息,提取HMAC,從對象中取消設置()HMAC,然後將對象編碼回JSON並創建一個HMAC。

只要我不使用「ž,š,č」等字符,HMAC就會匹配。當我在消息中使用這些字符時,HMAC不再匹配。

在Web應用程序中,我使用jQuery.post()傳輸已編碼的JSON字符串。

如果我通過JSON編碼的答覆將我從Web應用程序獲得的數據發回給它,應用程序將很好地顯示「ž,č,š」。

我該如何讓HMAC匹配?

更新: 這只是最新版本的Firefox和Opera的問題。它在IE8和Chrome上運行良好。在前者的瀏覽器,JSON字符串(在發送之前)是:

{"body":[{"name":"Žiga Kraljevič","email":"[email protected]","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4259d6ef8f477c020d644409cc16dd9c42301e8"}} 

,而在後者的瀏覽器(IE8和Chrome,它的工作原理)如下:

{"body":[{"name":"\u017diga Kraljevi\u010d","email":"[email protected]","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4e9e2d0d8d11728a2b4329ad6dacdb9409b1de1"}} 

回答

1

什麼是您的hmac-sha1功能,它從哪裏來?如果它採用JSON String作爲輸入,則會出現隱式編碼到字節的步驟,因爲SHA1在字節上運行,而不是UTF-16代碼單元,如JS String

我會懷疑你的JS函數是使用「一個代碼單元n每字節n」的編碼類型,以便於使用像getCharCodeAt這樣的工具進行計算。這與字符串輸入已被編碼爲ISO-8859-1的效果相同。而如果您使用encodeURIComponent或通過XMLHttpRequest發佈原始字符,則隱式編碼爲UTF-8。

您可以將String轉換爲JS hmac-sha1函數的UTF-8字節存儲爲代碼單元格式,這可能會使其與PHP匹配。有一個鬼鬼祟祟的成語來做到這一點:

var utf8= unescape(encodeURIComponent(s)); 

在發佈JSON我的base64反正用urlencode它的URL編碼

應該足夠(與encodeURIComponent,不escape這是錯誤的東西絕對一切除了上面的UTF-8轉換技巧的相反步驟)。

順便說一句,這是什麼目的?你知道它並不以任何方式保護瀏覽器和服務器之間的連接,是嗎?

編輯:

我使用jssha.sourceforge.net的SHA1-HMAC。在PHP中,我使用hash_hmac。

工作對我來說:

var data= '\u017E, \u010D, \u0161'; // 'ž, č, š' in a Unucode string 
var utf8bytes= unescape(encodeURIComponent(data)); 
var hmac= new jsSHA(utf8bytes).getHMAC('foo', 'ASCII', 'SHA-1', 'HEX'); 
alert(hmac); // 5d15f0b9... 
var form= 'message='+encodeURIComponent(data)+'&hmac='+encodeURIComponent(hmac); 
xmlhttprequest.send(form); 

...

$utf8bytes= $_POST['message']; // "\xc5\xbe, \xc4\x8d, \xc5\xa1" 
           // which is 'ž, č, š' as UTF-8 in byte string 
$hmac= hash_hmac('sha1', $utf8bytes, 'foo'); 
echo $hmac; // 5d15f0b9... 
echo strtolower($hmac)===strtolower($_POST['hmac']); // true 

此使用二進制('ASCII'到jsSHA)鍵foo。如果您使用的是帶有非ASCII字符的二進制密鑰,則您必須確保這些的編碼方式與數據相同。

HMAC的關鍵是服務器和客戶端之間的共享密鑰,它之前已通過安全連接進行交換。

這不僅是您必須通過安全連接發送的密鑰,還需要整個頁面及其中的所有腳本。否則,一箇中間人攻擊可能會破壞你的腳本到瀏覽器的路徑,以便用一個使用密鑰簽署僞造消息的版本替換它們。如果你有一個適用於所有這些東西的HTTPS服務器,沒問題。我不確定HMAC在這種情況下會做什麼,但似乎有點牽涉到反XSRF方案。

+0

你偷偷摸摸的成語沒有幫助。我正在使用http://jssha.sourceforge.net/用於sha1-hmac。在PHP中,我使用hash_hmac。 HMAC的關鍵是服務器和客戶端之間共享的祕密,以前通過安全連接進行交換。它提供了消息完整性,所以我知道哪個用戶發送了請求。部分JSON請求也是用戶的臨時唯一標識符。 – Matic 2010-10-05 07:06:27

+0

@Matic:[用jssha添加例子] – bobince 2010-10-05 12:51:33

+0

這樣做。謝謝! – Matic 2010-10-05 13:43:07

2

你」可能會遇到多個問題。其中之一很可能是客戶端上使用的字符編碼與服務器上使用的字符編碼不同,值得確保它們相同(更多關於Joel's excellent essay中的字符編碼)。另一個很可能是有多個正確的方式來編碼的東西。編碼器可能正在使用不同的方式。例如,您可以將"編碼爲\"\u0022。兩者都是有效的,並且它們是等價的,但哈希不匹配。同樣,如果不使用重音字符,例如使用空格,我感到有點驚訝。

+0

Web應用程序具有指定的UTF-8編碼,並且XHR請求也具有指定的UTF-8編碼。當發佈JSON時我的base64和urlencode無論如何,否則我無法在PHP中訪問它。 – Matic 2010-10-04 14:10:26

相關問題