How can I determine if my memory was safely released by a PHP application?

This might be better for security.stackexchange.com, but I'm particularly interested in PHP in particular.

I work with openssl in an application and notice free operations for openssl resources. This may well be just a general release of memory, but given the cryptographic nature of it, it can be considered as a special case.

AFAIK inside the application space there is no way to guarantee that a variable is deleted from memory. However, in Zend land, do C extenders clear known sensitive data or just free up memory? openssl_pkey_free safely free memory? How can I make a statement that it has been released reliably in order to apply it to other extensions that may be of interest to me in the future?

I am not a security analyst, so my definition is reliably rather vague.

+6
source share
1 answer

TL DR: Nope.

Before I even look, my answer is this: since PHP is a dynamic language, you should consider that it is not cleaned up until it is proved otherwise (for example, volatility). According to Colin Percival, a former FreeBSD security officer, β€œZero Buffers Are Not Enough,” so it might not even matter.

But this is an incredibly boring answer. What's under the hood?

What does openssl_pkey_free () do?

openssl_pkey_free() defined by PHP in ext / 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 } 

As you can see, it calls a function called EVP_PKEY_free() , which is defined by openssl in /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); } 

It performs some health checks, then calls OPENSSL_free() , which is just an alias for CRYPTO_free() .

Finally, CRYPTO_free() is defined here :

 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); } 

It seems that in a typical case, we simply call free_func() , which is a pointer to free() . Under no circumstances did I see any attempt to reset my memory in these operations.

But I really want to dump memory in PHP. How can I?!

If you can install the PECL extensions, libsodium offers \Sodium\memzero() in addition to the secure memory allocation utilities .

Remember that zeroing out memory is a mitigation strategy when compromise occurs. If your PHP code can read the private key from disk (or from the database), the attacker could probably play the code and steal the key directly. A way to protect against this is to store your keys in security hardware and never touch it directly.

+8
source

Source: https://habr.com/ru/post/984385/


All Articles