Security Best Practices
Overview
Section titled “Overview”Security is critical for desktop applications. Follow these practices to keep your application secure.
Input Validation
Section titled “Input Validation”Always Validate
Section titled “Always Validate”func (s *UserService) CreateUser(email, password string) (*User, error) { // Validate email if !isValidEmail(email) { return nil, errors.New("invalid email") }
// Validate password strength if len(password) < 8 { return nil, errors.New("password too short") }
// Sanitise input email = strings.TrimSpace(email) email = html.EscapeString(email)
// Continue...}Sanitise HTML
Section titled “Sanitise HTML”import "html"
func (s *Service) SaveComment(text string) error { // Escape HTML text = html.EscapeString(text)
// Validate length if len(text) > 1000 { return errors.New("comment too long") }
return s.db.Save(text)}Authentication
Section titled “Authentication”Secure Password Storage
Section titled “Secure Password Storage”import "golang.org/x/crypto/bcrypt"
func hashPassword(password string) (string, error) { hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) return string(hash), err}
func verifyPassword(hash, password string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil}Session Management
Section titled “Session Management”type Session struct { UserID int Token string ExpiresAt time.Time}
func (a *AuthService) CreateSession(userID int) (*Session, error) { token := generateSecureToken()
session := &Session{ UserID: userID, Token: token, ExpiresAt: time.Now().Add(24 * time.Hour), }
return session, a.saveSession(session)}Data Protection
Section titled “Data Protection”Encrypt Sensitive Data
Section titled “Encrypt Sensitive Data”import "crypto/aes"import "crypto/cipher"
func encrypt(data []byte, key []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { return nil, err }
gcm, err := cipher.NewGCM(block) if err != nil { return nil, err }
nonce := make([]byte, gcm.NonceSize()) return gcm.Seal(nonce, nonce, data, nil), nil}Secure Storage
Section titled “Secure Storage”// Use OS keychain for sensitive dataimport "github.com/zalando/go-keyring"
func saveAPIKey(key string) error { return keyring.Set("myapp", "api_key", key)}
func getAPIKey() (string, error) { return keyring.Get("myapp", "api_key")}Network Security
Section titled “Network Security”Use HTTPS
Section titled “Use HTTPS”func makeAPICall(url string) (*Response, error) { // Always use HTTPS if !strings.HasPrefix(url, "https://") { return nil, errors.New("only HTTPS allowed") }
return http.Get(url)}Verify Certificates
Section titled “Verify Certificates”import "crypto/tls"
func secureClient() *http.Client { return &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ MinVersion: tls.VersionTLS12, }, }, }}File Operations
Section titled “File Operations”Validate Paths
Section titled “Validate Paths”func readFile(path string) ([]byte, error) { // Prevent path traversal if strings.Contains(path, "..") { return nil, errors.New("invalid path") }
// Check file exists in allowed directory absPath, err := filepath.Abs(path) if err != nil { return nil, err }
if !strings.HasPrefix(absPath, allowedDir) { return nil, errors.New("access denied") }
return os.ReadFile(absPath)}Rate Limiting
Section titled “Rate Limiting”type RateLimiter struct { requests map[string][]time.Time mu sync.Mutex limit int window time.Duration}
func (r *RateLimiter) Allow(key string) bool { r.mu.Lock() defer r.mu.Unlock()
now := time.Now()
// Clean old requests var recent []time.Time for _, t := range r.requests[key] { if now.Sub(t) < r.window { recent = append(recent, t) } }
if len(recent) >= r.limit { return false }
r.requests[key] = append(recent, now) return true}Best Practices
Section titled “Best Practices”- Validate all input
- Use HTTPS for network calls
- Encrypt sensitive data
- Use secure password hashing
- Implement rate limiting
- Keep dependencies updated
- Log security events
- Use OS keychains
❌ Don’t
Section titled “❌ Don’t”- Don’t trust user input
- Don’t store passwords in plain text
- Don’t hardcode secrets
- Don’t skip certificate verification
- Don’t expose sensitive data in logs
- Don’t use weak encryption
- Don’t ignore security updates
Security Checklist
Section titled “Security Checklist”- All user input validated
- Passwords hashed with bcrypt
- Sensitive data encrypted
- HTTPS used for all network calls
- Rate limiting implemented
- File paths validated
- Dependencies up to date
- Security logging enabled
- Error messages don’t leak info
- Code reviewed for vulnerabilities
Next Steps
Section titled “Next Steps”- Architecture - Application architecture patterns
- Best Practices - Bindings best practices