Это может быть лучше подходит для security.stackexchange.com, но мне интересно, в частности, PHP.
Я работаю с openssl в приложении и замечаю свободные операции для ресурсов openssl. Это вполне может быть просто общий выпуск памяти, но, учитывая криптографический характер, он может рассматриваться как особый случай.
AFAIK внутри прикладной области нет никакого способа гарантировать, что переменная удалена из памяти. Однако, в Zend land, очищают ли расширения C известные конфиденциальные данные или просто освобождают память? Есть ли openssl_pkey_free
освободить память надежно? Как я могу сделать заявление о том, что он был выпущен надежно, чтобы применить его к другим расширениям, которые могут быть мне интересны в будущем?
Я не аналитик по безопасности, поэтому мое определение безопасности довольно расплывчато.
Прежде чем я посмотрю, мой ответ: так как PHP динамический язык, вы должны предположим, что это не очищено пока не доказано обратное (например, с волатильностью). По словам бывшего офицера безопасности FreeBSD Колина Персиваля, «Обнуление буферов недостаточно» — так что это может даже не иметь значения.
Но это невероятно скучный ответ. Что под капотом?
openssl_pkey_free()
определяется PHP в внутр / OpenSSL / openssl.c # 545:
void EVP_PKEY_free(EVP_PKEY *x)
{
int i;
if (x == NULL)
return;
i = CRYPTO_add(&x->references, -1, CRYPTO_LOCK_EVP_PKEY);
#ifdef REF_PRINT
REF_PRINT("EVP_PKEY", x);
#endif
if (i > 0)
return;
#ifdef REF_CHECK
if (i < 0) {
fprintf(stderr, "EVP_PKEY_free, bad reference count\n");
abort();
}
#endif
EVP_PKEY_free_it(x);
if (x->attributes)
sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
OPENSSL_free(x);
}
static void EVP_PKEY_free_it(EVP_PKEY *x)
{
if (x->ameth && x->ameth->pkey_free) {
x->ameth->pkey_free(x);
x->pkey.ptr = NULL;
}
#ifndef OPENSSL_NO_ENGINE
if (x->engine) {
ENGINE_finish(x->engine);
x->engine = NULL;
}
#endif
}
Как видите, он вызывает функцию под названием EVP_PKEY_free()
, который определяется openssl в /crypto/evp/p_lib.c#L376:
void EVP_PKEY_free(EVP_PKEY *x)
{
int i;
if (x == NULL)
return;
i = CRYPTO_add(&x->references, -1, CRYPTO_LOCK_EVP_PKEY);
#ifdef REF_PRINT
REF_PRINT("EVP_PKEY", x);
#endif
if (i > 0)
return;
#ifdef REF_CHECK
if (i < 0) {
fprintf(stderr, "EVP_PKEY_free, bad reference count\n");
abort();
}
#endif
EVP_PKEY_free_it(x);
if (x->attributes)
sk_X509_ATTRIBUTE_pop_free(x->attributes, X509_ATTRIBUTE_free);
OPENSSL_free(x);
}
Он делает некоторые проверки вменяемости, а затем вызывает OPENSSL_free()
что просто псевдоним за CRYPTO_free()
,
В заключение, CRYPTO_free()
определено Вот:
void CRYPTO_free(void *str)
{
if (free_debug_func != NULL)
free_debug_func(str, 0);
#ifdef LEVITTE_DEBUG_MEM
fprintf(stderr, "LEVITTE_DEBUG_MEM: < 0x%p\n", str);
#endif
free_func(str);
if (free_debug_func != NULL)
free_debug_func(NULL, 1);
}
Кажется, просто позвонить free_func()
в типичном случае, который является указателем на free()
, Ни в одной из этих операций я не видел попыток обнуления памяти.
Если вы можете установить расширения PECL, libsodium предложения \Sodium\memzero()
в дополнение к утилиты безопасного выделения памяти.
Пожалуйста, помните, что обнуление памяти — это стратегия смягчения последствий, когда происходит компромисс. Если ваш PHP-код может прочитать закрытый ключ с диска (или из базы данных), злоумышленник, вероятно, сможет воспроизвести код и украсть ключ напрямую. Способ защиты от этого — хранить ваши ключи в аппаратный модуль безопасности и никогда не трогай это напрямую.
Других решений пока нет …