Будьте осторожны при обработке уязвимых данных, таких как пароли, в коде программы
Будьте осторожны при обработке уязвимых данных, таких как пароли, в коде программы. [1]
Это средство проверки проверяет на эти проблемы:
Постоянный вектор инициализации блочного шифра.
Постоянный ключ шифра.
Предсказуемый вектор инициализации блочного шифра.
Предсказуемый ключ шифра.
Чувствительная память кучи, не очищенная перед релизом.
Неочищенные уязвимые данные в стеке.
Небезопасная стандартная функция шифрования.
Постоянный вектор инициализации блочного шифра происходит, когда вы используете константу в векторе инициализации (IV) во время шифрования.
Используя постоянный IV эквивалентно не использованию IV. Ваши зашифрованные данные уязвимы для атак с подбором по словарю.
Блочные шифры повреждают ваши данные в блоки фиксированного размера. Режимы блочного шифра, такие как CBC (Сцепление блоков шифра) защищают от атак с подбором по словарю XOR-лугом каждый блок с зашифрованным выходом от предыдущего блока. Чтобы защитить первый блок, эти режимы используют случайный вектор инициализации (IV). Если вы используете постоянный IV, чтобы зашифровать несколько потоков данных, которые имеют общее начало, ваши данные становятся уязвимыми для атак с подбором по словарю.
Произведите случайный IV при помощи сильного генератора случайных чисел.
Для списка генераторов случайных чисел, которые криптографически слабы, смотрите Vulnerable pseudo-random number generator
.
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
/* Using the cryptographic routines */
int func(EVP_CIPHER_CTX *ctx, unsigned char *key){
unsigned char iv[SIZE16] = {'1', '2', '3', '4','5','6','b','8','9',
'1','2','3','4','5','6','7'};
return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1);
}
В этом примере, вектор инициализации iv
имеет константы только. Постоянный вектор инициализации делает ваш шифр уязвимым для атак с подбором по словарю.
Одна возможная коррекция должна использовать сильный генератор случайных чисел, чтобы произвести вектор инициализации. Исправленный код здесь использует функциональный RAND_bytes
объявленный в openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 /* Using the cryptographic routines */ int func(EVP_CIPHER_CTX *ctx, unsigned char *key){ unsigned char iv[SIZE16]; RAND_bytes(iv, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Постоянный ключ шифра происходит, когда вы используете константу в ключе шифрования или ключе расшифровки.
Если вы используете константу в ключе шифрования или ключе расшифровки, атакующий может получить ваш ключ легко.
Вы используете ключ, чтобы зашифровать и позже дешифровать ваши данные. Если ключ легко получен, данные зашифровали использование, что ключ не безопасен.
Произведите случайный ключ при помощи сильного генератора случайных чисел.
Для списка генераторов случайных чисел, которые криптографически слабы, смотрите Vulnerable pseudo-random number generator
.
#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16
int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){
unsigned char key[SIZE16] = {'1', '2', '3', '4','5','6','b','8','9',
'1','2','3','4','5','6','7'};
return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1);
}
В этом примере, ключе шифра, key
, имеет константы только. Атакующий может легко получить постоянный ключ.
Используйте сильный генератор случайных чисел, чтобы произвести ключ шифра. Исправленный код здесь использует функциональный RAND_bytes
объявленный в openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){ unsigned char key[SIZE16]; RAND_bytes(key, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Предсказуемый вектор инициализации блочного шифра происходит, когда вы используете слабый генератор случайных чисел в векторе инициализации блочного шифра.
Если вы используете слабый генератор случайных чисел в векторе инициирования, ваши данные уязвимы для атак с подбором по словарю.
Блочные шифры повреждают ваши данные в блоки фиксированного размера. Режимы блочного шифра, такие как CBC (Сцепление блоков шифра) защищают от атак с подбором по словарю XOR-лугом каждый блок с зашифрованным выходом от предыдущего блока. Чтобы защитить первый блок, эти режимы используют случайный вектор инициализации (IV). Если вы используете слабый генератор случайных чисел в своем IV, ваши данные становятся уязвимыми для атак с подбором по словарю.
Используйте сильный генератор псевдослучайного числа (PRNG) в векторе инициализации. Например, используйте:
OS-level PRNG, такой как /dev/random
на UNIX® или CryptGenRandom()
на Windows®
Уровень приложения PRNG, такой как Усовершенствованный стандарт шифрования (AES) в режиме Counter (CTR), HMAC-SHA1, и т.д.
Для списка генераторов случайных чисел, которые криптографически слабы, смотрите Vulnerable pseudo-random number generator
.
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <stdlib.h>
#define SIZE16 16
int func(EVP_CIPHER_CTX *ctx, unsigned char *key){
unsigned char iv[SIZE16];
RAND_pseudo_bytes(iv, 16);
return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1);
}
В этом примере, функциональном RAND_pseudo_bytes
объявленный в openssl/rand.h
производит вектор инициализации. Последовательности байта, что RAND_pseudo_bytes
генерирует не обязательно непредсказуемы.
Используйте сильный генератор случайных чисел, чтобы произвести вектор инициализации. Исправленный код здесь использует функциональный RAND_bytes
объявленный в openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *key){ unsigned char iv[SIZE16]; RAND_bytes(iv, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Предсказуемый ключ шифра происходит, когда вы используете слабый генератор случайных чисел в ключе шифрования или ключе расшифровки.
Если вы используете слабый генератор случайных чисел в ключе шифрования или ключе расшифровки, атакующий может получить ваш ключ легко.
Вы используете ключ, чтобы зашифровать и позже дешифровать ваши данные. Если ключ легко получен, данные зашифровали использование, что ключ не безопасен.
Используйте сильный генератор псевдослучайного числа (PRNG) в ключе. Например:
Используйте OS-level PRNG, такой как /dev/random
на UNIX или CryptGenRandom()
на Windows
Используйте уровень приложения PRNG, такой как Усовершенствованный стандарт шифрования (AES) в режиме Counter (CTR), HMAC-SHA1, и т.д.
Для списка генераторов случайных чисел, которые криптографически слабы, смотрите Vulnerable pseudo-random number generator
.
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <stdlib.h>
#define SIZE16 16
int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){
unsigned char key[SIZE16];
RAND_pseudo_bytes(key, 16);
return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1);
}
В этом примере, функциональном RAND_pseudo_bytes
объявленный в openssl/rand.h
производит ключ шифра. Однако последовательности байта, что RAND_pseudo_bytes
генерирует не обязательно непредсказуемы.
Одна возможная коррекция должна использовать сильный генератор случайных чисел, чтобы произвести ключ шифра. Исправленный код здесь использует функциональный RAND_bytes
объявленный в openssl/rand.h
.
#include <openssl/evp.h> #include <openssl/rand.h> #include <stdlib.h> #define SIZE16 16 int func(EVP_CIPHER_CTX *ctx, unsigned char *iv){ unsigned char key[SIZE16]; RAND_bytes(key, 16); return EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, 1); }
Чувствительная память кучи, не очищенная перед релизом, обнаруживает динамически выделенную память, содержащую уязвимые данные. Если вы не очищаете уязвимые данные, когда вы освобождаете память, Средство поиска Ошибки повышает дефект на free
функция.
Если зона памяти перераспределена, атакующий может все еще смотреть уязвимые данные в старой зоне памяти.
Прежде, чем вызвать free
, уберите уязвимые данные с помощью memset
или SecureZeroMemory
.
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <pwd.h>
void sensitiveheapnotcleared(const char * my_user) {
struct passwd* result, pwd;
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
char* buf = (char*) malloc(1024);
getpwnam_r(my_user, &pwd, buf, bufsize, &result);
free(buf);
}
В этом примере функция использует буфер паролей и освобождает память перед концом функции. Однако данные в памяти не очищены при помощи free
команда.
Одна возможная коррекция должна переписать данные, чтобы убрать уязвимую информацию. Этот пример использует memset
переписать данные с нулями.
#include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <pwd.h> #include <assert.h> #define isNull(arr) for(int i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) assert(arr[i]==0) void sensitiveheapnotcleared(const char * my_user) { struct passwd* result, pwd; long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); char* buf = (char*) malloc(1024); if (buf) { getpwnam_r(my_user, &pwd, buf, bufsize, &result); memset(buf, 0, (size_t)1024); isNull(buf); free(buf); } }
Неочищенные уязвимые данные в стеке обнаруживают статическое ЗУ, содержащее уязвимые данные. Если вы не очищаете уязвимые данные от своего стека прежде, чем выйти из функции или программы, Средство поиска Ошибки повышает дефект на последней изогнутой фигурной скобке.
Оставлять уязвимую информацию в вашем стеке, таком как пароли или информация о пользователе, предоставляет атакующему дополнительный доступ к информации после того, как ваша программа закончилась.
Прежде, чем выйти из функции или программы, уберите зоны памяти, которые содержат уязвимые данные при помощи memset
или SecureZeroMemory
.
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
void bug_sensitivestacknotcleared(const char * my_user) {
struct passwd* result, pwd;
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
char buf[1024] = "";
getpwnam_r(my_user, &pwd, buf, bufsize, &result);
}
В этом примере статический буфер заполнен информацией о пароле. Программа освобождает стековую память в конце программы. Однако данные все еще доступны из памяти.
Одна возможная коррекция должна переписать память прежде, чем выйти из функции. Этот пример использует memset
очистить данные из буферной памяти.
#include <unistd.h> #include <string.h> #include <sys/types.h> #include <pwd.h> #include <assert.h> #define isNull(arr) for(int i=0; i<(sizeof(arr)/sizeof(arr[0])); i++) assert(arr[i]==0) void corrected_sensitivestacknotcleared(const char * my_user) { struct passwd* result, pwd; long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); char buf[1024] = ""; getpwnam_r(my_user, &pwd, buf, bufsize, &result); memset(buf, 0, (size_t)1024); isNull(buf); }
Небезопасная стандартная функция шифрования обнаруживает использование функций с поврежденным или слабым криптографическим алгоритмом. Например, crypt
не повторно используемо и основан на опасном Стандарте шифрования данных (DES).
Использование поврежденного, слабого, или нестандартного алгоритма может отсоединить уязвимую информацию атакующему. Решительный хакер может получить доступ к защищенным данным с помощью различных методов.
Если слабая функция неповторно используема, когда вы используете функцию в параллельных программах, существует дополнительный риск состояния состязания.
Избегайте функций, которые используют эти алгоритмы шифрования. Вместо этого используйте повторно используемую функцию, которая использует стойкий алгоритм шифрования.
Некоторые реализации crypt
дополнительная поддержка, возможно более безопасные, алгоритмы шифрования.
crypt
#define _GNU_SOURCE
#include <pwd.h>
#include <string.h>
#include <crypt.h>
volatile int rd = 1;
const char *salt = NULL;
struct crypt_data input, output;
int verif_pwd(const char *pwd, const char *cipher_pwd, int safe)
{
int r = 0;
char *decrypted_pwd = NULL;
switch(safe)
{
case 1:
decrypted_pwd = crypt_r(pwd, cipher_pwd, &output);
break;
case 2:
decrypted_pwd = crypt_r(pwd, cipher_pwd, &output);
break;
default:
decrypted_pwd = crypt(pwd, cipher_pwd);
break;
}
r = (strcmp(cipher_pwd, decrypted_pwd) == 0);
return r;
}
В этом примере, crypt_r
и crypt
дешифруйте пароль. Однако crypt
неповторно используемо и использует небезопасный алгоритм Стандарта шифрования данных.
crypt_r
Одна возможная коррекция должна заменить crypt
с crypt_r
.
#define _GNU_SOURCE #include <pwd.h> #include <string.h> #include <crypt.h> volatile int rd = 1; const char *salt = NULL; struct crypt_data input, output; int verif_pwd(const char *pwd, const char *cipher_pwd, int safe) { int r = 0; char *decrypted_pwd = NULL; switch(safe) { case 1: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; case 2: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; default: decrypted_pwd = crypt_r(pwd, cipher_pwd, &output); break; } r = (strcmp(cipher_pwd, decrypted_pwd) == 0); return r; }
Группа: Rec. 48. Разное (MSC) |
[1] Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.
ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ-МЕЛЛОН И/ИЛИ ЕГО ИНСТИТУТА ПРОГРАММНОЙ ИНЖЕНЕРИИ СОДЕРЖАЛ, ЗДЕСЬ ПРЕДОСТАВЛЯЕТСЯ НА ОСНОВЕ "ASIS". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.
Это программное обеспечение и сопоставленная документация не были рассмотрены, ни являются подтвержденным Университетом Карнеги-Меллон или его Институтом программной инженерии.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.