使用Apache进行快速SHA-2身份验证,这可能吗?

使用Apache进行快速SHA-2身份验证,这可能吗?,apache,sha256,sha2,mod-auth,Apache,Sha256,Sha2,Mod Auth,好的,我花了几天的时间研究这个问题,我不敢相信Apache本机支持的哈希函数已经过时了 我发现了两种方法,mod_perl和mod_authnz_external,这两种方法都太慢了,因为apache在调用受保护目录中的任何对象时都会运行。这意味着一个用户在一个会话中可能需要经过数百次身份验证 有没有人能让Apache使用比MD5和SHA-1更安全的东西,而不用将身份验证从Apache移开?咸沙-2将是一个真正的奖金 谢谢 如果您使用的GNU/Linux系统的glibc2版本是在过去5年左右发布

好的,我花了几天的时间研究这个问题,我不敢相信Apache本机支持的哈希函数已经过时了

我发现了两种方法,mod_perl和mod_authnz_external,这两种方法都太慢了,因为apache在调用受保护目录中的任何对象时都会运行。这意味着一个用户在一个会话中可能需要经过数百次身份验证

有没有人能让Apache使用比MD5和SHA-1更安全的东西,而不用将身份验证从Apache移开?咸沙-2将是一个真正的奖金


谢谢

如果您使用的GNU/Linux系统的glibc2版本是在过去5年左右发布的,那么您可以修改htpasswd的crypt()实现,将“$6$”预先添加到salt中,然后简单到:

 # htpasswd -d -c .htpasswd someusername
当salt以“$6$”开头时,glibc2将使用salt SHA-512,后面最多16个字符为salt,范围为[a-zA-Z0-9./]

见人3号地下室

我不知道有任何补丁支持这个,但它应该是一个简单的

编辑:我还想提一下,如果你的攻击者有足够的决心,即使是盐腌的SHA-512,一轮也是易碎的。我建议使用HMAC-SHA512编辑128000轮PBKDF2,我已经能够在大多数情况下使用它,但这将是一个非常广泛的编辑,除非您想将htpasswd与openssl链接,openssl具有PKCS5_PBKDF2_HMAC()函数

编辑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 ~ # 
abraxas~#cat pbkdf2.c
#包括
#包括
#包括
#包括
#定义PBKDF2_SALT_前缀“$pbkdf2sha512$”
#定义PBKDF2_SALT_前缀_长度strlen(PBKDF2_SALT_前缀)
#定义PBKDF2_PRF_算法EVP_sha512()
#定义PBKDF2_摘要长度SHA512_摘要长度
#定义PBKDF2_盐_长度32
#定义PBKDF2_结果_长度PBKDF2_盐_前缀_长度+(2*PBKDF2_摘要_长度)+PBKDF2_盐_长度+2
#定义PBKDF2_128000
无效哈希_密码(常量字符*密码,常量未签名字符*密码,字符*结果)
{
无符号整数i;
静态无符号字符摘要[PBKDF2_摘要_长度];
memcpy(结果,PBKDF2_SALT_前缀,PBKDF2_SALT_前缀长度);
memcpy(结果+PBKDF2_SALT_前缀_长度,SALT,PBKDF2_SALT_长度);
结果[PBKDF2_SALT_PREFIX_LENGTH+PBKDF2_SALT_LENGTH]='$';
PKCS5_PBKDF2_HMAC(pass、strlen(pass)、salt、PBKDF2_salt_长度、PBKDF2_轮数、PBKDF2_PRF_算法、PBKDF2_摘要_长度、摘要);
对于(i=0;i
如果您在GNU/Linux系统上使用的glibc2版本是在过去5年左右发布的,那么您可以修改htpasswd的crypt()实现,将“$6$”预先添加到salt中,然后它将非常简单:

 # htpasswd -d -c .htpasswd someusername
当salt以“$6$”开头时,glibc2将使用salt SHA-512,后面最多16个字符为salt,范围为[a-zA-Z0-9./]

见人3号地下室

我不知道有任何补丁支持这个,但它应该是一个简单的

编辑:我还想提一下,如果你的攻击者有足够的决心,即使是盐腌的SHA-512,一轮也是易碎的。我建议使用HMAC-SHA512编辑128000轮PBKDF2,我已经能够在大多数情况下使用它,但这将是一个非常广泛的编辑,除非您想将htpasswd与openssl链接,openssl具有PKCS5_PBKDF2_HMAC()函数

编辑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 ~ # 
abraxas~#cat pbkdf2.c
#包括
#包括
#包括
#包括
#定义PBKDF2_SALT_前缀“$pbkdf2sha512$”
#定义PBKDF2_SALT_前缀_长度strlen(PBKDF2_SALT_前缀)
#定义PBKDF2_PRF_算法EVP_sha512()
#定义PBKDF2_摘要长度SHA512_摘要长度
#定义PBKDF2_盐_长度32
#定义PBKDF2_结果_长度PBKDF2_盐_前缀_长度+(2*PBKDF2_摘要_长度)+PBKDF2_盐_长度+2
#定义PBKDF2_128000
无效哈希_密码(常量字符*密码,常量未签名字符*密码,字符*结果)
{
无符号整数i;
静态无符号字符摘要[PBKDF2_摘要_长度];
memcpy(结果,PBKDF2_SALT_前缀,PBKDF2_SALT_前缀长度);
memcpy(结果+PBKDF2_SALT_前缀_长度,SALT,PBKDF2_SALT_长度);
结果[PBKDF2_SALT_PREFIX_LENGTH+PBKDF2_SALT_LENGTH]='$';
PKCS5_PBKDF2_HMAC(pass、strlen(pass)、salt、PBKDF2_salt_长度、PBKDF2_轮数、PBKDF2_PRF_算法、PBKDF2_摘要_长度、摘要);
对于(i=0;i