2010-10-04 42 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

相关问题