7

我写了一个网站,利用SHA-256哈希来验证用户的密码。这是一个相对不安全的设置,因为大多数用户将拥有相同的用户名/密码。为了尽力保护它至少一点点,我做了以下内容:Chrome和IE返回不同的SHA哈希值

  1. 客户端从服务器
  2. 客户端请求一个新的盐哈希有这种盐
  3. 密码的客户端发送的散列与盐回服务器
  4. 服务器密码哈希实际的密码,并比较了这两种

这里是我的代码:

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

$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; 
     }); 
    }); 

此代码工作正常的谷歌浏览器,而不是在Internet Explorer 11(如被看见在调试器)的问题是,哈希由javascript生成的结果与由C#生成的结果不同。

嫌疑人这与字符编码有关,但在网上没有发现太多证明/驳斥这个理论(或帮助解决一般问题)。如果有更好的方法来解决这个问题,我很乐意听到这个消息,但是也想理解原始错误的原因。

哈希为什么不同,我能做些什么来解决它?

+0

什么是“sjcl”?通过基于随机字符串的大规模比较运行(即,生成一百万个随机字符串,在两侧对它们进行散列,比较结果),我会确保JS和C#哈希产生相同的输出。为了保持事物的确定性(所以结果很重要),我会在这次测试中不使用盐。 – Alex

+0

@Alex sjcl是斯坦福大学的Javascript Crypto库。既然Chrome可以正常工作,你是否建议针对C#运行Chrome浏览器,针对C#的IE还是两者(没有建议的盐)? – BradleyDotNET

+0

以上所有内容:如果Chrome始终可用,IE永远不会,那么您可以确认它是浏览器问题。现在,如果其中一个*有时*可以工作... – Alex

回答

3

IE确实是而不是就像查询字符串中的Unicode字符一样。它也不喜欢ASCII的一些“特殊”字符。即使它正确地接受它们,并正确执行散列,但在运行此代码时,salt是“???????”来自IE浏览器时,以及来自Chrome的正确字符串。

简单的解决方法是将salt的字符集限制为大写,小写和数字。使用这种方法,两个浏览器都给出了正确的散列。