简体   繁体   English

Chrome和IE返回不同的SHA哈希值

[英]Chrome and IE return different SHA hashes

I have written a website that utilizes a SHA-256 hash to validate a user's password. 我写了一个利用SHA-256哈希来验证用户密码的网站。 This is a relatively unsecure setup to start with, as most users will have the same username/password. 这是一个相对不安全的设置,因为大多数用户将拥有相同的用户名/密码。 To try and protect it at least a little bit, I do the following: 为了尝试保护它至少一点点,我做以下事情:

  1. The client requests a new salt from the server 客户端从服务器请求新的salt
  2. The client hashes the password with this salt 客户端用这个盐哈希密码
  3. The client sends the hashed password with the salt back to the server 客户端将带有salt的哈希密码发送回服务器
  4. The server hashes the actual password and compares the two 服务器散列实际密码并比较两者

Here is my code: 这是我的代码:

C# C#

//Just for testing!
private static Dictionary<string, string> users = new Dictionary<string, string>() { { "User", "Password" } };

[HttpGet]
public HttpResponseMessage GetSalt()
{
   RNGCryptoServiceProvider secureRNG = new RNGCryptoServiceProvider();
   byte[] saltData = new byte[64];

   secureRNG.GetBytes(saltData);

   HttpResponseMessage response = new HttpResponseMessage();
   response.Content = new StringContent(System.Text.Encoding.Unicode.GetString(saltData), System.Text.Encoding.Unicode);
   return response;
}

[HttpGet]
public bool ValidateUser(string userName, string hashedPassword, string salt)
{
   SHA256Managed hash = new SHA256Managed();         
   if (users.ContainsKey(userName))
   {
       string fullPassword = salt + users[userName];
       byte[] correctHash = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(fullPassword));

       if (hashedPassword.ToUpper() == BitConverter.ToString(correctHash).Replace("-",""))
       {
           return true;
       }
   }
   return false;
}

Javascript 使用Javascript

$scope.login = function () {
    $http.get('api/Login').success(function (salt) {
        //Hash the password with the salt and validate
        var hashedPassword = sjcl.hash.sha256.hash(salt.toString().concat($scope.password));
        var hashString = sjcl.codec.hex.fromBits(hashedPassword);

        $http.get('api/Login?userName=' + $scope.userName + '&hashedPassword=' + hashString + '&salt=' + salt).success(function (validated) {
            $scope.loggedIn = validated;
        });
    });

This code works fine on Google Chrome, but not on Internet Explorer 11. The problem (as seen in the debugger) is that the hash generated by the javascript is different than that generated by C#. 此代码在Google Chrome上运行良好,但在Internet Explorer 11上运行不正常。问题(如调试器中所示)是javascript生成的哈希值与C#生成的哈希值不同。

I suspect this has something to do with character encoding, but haven't found much on the web to prove/disprove this theory (or help with the problem in general). 怀疑这与字符编码有关,但是在网上没有发现很多东西来证明/反驳这个理论(或者总体上帮助解决这个问题)。 If there is a better way to accomplish this problem, I'm happy to hear about it but would like understanding as to the cause of the original error as well. 如果有更好的方法来解决这个问题,我很高兴听到它,但也希望了解原始错误的原因。

Why are the hashes different, and what can I do to fix it? 为什么哈希不同,我该怎么做才能解决它?

IE does not like Unicode characters in the query string. IE浏览器喜欢在查询字符串中的Unicode字符。 It also doesn't like some "special" characters that are ASCII. 它也不喜欢一些ASCII的“特殊”字符。 Even though it accepts them correctly, and performs the hash correctly, when you run this code, the salt is "???????" 即使它正确接受它们并正确执行哈希,当你运行这段代码时,盐就是“???????” when coming from IE, and the correct string when coming from Chrome. 来自IE时,以及来自Chrome的正确字符串。

The simple fix is to just limit the character set of the salt to upper-case, lower-case, and numbers. 简单的解决方法是将salt的字符集限制为大写,小写和数字。 Using this method, both browsers give the correct hash. 使用此方法,两个浏览器都提供正确的哈希。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM