![](/img/trans.png)
[英]String hashing function that would produce identical results in JavaScript and PHP
[英]Hashing JSON in PHP does not produce the same result as in Javascript for unicode characters
我的Web應用程序通過JSON協議與服務器通信。 在從Web應用程序發送每個JSON消息之前,我先在其上(已編碼的對象上)運行hmac-sha1函數,然后將生成的HMAC插入JSON請求的標頭中。
在服務器端,我用PHP解碼JSON消息,提取HMAC,從對象中取消HMAC的設置,然后將該對象編碼回JSON並為其創建HMAC。
只要我不使用“ž,š,č”之類的字符,HMAC就會匹配。 當我在消息中使用這些字符時,HMAC不再匹配。
在Web應用程序中,我使用jQuery.post()傳輸已編碼的JSON字符串。
如果我將通過Web應用程序獲得的數據發送回JSON編碼的回復中,則該應用程序將很好地顯示“ž,č,š”。
如何使HMAC匹配?
更新:這僅是最新版本的Firefox和Opera上的問題。 在IE8和Chrome上運行正常。 在以前的瀏覽器上,JSON字符串(發送前)為:
{"body":[{"name":"Žiga Kraljevič","email":"test@email.com","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4259d6ef8f477c020d644409cc16dd9c42301e8"}}
在后一種瀏覽器(IE8和Chrome,可在其中運行)上顯示以下內容:
{"body":[{"name":"\u017diga Kraljevi\u010d","email":"test@email.com","password":"secretpass"}],"header":{"apiID":"person-27jhfa83ha-js84sjj18dasjd","hmac":"e4e9e2d0d8d11728a2b4329ad6dacdb9409b1de1"}}
您可能遇到了多個問題。 其中之一很可能是客戶端上使用的字符編碼與服務器上使用的字符編碼不同,值得確保它們相同(有關Joel優秀論文中的字符編碼的更多信息)。 另一種可能是存在多種正確的編碼方式。 編碼器可能會使用不同的方式。 例如,您可以將字符串中的"
編碼為\\"
或"
。 兩者都是有效的,並且它們是等效的,但是哈希值不匹配。 同樣,讓您在不使用帶重音的字符(例如帶空格)時沒有遇到更多麻煩,我感到有些驚訝。
您的hmac-sha1函數是什么,它從哪里來? 如果將JSON String
作為輸入,則此處將執行隱式的“按字節編碼”步驟,因為SHA1對字節進行操作,而不是像JS String
這樣的UTF-16代碼單元。
我懷疑您的JS函數使用的是“每個字節n個代碼單位n”類型的編碼,以便通過getCharCodeAt
工具輕松進行計算。 這實際上與將字符串輸入編碼為ISO-8859-1相同。 而如果您使用encodeURIComponent
或通過XMLHttpRequest發布原始字符,則隱式編碼為UTF-8。
您可以將JS hmac-sha1函數將String
轉換為UTF-8字節存儲為代碼單位格式,這可能使其與PHP匹配。 有一個偷偷摸摸的習慣來做到這一點:
var utf8= unescape(encodeURIComponent(s));
發布JSON時,我會以base64進行urlencode
URL編碼應該足夠了(使用encodeURIComponent
,不要escape
, 除了上面的UTF-8轉換技巧的反向步驟,這絕對是所有事情的錯)。
順便說一句,這是什么目的? 您知道它不以任何方式保護瀏覽器和服務器之間的連接,是嗎?
編輯:
我正在使用shasha-hmac的jssha.sourceforge.net。 在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方案有關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.