RCA.HASH.SALT.EMPTY

在 salt 为空的情况下使用单向密码哈希

如果软件使用密码等敏感数据并通过利用敏感数据计算出单向密码哈希或基于哈希的派生密钥进行保护,例如,通过通信通道进行发送,软件可使用将 salt 用作输入一部分的密码函数。使用 salt 有助于阻止暴力攻击。通过空 salt 值使用这些函数会降低密码强度并更容易发动暴力攻击。

漏洞与风险

若缺失 salt,攻击者更容易使用彩虹表等字典攻击技术预先计算哈希值。请注意,使用 salt 仅略微增加对攻击者的计算要求。对于瞄准个人密码或拥有大量可用计算资源的攻击者来说,将良好的 salt 与哈希一起使用并不能足够增大攻击者的难度。如果哈希函数的计算成本不是很高,脱机密码破解可能仍然有效。许多密码函数的目标是提高效率,容易遭受使用大量计算资源发起的攻击,即使哈希的密码强度很高亦如此。

缓解与预防

考虑使用自适应哈希函数,将其配置为可更改哈希计算所需要的计算量,例如需要的迭代次数或内存量。一些哈希函数自动执行 salt 功能。这些函数可大幅增加暴力攻击的开销。如果不能实施需要额外计算工作的技术,则对于每个处理的密码,使用具有不可预测种子的强随机数生成程序生成新的随机 salt。

漏洞代码示例 1

在此例中,Klocwork 针对 19 行生成 RCA.HASH.SALT.EMPTY 报告,指出通过空 salt 参数调用 EVP_BytesToKey 函数。

复制
  #include <openssl/evp.h>
 
  int  main( int  argc,  char * argv[]) 
  { 
       const  EVP_CIPHER *cipher; 
       const  EVP_MD *digest = NULL;    
       unsigned  char  key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; 
       const  unsigned  char  *salt =  "" ; 
       int  i;

      OpenSSL_add_all_algorithms();

      cipher = EVP_get_cipherbyname( "aes-256-cbc" ); 
      if  (!cipher)  return  -1;     

      digest = EVP_get_digestbyname( "md5" ); 
      if  (!digest)  return  -1;  

      if  (!EVP_BytesToKey(cipher, digest, salt ,        
                           (unsigned  char  *) argv[1],  strlen (argv[1]),        
                           1, key, iv))  return  -3;  

       printf ( "Key: " );  for (i = 0; i < cipher->key_len; ++i)printf ( "%02x" , key[i]);  printf ( "\n" ); 
       printf ( "IV: " );  for (i = 0;  i < cipher->iv_len; ++i)  printf ( "%02x" , iv[i]);  printf ( "\n" );  

       return  0;
  } 

修正代码示例 1

在此例中,传递到 EVP_BytesToKey 函数的 salt 值来自程序的第二个命令行参数或非空字符串值。Klocwork 未报告 RCA.HASH.SALT.EMPTY。

复制
   #include <openssl/evp.h>
   int main(int argc, char* argv[]) 
   {
       const EVP_CIPHER *cipher;
       const EVP_MD *digest = NULL;
       unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
       const unsigned char *default_salt = "7h%ms(81klm3&wer#2";
       const unsigned char *salt;
       int i;

      OpenSSL_add_all_algorithms();

      cipher = EVP_get_cipherbyname("aes-256-cbc");
      if (!cipher) return -1;

      digest = EVP_get_digestbyname("md5");
      if (!digest) return -1;

      if (argc > 2)
         salt = argv[2];
      else
         salt = default_salt;

      if (!EVP_BytesToKey(cipher, digest, salt ,
                          (unsigned char *) argv[1], strlen(argv[1]),
                          1, key, iv)) return -3;

      printf("Key: "); for(i = 0; i < cipher->key_len; ++i) printf("%02x", key[i]); printf("\n");
      printf("IV: ");  for(i = 0;  i < cipher->iv_len; ++i) printf("%02x", iv[i]); printf("\n");

      return 0;

  }

漏洞代码示例 2

在此例中,Klocwork 针对第 16 行生成 RCA.HASH.SALT.EMPTY 报告,指出通过零 salt_length 参数调用了 PKCS5_PBKDF2_HMAC 函数。这说明未向函数提供 salt。

复制
   #include <openssl/pkcs12.h>
 
   int main(int argc, char* argv[]) 
   {
       const EVP_MD *digest = NULL;
       unsigned char key[EVP_MAX_KEY_LENGTH];
       const unsigned char *salt;
       int i;

       OpenSSL_add_all_algorithms();

      digest=EVP_get_digestbyname("md5");
      if (!digest) return -1;

      if (!PKCS5_PBKDF2_HMAC(argv[1], strlen(argv[1]),
                            NULL, 0, -1,
                            digest, EVP_MAX_KEY_LENGTH, key))
          return -2;

      printf("Key: "); for(i = 0; i < EVP_MAX_KEY_LENGTH; ++i) printf("%02x", key[i]); printf("\n");

      return 0;
  }

修正代码示例 2

在此例中,通过非零 salt 长度调用函数 PKCS5_PBKDF2_HMAC 来生成哈希,因此,Klocwork 将不会报告 RCA.HASH.SALT.EMPTY。

复制
   #include <openssl/pkcs12.h>
 
   int main(int argc, char* argv[]) 
   {
       const EVP_MD *digest = NULL;
       unsigned char key[EVP_MAX_KEY_LENGTH];
       const unsigned char *default_salt = "7h%ms(81klm3&wer#2";
       const unsigned char *salt;
       int i;

      OpenSSL_add_all_algorithms();

      digest=EVP_get_digestbyname("md5");
      if (!digest) return -1;

      if (argc > 2)
         salt = argv[2];
      else
         salt = default_salt;

      if (!PKCS5_PBKDF2_HMAC(argv[1], strlen(argv[1]),
                            salt, strlen(salt), -1,
                            digest, EVP_MAX_KEY_LENGTH, key))
          return -2;

      printf("Key: "); for(i = 0; i < EVP_MAX_KEY_LENGTH; ++i) printf("%02x", key[i]); printf("\n");

      return 0;
  }

相关检查器

安全培训

应用程序安全培训材料由 Secure Code Warrior 提供。

扩展

此检查器可通过 Klocwork 知识库进行扩展。有关详情,请参阅调整 C/C++ 分析。