是PHP的password_verify()针对极长的密码(DoS攻击)安全吗? [英] Is PHP's password_verify() safe against extremely long passwords (DoS attack)?
问题描述
普通攻击的场景:
在2013 Django的作为了攻击者一般漏洞可以通过[的在这里看到安全通知。我不能确定是否使用PHP的的 password_verify()的等密码散列方法没有任何进一步的检查时,这仍然是可能的。
In 2013 Django had a general vulnerability as an attacker could create extremely intense CPU calculations via very large passwords [see the security notice here]. I'm unsure if this is still possible when using PHP's password_verify() and other password-hashing methods without any further checks.
PHP的文件说:
使用的算法中的参数的PASSWORD_BCRYPT,将导致在密码参数被截断到72个字符的最大长度。
Using the PASSWORD_BCRYPT for the algo parameter, will result in the password parameter being truncated to a maximum length of 72 characters.
但是,PHP的code MAYBE说不同的东西:
借助 C $ C $后面PHP 5.5.0Ç的的 password_verify()的功能但并不直接限制传递的参数(也许在bcrypt算法里面更深层次的?)。此外, PHP实现不限制的说法。
The C code behind PHP 5.5.0's password_verify() function however does not limit the passed argument directly (maybe on a deeper level inside the bcrypt algorithm ?). Also, the PHP implementation does not limit the argument.
的问题:
时的 password_verify()的(和相同的功能设置等功能),通过刷爆了POST参数防范DoS脆弱?也请考虑POST上传大小的站点范围内的配置情况下比4MB大得多。
Is password_verify() (and other functions of the same function set) vulnerable against DoS via maxed out POST parameters ? Please also consider site-wide config situations of POST upload sizes much larger than 4MB.
推荐答案
密码仅限于内部72个字符的隐窝算法。
The password is limited to 72 characters internally in the crypt algorithm.
要明白为什么,让我们来看看的crypt()
的源:<一href=\"http://lxr.php.net/xref/PHP_TRUNK/ext/standard/crypt.c#202\">http://lxr.php.net/xref/PHP_TRUNK/ext/standard/crypt.c#202
To see why, let's look at crypt()
's source: http://lxr.php.net/xref/PHP_TRUNK/ext/standard/crypt.c#202
} else if (
salt[0] == '$' &&
salt[1] == '2' &&
salt[3] == '$') {
char output[PHP_MAX_SALT_LEN + 1];
memset(output, 0, PHP_MAX_SALT_LEN + 1);
crypt_res = php_crypt_blowfish_rn(password, salt, output, sizeof(output));
if (!crypt_res) {
ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
return NULL;
} else {
result = zend_string_init(output, strlen(output), 0);
ZEND_SECURE_ZERO(output, PHP_MAX_SALT_LEN + 1);
return result;
}
的密码
字段是一个简单的的char *
字段。因此,有没有长度的信息。所有这一切传递是一种正常的指针。
The password
field is a simple char*
field. So there's no length information. All that's passed is a normal pointer.
因此,如果我们遵循通过,我们最终会降落在<一个href=\"http://lxr.php.net/xref/PHP_TRUNK/ext/standard/crypt_blowfish.c#BF_set_key\"><$c$c>BC_set_key$c$c>.
So if we follow that through, we'll eventually land at BC_set_key
.
最重要的部分是循环:
for (i = 0; i < BF_N + 2; i++) {
tmp[0] = tmp[1] = 0;
for (j = 0; j < 4; j++) {
tmp[0] <<= 8;
tmp[0] |= (unsigned char)*ptr; /* correct */
tmp[1] <<= 8;
tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
if (j)
sign |= tmp[1] & 0x80;
if (!*ptr)
ptr = key;
else
ptr++;
}
diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
expanded[i] = tmp[bug];
initial[i] = BF_init_state.P[i] ^ tmp[bug];
}
BF_N
被定义为16所以外循环将循环18次( BF_N + 2
)。
BF_N
is defined to be 16. So the outer loop will loop 18 times (BF_N + 2
).
内环将循环4次。 4 * 18 == 72。
The inner loop will loop 4 times. 4 * 18 == 72.
和你有它,只有72键的字符将被读取。没有更多的。
And there you have it, only 72 characters of the key will be read. No more.
现在,有一个有趣的副作用该算法。由于它使用,它不可能为它使用任何过去 \\ 0 $ C C字符串(由
\\ 0
空字节结尾的字符串) $ C>。所以包含空字节的密码将失去以往任何熵。例如: http://3v4l.org/Y6onV
Now, there's an interesting side-effect to that algorithm. Because it uses C-Strings (strings terminated by a \0
null byte), it's impossible for it to use anything past \0
. So a password that contains a null-byte will lose any entropy past it. Example: http://3v4l.org/Y6onV
这篇关于是PHP的password_verify()针对极长的密码(DoS攻击)安全吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!