explicit_bzero
explicit_bzero
是一個為了解決 memset
在安全清除內存場景中可能被優化器移除的問題而設計的函數,廣泛用于安全編程中,比如密碼、密鑰清除等。
Introduce
頭文件
#include <string.h>
函數原型
void explicit_bzero(void *s, size_t n);
功能說明
將內存區域 s
開始的 n
個字節強制清零(寫入 0
),確保不會被編譯器優化掉。
為什么不能用 memset
?
當你寫:
char key[32];
// ... 使用 key ...
memset(key, 0, sizeof(key));
有些編譯器會發現 key
后面就不再使用,于是優化器會移除 memset 調用,導致密碼/密鑰未被真正擦除,造成信息泄露風險。
explicit_bzero
的實現避免了這一問題:
- 使用
volatile
指針或編譯器 barrier; - 或直接調用外部函數(編譯器無法內聯);
- 保證操作不可優化,滿足安全清除需求。
可用平臺
平臺 | 是否支持 explicit_bzero |
---|---|
? FreeBSD | 原生支持 |
? OpenBSD | 原生支持(首發平臺) |
? glibc >= 2.25(2017) | 支持 |
? macOS 10.12+ | 可用 |
🚫 Windows | 不支持(用 SecureZeroMemory ) |
用法示例
#include <string.h>int main() {char secret[32] = "TopSecretPassword123!";// 使用 secret 做某些操作...// 清除 secret(防止泄露)explicit_bzero(secret, sizeof(secret));return 0;
}
📌 即使 secret
后續沒有再用,這個清除也不會被優化掉!
與 bzero
區別?
函數 | 是否會被優化器移除 | 是否已廢棄 | 推薦使用 |
---|---|---|---|
memset | ? 有風險 | 否 | ? 不用于清除敏感數據 |
bzero | ? 有風險 | ? 已廢棄(非標準) | ? |
explicit_bzero | ? 安全 | 否 | ? ? ? |
Windows 等平臺
Windows 沒有 explicit_bzero
,可以用:
#include <windows.h>
SecureZeroMemory(ptr, size);
或者自己寫:
void secure_memzero(void* p, size_t len) {volatile unsigned char* vp = (volatile unsigned char*)p;while (len--) {*vp++ = 0;}
}
跨平臺、安全、可靠的 explicit_bzero
封裝實現
- Linux(glibc >= 2.25)使用系統
explicit_bzero
- macOS 使用
explicit_bzero
或bzero
- Windows 使用
SecureZeroMemory
- 其他平臺使用手動
volatile
寫法
跨平臺安全內存清除封裝
#pragma once#include <cstddef> // for size_t#if defined(_WIN32)#include <windows.h>
#elif defined(__has_include)#if __has_include(<string.h>)#include <string.h>#endif
#endifnamespace secure {// 可移植 secure_memzero 封裝
inline void memzero(void* ptr, size_t len) {if (!ptr || len == 0) return;#if defined(_WIN32)// Windows 安全 APISecureZeroMemory(ptr, len);#elif defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))// glibc 2.25+ 提供 explicit_bzeroexplicit_bzero(ptr, len);#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)// macOS / BSD 系統一般也有 explicit_bzeroexplicit_bzero(ptr, len);#else// 手動 volatile 寫法,防止優化器移除volatile unsigned char* p = reinterpret_cast<volatile unsigned char*>(ptr);while (len--) {*p++ = 0;}
#endif
}} // namespace secure
使用方式
#include "secure_memzero.hpp"int main() {char password[32] = "MySecretPassword";// ... 使用 password ...// 安全清除secure::memzero(password, sizeof(password));return 0;
}
測試建議
- Release 模式下測試,確保
secure::memzero
不被優化掉。 - 檢查編譯器匯編輸出(例如
objdump -d
)確保有寫入指令。 - 如在密碼模塊中使用,建議配合內存保護機制(如
mlock
)以防 swap 泄露。
優點
特性 | 描述 |
---|---|
安全 | 防止編譯器優化清零操作 |
跨平臺 | 兼容 Linux/macOS/Windows/FreeBSD 等系統 |
無依賴 | 不依賴 C11 memset_s |
可內聯 | 單頭文件,適用于庫內/項目中任意使用 |
總結
特性 | 說明 |
---|---|
安全 | 不會被編譯器優化 |
用途 | 清除密碼、私鑰等敏感數據 |
可移植性 | glibc 2.25+、BSD、macOS 支持,Windows 需替代方案 |
推薦場景 | 密碼學、加密庫、認證信息清除等 |