Будьте осторожны при обработке конфиденциальных данных, таких как пароли, в программном коде
Будьте осторожны при обработке конфиденциальных данных, например паролей, в программном коде [1 ].
Эта проверка проверяет наличие следующих проблем:
Вектор инициализации постоянного блочного шифра.
Постоянный шифровальный ключ.
Предсказуемый вектор инициализации блочного шифра.
Предсказуемый ключ шифра.
Конфиденциальная память кучи не очищена перед выпуском.
Неочищенные конфиденциальные данные в стеке.
Небезопасная стандартная функция шифрования.
Вектор инициализации постоянного блочного шифра возникает при использовании константы для вектора инициализации (IV) во время шифрования.
Использование постоянной IV эквивалентно неиспользованию IV. Ваши зашифрованные данные уязвимы для словарных атак.
Блочные шифры разбивают данные на блоки фиксированного размера. Блочные режимы шифрования, такие как CBC (Cipher Block Chaining), защищают от словарных атак с помощью XOR-ing каждого блока с зашифрованным выходом из предыдущего блока. Для защиты первого блока эти режимы используют случайный вектор инициализации (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 (Cipher Block Chaining), защищают от словарных атак с помощью XOR-ing каждого блока с зашифрованным выходом из предыдущего блока. Для защиты первого блока эти режимы используют случайный вектор инициализации (IV). Если вы используете слабый генератор случайных чисел для вашего IV, ваши данные становятся уязвимыми для словарных атак.
Используйте сильный генератор псевдослучайных чисел (PRNG) для вектора инициализации. Например, используйте:
PRNG уровня ОС, например, /dev/random в UNIX ® илиCryptGenRandom() в ОС Windows ®
PRNG на уровне приложений, например, Advanced Encryption Standard (AES) в режиме счетчика (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) для ключа. Например:
Использование PRNG уровня ОС, например /dev/random в UNIX или CryptGenRandom() в Windows
Используйте PRNG на уровне приложений, например Advanced Encryption Standard (AES) в режиме счетчика (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);
}Чувствительная память кучи не очищается перед освобождением и обнаруживает динамически выделенную память, содержащую конфиденциальные данные. Если вы не очистите конфиденциальные данные, когда освободите память, Bug Finder поднимет дефект на 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);
}
}
Неочищенные конфиденциальные данные в стеке обнаруживают статическую память, содержащую конфиденциальные данные. Если вы не очистите конфиденциальные данные из стека перед выходом из функции или программы, Bug Finder поднимет дефект на последней фигурной скобке.
Сохранение в стеке конфиденциальной информации, например паролей или сведений о пользователе, позволяет злоумышленнику получить дополнительный доступ к этой информации после завершения программы.
Перед выходом из функции или программы удалите зоны памяти, содержащие конфиденциальные данные, с помощью 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 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.
ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.
Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.