/

Data Masking

Data masking ensures sensitive information like passwords, tokens, and personal data are never logged. ByteHide Logger provides mechanisms to automatically mask specified sensitive keys.

Sensitive Data Types

Common sensitive data that should be masked:

  • Authentication: passwords, tokens, session IDs, API keys, JWT
  • Personal: email addresses, phone numbers, SSN, driver's license
  • Payment: credit card numbers, bank accounts, CVV codes
  • Medical: health records, diagnoses, prescriptions
  • Business: trade secrets, proprietary algorithms, customer lists

Adding Sensitive Keys

Use AddSensitiveKey() to register keys that should always be masked:

Go
import "github.com/bytehide/bytehide-logs-go"

// Configure at application startup
func init() {
    // Authentication
    logs.AddSensitiveKey("password")
    logs.AddSensitiveKey("token")
    logs.AddSensitiveKey("apiKey")
    logs.AddSensitiveKey("authToken")
    logs.AddSensitiveKey("sessionId")
    logs.AddSensitiveKey("refreshToken")
    
    // Personal data
    logs.AddSensitiveKey("email")
    logs.AddSensitiveKey("phoneNumber")
    logs.AddSensitiveKey("ssn")
    logs.AddSensitiveKey("driverLicense")
    
    // Payment
    logs.AddSensitiveKey("creditCard")
    logs.AddSensitiveKey("cardNumber")
    logs.AddSensitiveKey("cvv")
    logs.AddSensitiveKey("bankAccount")
    
    // Other
    logs.AddSensitiveKey("secretKey")
    logs.AddSensitiveKey("privateKey")
    logs.AddSensitiveKey("apiSecret")
}

Basic Masking Examples

When context values have sensitive keys, they are automatically masked:

Go
import "github.com/bytehide/bytehide-logs-go"

// Sensitive value is masked
logs.WithContext("email", "john@example.com").
    Info("User logged in")
// Logged as: User logged in {email: ****}

// Sensitive value is masked
logs.WithContext("creditCard", "4532-1234-5678-9012").
    WithContext("amount", 99.99).
    Info("Payment processed")
// Logged as: Payment processed {creditCard: ****, amount: 99.99}

// Multiple sensitive values
logs.WithContext("username", "john_doe").
    WithContext("password", "SecurePass123").
    WithContext("token", "eyJhbGc...").
    Warn("Authentication failed")
// Logged as: Authentication failed {username: john_doe, password: ****, token: ****}

Configuration Examples

Startup Configuration

Go
func init() {
    // Register common sensitive patterns
    setupSensitiveKeyConfiguration()
}

func setupSensitiveKeyConfiguration() {
    // User authentication
    logs.AddSensitiveKey("password")
    logs.AddSensitiveKey("pwd")
    logs.AddSensitiveKey("passwd")
    
    // Tokens and keys
    logs.AddSensitiveKey("token")
    logs.AddSensitiveKey("apiKey")
    logs.AddSensitiveKey("api_key")
    logs.AddSensitiveKey("secretKey")
    logs.AddSensitiveKey("secret")
    logs.AddSensitiveKey("jwt")
    logs.AddSensitiveKey("bearer")
    logs.AddSensitiveKey("authorization")
    
    // Personal identifiable information (PII)
    logs.AddSensitiveKey("email")
    logs.AddSensitiveKey("phoneNumber")
    logs.AddSensitiveKey("phone")
    logs.AddSensitiveKey("ssn")
    logs.AddSensitiveKey("socialSecurityNumber")
    logs.AddSensitiveKey("driverLicense")
    logs.AddSensitiveKey("passport")
    
    // Payment information
    logs.AddSensitiveKey("creditCard")
    logs.AddSensitiveKey("cardNumber")
    logs.AddSensitiveKey("cvv")
    logs.AddSensitiveKey("bankAccount")
    logs.AddSensitiveKey("routingNumber")
}

Practical Patterns

User Authentication

Go
type AuthService struct {
    userRepo UserRepository
}

func (s *AuthService) Authenticate(email, password string) (*User, error) {
    logs.WithContext("email", email).
        Debug("Attempting user authentication")
    // Logged as: {email: ****}
    
    user, err := s.userRepo.GetByEmail(email)
    if err != nil {
        logs.WithContext("email", email).
            WithContext("error", err.Error()).
            Warn("User not found")
        return nil, fmt.Errorf("authentication failed")
    }
    
    // Verify password
    if !verifyPassword(password, user.PasswordHash) {
        logs.WithContext("email", email).
            Warn("Invalid password")
        return nil, fmt.Errorf("authentication failed")
    }
    
    logs.WithContext("email", email).
        WithContext("userId", user.ID).
        Info("User authenticated successfully")
    
    return user, nil
}

API Key Management

Go
type APIKeyService struct {
    repo APIKeyRepository
}

func (s *APIKeyService) CreateAPIKey(ctx context.Context, userId string) (string, error) {
    logs.WithContext("userId", userId).
        Debug("Creating API key")
    
    apiKey := generateSecureKey()
    hashedKey := hashKey(apiKey)
    
    err := s.repo.Save(&APIKey{
        UserID:     userId,
        KeyHash:    hashedKey,
        CreatedAt:  time.Now(),
    })
    if err != nil {
        logs.WithContext("userId", userId).
            WithContext("apiKey", apiKey).
            Error("Failed to save API key", err)
        // Logged as: {userId: ..., apiKey: ****}
        return "", err
    }
    
    logs.WithContext("userId", userId).
        Info("API key created successfully")
    
    return apiKey, nil
}

func (s *APIKeyService) ValidateAPIKey(apiKey string) (string, error) {
    logs.WithContext("apiKey", apiKey).
        Trace("Validating API key")
    // Logged as: {apiKey: ****}
    
    hashedKey := hashKey(apiKey)
    
    keyRecord, err := s.repo.GetByHash(hashedKey)
    if err != nil {
        logs.WithContext("apiKey", apiKey).
            Debug("API key not found")
        return "", fmt.Errorf("invalid key")
    }
    
    if time.Now().After(keyRecord.ExpiresAt) {
        logs.WithContext("apiKey", apiKey).
            Warn("API key expired")
        return "", fmt.Errorf("key expired")
    }
    
    logs.WithContext("userId", keyRecord.UserID).
        Debug("API key validated successfully")
    
    return keyRecord.UserID, nil
}

Payment Processing

Go
type PaymentProcessor struct {
    gateway PaymentGateway
}

func (p *PaymentProcessor) ProcessPayment(ctx context.Context, payment *Payment) error {
    logs.WithContext("amount", payment.Amount).
        WithContext("currency", payment.Currency).
        WithContext("cardNumber", payment.CardNumber).
        WithContext("cardholderName", payment.CardholderName).
        Debug("Processing payment")
    // Logged as: {amount: ..., currency: ..., cardNumber: ****, cardholderName: ...}
    
    // Call payment gateway
    result, err := p.gateway.Charge(&GatewayRequest{
        Amount:       payment.Amount,
        CardToken:    payment.CardToken,
        Currency:     payment.Currency,
    })
    if err != nil {
        logs.WithContext("amount", payment.Amount).
            WithContext("cardNumber", payment.CardNumber).
            WithContext("error", err.Error()).
            Error("Payment processing failed", err)
        return err
    }
    
    logs.WithContext("amount", payment.Amount).
        WithContext("transactionId", result.ID).
        Info("Payment processed successfully")
    
    return nil
}

Configuration Management

Go
type ConfigService struct {
    store ConfigStore
}

func (s *ConfigService) SetConfig(key string, value interface{}) error {
    logs.WithContext("key", key).
        WithContext("value", value).
        Debug("Updating configuration")
    // Logged as: {key: ..., value: **** if key is sensitive}
    
    err := s.store.Set(key, value)
    if err != nil {
        logs.WithContext("key", key).
            WithContext("value", value).
            Error("Failed to update configuration", err)
        return err
    }
    
    logs.WithContext("key", key).
        Info("Configuration updated successfully")
    
    return nil
}

func (s *ConfigService) GetConfig(key string) (interface{}, error) {
    logs.WithContext("key", key).
        Trace("Retrieving configuration")
    
    value, err := s.store.Get(key)
    if err != nil {
        logs.WithContext("key", key).
            Error("Failed to retrieve configuration", err)
        return nil, err
    }
    
    logs.WithContext("key", key).
        Trace("Configuration retrieved")
    
    return value, nil
}

Data Masking Patterns

Consistent Key Naming

Go
// Use consistent naming across your application
// All password-related fields
logs.AddSensitiveKey("password")
logs.AddSensitiveKey("newPassword")
logs.AddSensitiveKey("oldPassword")
logs.AddSensitiveKey("confirmPassword")

// All token-related fields
logs.AddSensitiveKey("token")
logs.AddSensitiveKey("accessToken")
logs.AddSensitiveKey("refreshToken")
logs.AddSensitiveKey("bearerToken")

// All credential fields
logs.AddSensitiveKey("credentials")
logs.AddSensitiveKey("secret")
logs.AddSensitiveKey("key")

Best Practices

Data Masking Best Practices

  • Configure at startup - register all sensitive keys during initialization
  • Use consistent naming - standardize sensitive field names across your app
  • Be comprehensive - include all sensitive data types (auth, PII, payment, etc.)
  • Don't log sensitive data directly - always use context with registered keys
  • Review periodically - audit logs to ensure sensitive data isn't exposed
  • Team documentation - document which keys are sensitive in your codebase
  • Test masking - verify sensitive data is masked in log output

Compliance Considerations

Data masking helps meet compliance requirements like GDPR, HIPAA, and PCI-DSS. Always ensure sensitive data is masked before logs leave your system.

Next Steps

Previous
Basic Logging