SecureValue API
Тип SecureValue используется для безопасного хранения конфиденциальных данных, обеспечивает блокировку памяти, автоматическую очистку и маскирование.
Потокобезопасность
Все методы SecureValue потокобезопасны и могут параллельно вызываться из нескольких goroutine:
- Методы чтения (
String(),Bytes(),Length(),Masked()) используют блокировку чтения, поддерживают параллельное чтение - Методы закрытия (
Close(),Release()) используют блокировку записи, обеспечивая безопасное обнуление - Проверка состояния (
IsClosed(),IsMemoryLocked()) использует атомарные операции
secret := env.GetSecure("API_KEY")
if secret != nil {
defer secret.Release()
// Параллельное чтение безопасно
go func() { fmt.Println(secret.Masked()) }()
go func() { fmt.Println(secret.Length()) }()
}Внимание
Close() и Release() следует вызывать только один раз. Повторные вызовы безопасны, но не дают эффекта.
Создание
NewSecureValue
func NewSecureValue(value string) *SecureValueСоздаёт обёртку безопасного значения.
Параметры:
value- Защищаемое строковое значение
Возвращает:
*SecureValue- Объект безопасного значения
Поведение:
- Использует пул объектов для уменьшения выделения памяти
- Устанавливает финализатор GC для автоматического обнуления
- Если блокировка памяти включена, пытается заблокировать память (при неудаче тихо игнорируется)
secret := env.NewSecureValue("my-secret-password")
defer secret.Release() // или Close()NewSecureValueStrict
func NewSecureValueStrict(value string) (*SecureValue, error)Создаёт безопасное значение, возвращает ошибку если блокировка памяти не удалась.
Параметры:
value- Защищаемое строковое значение
Возвращает:
*SecureValue- Объект безопасного значенияerror- Ошибка блокировки памяти (только строгий режим)
env.SetMemoryLockEnabled(true)
env.SetMemoryLockStrict(true)
secret, err := env.NewSecureValueStrict("my-secret")
if err != nil {
// Неудачная блокировка памяти
log.Printf("Warning: %v", err)
}
if secret != nil {
defer secret.Release()
}GetSecure (Метод Loader)
func (l *Loader) GetSecure(key string) *SecureValueПолучает безопасное значение из загрузчика.
Параметры:
key- Имя ключа
Возвращает:
*SecureValue- Защитная копия безопасного значения; вызывающий ответственен за освобождение; nil если ключ не существует или загрузчик закрыт
secret := loader.GetSecure("API_KEY")
if secret != nil {
defer secret.Release()
// Использование secret
}Защитная копия
GetSecure возвращает копию исходного значения, независимую от родительского Loader. Вызывающий ответственен за вызов Release() или Close() для освобождения.
Методы
String
func (sv *SecureValue) String() stringВозвращает маскированное представление, безопасное для логов и форматирования. Реализует интерфейс fmt.Stringer, предотвращая случайную утечку ключей через fmt.Printf, log.Println или обёртку ошибок.
Возвращает:
string- Маскированное представление (например,[SECURE:32 bytes]); nil возвращает[NIL]
secret := env.GetSecure("PASSWORD")
if secret != nil {
log.Printf("Password: %s", secret) // Безопасно, выводит маскированное представление
// Эквивалентно log.Printf("Password: %s", secret.Masked())
}Внимание
String() возвращает маскированное представление, а не открытое значение. Для получения открытого значения используйте Reveal().
Reveal
func (sv *SecureValue) Reveal() stringВозвращает открытое значение. Вызывающий ответственен за безопасную обработку возвращённой строки — избегайте логирования, сериализации или сохранения в постоянное хранилище. Используйте только когда необходимо фактическое значение для криптографических операций, вызовов API или аналогичной безопасной обработки.
Возвращает:
string- Открытое значение; закрыто или nil возвращает пустую строку
secret := env.GetSecure("API_KEY")
if secret != nil {
defer secret.Release()
plaintext := secret.Reveal() // Получение открытого значения
// Использование plaintext для вызовов API и подобных безопасных операций
_ = plaintext
}Предупреждение безопасности
Reveal() возвращает строку в открытом виде. Строки Go неизменяемы и не могут быть очищены вручную. Используйте только при необходимости и избегайте логирования или хранения возвращённого значения.
Bytes
func (sv *SecureValue) Bytes() []byteВозвращает копию байтового среза значения. Вызывающий ответственен за очистку с помощью ClearBytes.
Возвращает:
[]byte- Байтовая копия значения; nil если закрыт
secret := env.GetSecure("API_KEY")
if secret != nil {
data := secret.Bytes()
defer env.ClearBytes(data) // Обнуление после использования
// Использование data
}Length
func (sv *SecureValue) Length() intВозвращает длину значения без раскрытия содержимого.
Возвращает:
int- Длина значения; 0 если закрыт
secret := env.GetSecure("API_KEY")
if secret != nil {
fmt.Printf("API Key length: %d\n", secret.Length())
}Masked
func (sv *SecureValue) Masked() stringВозвращает маскированное значение для вывода в лог.
Возвращает:
string- Маскированное представление
Формат вывода:
- Закрыто:
[CLOSED] - Пустое значение:
[SECURE:0 bytes] - Нормально:
[SECURE:N bytes]или[SECURE:N bytes locked]или[SECURE:N bytes lock-failed]или[SECURE:N bytes unlocked]
secret := env.GetSecure("API_KEY")
if secret != nil {
log.Printf("API Key: %s", secret.Masked())
// Вывод: API Key: [SECURE:32 bytes]
// Примечание: суффикс " locked" добавляется к маске только если включена
// блокировка памяти (SetMemoryLockEnabled(true)) и блокировка успешна
// (также возможны " lock-failed" и " unlocked").
}Close
func (sv *SecureValue) Close() errorБезопасно очищает память и закрывает объект.
Возвращает:
error- Всегда возвращает nil
Поведение:
- Безопасно обнуляет внутренние данные
- Помечает как закрытый
- Не возвращает в пул объектов
secret := env.GetSecure("TOKEN")
if secret != nil {
defer secret.Close()
// После Close память обнулена
}Release
func (sv *SecureValue) Release()Обнуляет память и возвращает в пул объектов.
Поведение:
- Безопасно обнуляет внутренние данные
- Удаляет финализатор GC
- Возвращает в пул объектов для повторного использования
secret := env.GetSecure("KEY")
if secret != nil {
defer secret.Release()
// После Release память обнулена и объект возвращён в пул
}Close vs Release
Close()- Только обнуляет, не возвращает в пулRelease()- Обнуляет и возвращает в пул (рекомендуется для высокочастотных сценариев)
IsClosed
func (sv *SecureValue) IsClosed() boolПроверяет, закрыт ли объект.
Возвращает:
bool- Закрыт ли
if secret.IsClosed() {
// Объект закрыт, не может использоваться
}IsMemoryLocked
func (sv *SecureValue) IsMemoryLocked() boolПроверяет, заблокирована ли память (предотвращение подкачки на диск).
Возвращает:
bool- Заблокирована ли
if secret.IsMemoryLocked() {
fmt.Println("Memory is locked, protected from swapping")
}MemoryLockError
func (sv *SecureValue) MemoryLockError() errorВозвращает ошибку попытки блокировки памяти (если есть).
Возвращает:
error- Ошибка блокировки; nil при успехе или если попытка не производилась
if err := secret.MemoryLockError(); err != nil {
log.Printf("Memory lock failed: %v", err)
}Конфигурация блокировки памяти
SetMemoryLockEnabled
func SetMemoryLockEnabled(enabled bool)Глобальное включение/выключение блокировки памяти. Влияет на все новые создаваемые SecureValue.
Параметры:
enabled- Включить ли
package main
import "github.com/cybergodev/env"
func main() {
// Включение при запуске приложения
env.SetMemoryLockEnabled(true)
// Все последующие SecureValue будут пытаться заблокировать
}IsMemoryLockEnabled
func IsMemoryLockEnabled() boolПроверяет, включена ли блокировка памяти.
Возвращает:
bool- Включена ли
if env.IsMemoryLockEnabled() {
// Блокировка памяти включена
}SetMemoryLockStrict
func SetMemoryLockStrict(strict bool)Устанавливает строгий режим. При включении NewSecureValueStrict возвращает ошибку при неудачной блокировке.
Параметры:
strict- Включить ли строгий режим
env.SetMemoryLockEnabled(true)
env.SetMemoryLockStrict(true)
secret, err := env.NewSecureValueStrict("sensitive-data")
if err != nil {
// Блокировка не удалась
}IsMemoryLockStrict
func IsMemoryLockStrict() boolПроверяет, включён ли строгий режим.
Возвращает:
bool- Включён ли
strict := env.IsMemoryLockStrict()IsMemoryLockSupported
func IsMemoryLockSupported() boolПроверяет, поддерживает ли текущая платформа блокировку памяти.
Возвращает:
bool- Поддерживается ли
| Платформа | Поддержка |
|---|---|
| Linux | Да |
| macOS | Да |
| Windows | Да |
| FreeBSD | Да |
| wasm | Нет |
Внимание
Возвращение true означает только поддержку платформой, но не наличие достаточных прав у процесса. Linux требует CAP_IPC_LOCK или права root.
if env.IsMemoryLockSupported() {
env.SetMemoryLockEnabled(true)
}Функции инструментов безопасности
ClearBytes
func ClearBytes(b []byte)Безопасно обнуляет байтовый срез. Используйте для немедленного обнуления конфиденциальных данных после использования.
Параметры:
b- Байтовый срез для обнуления
sensitive := []byte("secret-data")
// Использование...
env.ClearBytes(sensitive)
// sensitive теперь содержит нулиIsSensitiveKey
func IsSensitiveKey(key string) boolПроверяет, соответствует ли ключ шаблону конфиденциальности.
Параметры:
key- Имя ключа
Возвращает:
bool- Является ли конфиденциальным
if env.IsSensitiveKey("DB_PASSWORD") {
// Конфиденциальный ключ, используйте безопасный метод обработки
secret := env.GetSecure("DB_PASSWORD")
if secret != nil {
defer secret.Release()
}
}Шаблоны конфиденциальности: password, secret, token, key, api_key, credential и др.
MaskValue
func MaskValue(key, value string) stringВозвращает маскированное значение в зависимости от чувствительности ключа.
Параметры:
key- Имя ключаvalue- Исходное значение
Возвращает:
string- Маскированное значение
// Конфиденциальный ключ — возвращает формат [MASKED:N chars]
masked := env.MaskValue("API_KEY", "secret123")
// Возвращает: [MASKED:9 chars]
// Неконфиденциальный ключ — возвращает исходное значение (обрезается свыше 20 символов)
masked := env.MaskValue("APP_NAME", "myapp")
// Возвращает: myappMaskKey
func MaskKey(key string) stringМаскирует имя ключа для логирования.
Параметры:
key- Имя ключа
Возвращает:
string- Маскированное имя ключа
masked := env.MaskKey("DB_PASSWORD")
// Возвращает: DB***SanitizeForLog
func SanitizeForLog(s string) stringОчищает строку от конфиденциальных пар ключ-значение. Автоматически обнаруживает и маскирует конфиденциальные значения в формате key=value.
Параметры:
s- Исходная строка
Возвращает:
string- Очищенная строка
// Автоматическое маскирование конфиденциальных пар ключ-значение
msg := "Connected with password=secret123 api_key=abc123"
clean := env.SanitizeForLog(msg)
// Возвращает: "Connected with password=[MASKED] api_key=[MASKED]"MaskSensitiveInString
func MaskSensitiveInString(s string) stringМаскирует потенциально конфиденциальное содержимое в строке. Обрезает строки длиннее 50 символов.
Параметры:
s- Исходная строка
Возвращает:
string- Маскированная строка
// Длинные строки будут усечены (сохраняются первые 47 символов и добавляется "...")
long := "This is a very long string that exceeds 50 characters"
clean := env.MaskSensitiveInString(long)
// Возвращает: "This is a very long string that exceeds 50 char..."Сценарии использования
Используется для усечения длинных строк, которые могут содержать конфиденциальные данные. Для автоматического маскирования конфиденциальных пар ключ-значение используйте SanitizeForLog.
Полный пример
package main
import (
"fmt"
"log"
"github.com/cybergodev/env"
)
func main() {
// Проверка и включение блокировки памяти
if env.IsMemoryLockSupported() {
env.SetMemoryLockEnabled(true)
fmt.Println("Memory locking enabled")
}
// Загрузка переменных окружения
if err := env.Load(".env"); err != nil {
log.Printf("Warning: %v", err)
}
// Безопасное получение конфиденциального значения
apiKey := env.GetSecure("API_KEY")
if apiKey == nil {
log.Fatal("API_KEY not found")
}
defer apiKey.Release()
// Безопасное использование
fmt.Printf("API Key length: %d\n", apiKey.Length())
fmt.Printf("API Key (masked): %s\n", apiKey.Masked())
// Проверка состояния блокировки памяти
if apiKey.IsMemoryLocked() {
fmt.Println("Memory is locked")
}
// Проверка ошибки блокировки
if err := apiKey.MemoryLockError(); err != nil {
fmt.Printf("Memory lock warning: %v\n", err)
}
// Передача другим функциям
connectAPI(apiKey.Reveal())
// Использование функций безопасности
logMessage := "Processing with API_KEY=secret"
safeMessage := env.SanitizeForLog(logMessage)
fmt.Println(safeMessage) // Processing with API_KEY=[MASKED]
}
func connectAPI(key string) {
// Подключение с использованием ключа...
fmt.Printf("Connecting with key of length %d\n", len(key))
}Внутренняя реализация
Пул объектов
SecureValue использует sync.Pool для уменьшения выделения памяти:
var secureValuePool = sync.Pool{
New: func() interface{} {
return &SecureValue{}
},
}Финализатор GC
При создании устанавливается финализатор GC, обеспечивающий автоматическое обнуление при сборке мусора:
runtime.SetFinalizer(sv, (*SecureValue).finalize)Безопасная очистка
Использует unsafe.Pointer для предотвращения оптимизации компилятора:
func (sv *SecureValue) clearData() {
dataPtr := unsafe.Pointer(&sv.data[0])
for i := range sv.data {
*(*byte)(unsafe.Pointer(uintptr(dataPtr) + uintptr(i))) = 0
}
runtime.KeepAlive(sv.data)
sv.data = nil
}Связанная документация
- Константы и ошибки - Запрещённые ключи, шаблоны конфиденциальных ключей, типы ошибок
- Обзор безопасности - Архитектура безопасности и основные функции
- Контрольный список для производства - Проверка безопасности перед развёртыванием
- Loader API - Метод GetSecure