好吧,我花了几天时间研究这个,我不敢相信 Apache 原生支持的散列函数已经过时了。
我发现了几种方法来做到这一点,它们是 mod_perl 和 mod_authnz_external,它们都太慢了,因为只要调用受保护目录中的任何对象,apache 就会运行它。这意味着用户可能必须在单个会话中进行数百次身份验证。
有没有人设法让 Apache 使用比 MD5 和 SHA-1 更安全的东西,而无需将身份验证从 Apache 移开?Salted SHA-2 将是一个真正的奖励。
谢谢!
如果你在 GNU/Linux 系统上使用过去 5 年左右发布的 glibc2 版本,你可以修改 htpasswd 的 crypt() 实现,在 salt 前面加上“$6$”,然后就很简单了作为:
# htpasswd -d -c .htpasswd someusername
当 salt 以“$6$”开头时,glibc2 将使用 salted SHA-512,之后最多 16 个字符是 salt,范围为 [a-zA-Z0-9./]。
见 man 3 地穴。
我不知道有任何补丁可以支持这一点,但它应该是一个简单的补丁。
编辑:我还想提一下,如果您的攻击者足够坚定,那么一轮甚至加盐的 SHA-512 是易碎的。我建议并且在我能够编辑的大多数事情中使用 128000 轮带有 HMAC-SHA512 的 PBKDF2,但这将是一个非常广泛的编辑,除非您想将 htpasswd 与具有 PKCS5_PBKDF2_HMAC 的 openssl 链接起来() 功能。
编辑 2:此外,如果您有兴趣,使用 openssl 进行强散列并不难:
abraxas ~ # cat pbkdf2.c
#include <string.h>
#include <stdio.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#define PBKDF2_SALT_PREFIX "$pbkdf2sha512$"
#define PBKDF2_SALT_PREFIX_LENGTH strlen(PBKDF2_SALT_PREFIX)
#define PBKDF2_PRF_ALGORITHM EVP_sha512()
#define PBKDF2_DIGEST_LENGTH SHA512_DIGEST_LENGTH
#define PBKDF2_SALT_LENGTH 32
#define PBKDF2_RESULT_LENGTH PBKDF2_SALT_PREFIX_LENGTH + (2 * PBKDF2_DIGEST_LENGTH) + PBKDF2_SALT_LENGTH + 2
#define PBKDF2_ROUNDS 128000
void hash_password(const char* pass, const unsigned char* salt, char* result)
{
unsigned int i;
static unsigned char digest[PBKDF2_DIGEST_LENGTH];
memcpy(result, PBKDF2_SALT_PREFIX, PBKDF2_SALT_PREFIX_LENGTH);
memcpy(result + PBKDF2_SALT_PREFIX_LENGTH, salt, PBKDF2_SALT_LENGTH);
result[PBKDF2_SALT_PREFIX_LENGTH + PBKDF2_SALT_LENGTH] = '$';
PKCS5_PBKDF2_HMAC(pass, strlen(pass), salt, PBKDF2_SALT_LENGTH, PBKDF2_ROUNDS, PBKDF2_PRF_ALGORITHM, PBKDF2_DIGEST_LENGTH, digest);
for (i = 0; i < sizeof(digest); i++)
sprintf(result + PBKDF2_SALT_PREFIX_LENGTH + PBKDF2_SALT_LENGTH + 1 + (i * 2), "%02x", 255 & digest[i]);
}
int main(void)
{
char result[PBKDF2_RESULT_LENGTH];
char pass[] = "password";
unsigned char salt[] = "178556d2988b6f833f239cd69bc07ed3";
printf("Computing PBKDF2(HMAC-SHA512, '%s', '%s', %d, %d) ...\n", pass, salt, PBKDF2_ROUNDS, PBKDF2_DIGEST_LENGTH);
memset(result, 0, PBKDF2_RESULT_LENGTH);
hash_password(pass, salt, result);
printf("Result: %s\n", result);
return 0;
}
abraxas ~ # gcc -Wall -Wextra -O3 -lssl pbkdf2.c -o pbkdf2
abraxas ~ # time ./pbkdf2
Computing PBKDF2(HMAC-SHA512, 'password', '178556d2988b6f833f239cd69bc07ed3', 128000, 64) ...
Result: $pbkdf2sha512$178556d2988b6f833f239cd69bc07ed3$3acb79896ce3e623c3fac32f91d4421fe360fcdacfb96ee3460902beac26807d28aca4ed01394de2ea37b363ab86ba448286eaf21e1d5b316149c0b9886741a7
real 0m0.320s
user 0m0.319s
sys 0m0.001s
abraxas ~ #