用戶密碼應(yīng)該使用 Argon2, scrypt, bcrypt, pbkdf2 等算法做哈希之后再存入存儲(chǔ)系統(tǒng), https://password-hashing.net
https://libsodium.gitbook.io/doc/password_hashing/default_phf#example-2-password-storage
用戶敏感數(shù)據(jù),應(yīng)該做到傳輸過(guò)程中加密,存儲(chǔ)狀態(tài)下加密 傳輸過(guò)程中加密,可以使用 HTTPS 等認(rèn)證加密通信協(xié)議
存儲(chǔ)狀態(tài)下加密,可以使用 SQLCipher 等類似方案。
例如用戶密碼等,即使是臨時(shí)使用,也應(yīng)在使用完成后應(yīng)當(dāng)將內(nèi)容徹底清空。
錯(cuò)誤:
#include <openssl/crypto.h>
#include <unistd.h>
{
...
string user_password(100, '\0');
snprintf(&user_password, "password: %s", user_password.size(), password_from_input);
...
}
正確:
{
...
string user_password(100, '\0');
snprintf(&user_password, "password: %s", user_password.size(), password_from_input);
...
OPENSSL_cleanse(&user_password[0], user_password.size());
}
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-敏感信息泄露
rand類函數(shù)的隨機(jī)性并不高。而且在使用前需要使用srand()來(lái)初始化。未初始化的隨機(jī)數(shù)可能導(dǎo)致某些內(nèi)容可預(yù)測(cè)。
// Bad
int main() {
int foo = rand();
return 0;
}
上述代碼執(zhí)行完成后,foo的值是固定的。它等效于 srand(1); rand();
。
// Good
int main() {
srand(time(0));
int foo = rand();
return 0;
}
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-邏輯漏洞
在需要生成 AES/SM1/HMAC 等算法的密鑰/IV/Nonce, RSA/ECDSA/ECDH 等算法的私鑰,這類需要高安全性的業(yè)務(wù)場(chǎng)景,必須使用密碼學(xué)安全的隨機(jī)數(shù)生成器 (Cryptographically Secure PseudoRandom Number Generator (CSPRNG) ), 不得使用 rand()
等無(wú)密碼學(xué)安全性保證的普通隨機(jī)數(shù)生成器。
推薦使用的 CSPRNG 有:
RAND_bytes()
函數(shù), https://www.openssl.org/docs/man1.1.1/man3/RAND_bytes.html
randombytes_buf()
函數(shù)getrandom()
系統(tǒng)調(diào)用, https://man7.org/linux/man-pages/man2/getrandom.2.html
.
或者讀 /dev/urandom 文件, 或者 /dev/random 文件。SecRandomCopyBytes()
, https://developer.apple.com/documentation/security/1399291-secrandomcopybytes
BCryptGenRandom()
, CryptGenRandom()
, RtlGenRandom()
#include <openssl/aes.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>
#include <unistd.h>
{
unsigned char key[16];
if (1 != RAND_bytes(&key[0], sizeof(key))) { //... 錯(cuò)誤處理
return -1;
}
AES_KEY aes_key;
if (0 != AES_set_encrypt_key(&key[0], sizeof(key) * 8, &aes_key)) {
// ... 錯(cuò)誤處理
return -1;
}
...
OPENSSL_cleanse(&key[0], sizeof(key));
}
rand()
類函數(shù)的隨機(jī)性并不高。敏感操作時(shí),如設(shè)計(jì)加密算法時(shí),不得使用rand()或者類似的簡(jiǎn)單線性同余偽隨機(jī)數(shù)生成器來(lái)作為隨機(jī)數(shù)發(fā)生器。符合該定義的比特序列的特點(diǎn)是,序列中“1”的數(shù)量約等于“0”的數(shù)量;同理,“01”、“00”、“10”、“11”的數(shù)量大致相同,以此類推。
例如 C 標(biāo)準(zhǔn)庫(kù)中的 rand()
的實(shí)現(xiàn)只是簡(jiǎn)單的線性同余算法,生成的偽隨機(jī)數(shù)具有較強(qiáng)的可預(yù)測(cè)性。
當(dāng)需要實(shí)現(xiàn)高強(qiáng)度加密,例如涉及通信安全時(shí),不應(yīng)當(dāng)使用 rand()
作為隨機(jī)數(shù)發(fā)生器。
實(shí)際應(yīng)用中, C++11 標(biāo)準(zhǔn)提供的random_device
保證加密的安全性和隨機(jī)性
但是 C++ 標(biāo)準(zhǔn)并不保證這一點(diǎn)。跨平臺(tái)的代碼可以考慮用 OpenSSL 等保證密碼學(xué)安全的庫(kù)里的隨機(jī)數(shù)發(fā)生器。
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-敏感數(shù)據(jù)泄露
如果在弱安全場(chǎng)景相關(guān)的算法中自己實(shí)現(xiàn)了PRNG,請(qǐng)確保rand出來(lái)的隨機(jī)數(shù)不會(huì)很小或可預(yù)測(cè)。
// Bad
int32_t val = ((state[0] * 1103515245U) + 12345U) & 999999;
上述例子可能想生成0~999999共100萬(wàn)種可能的隨機(jī)數(shù),但是999999的二進(jìn)制是11110100001000111111,與&運(yùn)算后,0位一直是0,所以生成出的范圍明顯會(huì)小于100萬(wàn)種。
// Good
int32_t val = ((state[0] * 1103515245U) + 12345U) % 1000000;
// Good
int32_t val = ((state[0] * 1103515245U) + 12345U) & 0x7fffffff;
關(guān)聯(lián)漏洞:
高風(fēng)險(xiǎn)-邏輯漏洞
更多建議: