Skip to content
SP StackPractices
intermediate By StackPractices

Secure Coding Practices — By Language and Pattern

A practical guide to secure coding practices across languages: input validation, memory safety, authentication, and defensive patterns for Python, Java, JavaScript, and Go.

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

Secure coding is the practice of writing software that is resistant to vulnerabilities and attacks. It is not a single technique but a mindset: validate every assumption, distrust all input, and design for failure. This guide covers language-specific patterns and universal defensive techniques that apply regardless of your stack.

When to Use

  • You are writing code that processes user input or sensitive data
  • You need to prevent the most common vulnerability classes
  • You are onboarding developers to a security-conscious codebase
  • You want to establish secure coding standards for your team

Input Validation

The most fundamental security control: never trust input from users, files, APIs, or databases without validation.

Whitelist Validation

Reject what you do not explicitly allow.

import re
from pydantic import BaseModel, validator

class UserRegistration(BaseModel):
    email: str
    username: str

    @validator('username')
    def username_alphanumeric(cls, v):
        if not re.match(r'^[a-zA-Z0-9_]{3,30}$', v):
            raise ValueError('Invalid username')
        return v

Type Safety

Use strong typing to prevent type confusion attacks.

// Validate API payloads with Zod
import { z } from 'zod';

const UserSchema = z.object({
  id: z.number().int().positive(),
  email: z.string().email(),
  role: z.enum(['user', 'admin']),
});

const user = UserSchema.parse(req.body);

File Upload Validation

import magic

ALLOWED_TYPES = {'image/png', 'image/jpeg', 'application/pdf'}
MAX_SIZE = 5 * 1024 * 1024  # 5 MB

def validate_upload(file):
    if file.size > MAX_SIZE:
        raise ValueError('File too large')
    detected = magic.from_buffer(file.read(1024), mime=True)
    if detected not in ALLOWED_TYPES:
        raise ValueError('Unsupported file type')

Memory Safety

Rust — Ownership and Borrowing

Rust prevents memory errors at compile time.

// Safe: ownership prevents use-after-free
fn process(data: Vec<u8>) {
    let slice = &data[0..10];
    println!("{:?}", slice);
} // data dropped here; no dangling references

// Unsafe: requires explicit unsafe block
unsafe {
    let raw = some_ptr.as_mut().unwrap();
}

Go — Bounds Checking

// Safe slice access with bounds check
func safeAccess(data []byte, index int) byte {
    if index < 0 || index >= len(data) {
        panic("index out of bounds")
    }
    return data[index]
}

Java — Avoid Deserialization of Untrusted Data

// Dangerous: ObjectInputStream with untrusted data
ObjectInputStream ois = new ObjectInputStream(untrustedInput);
Object obj = ois.readObject(); // Can execute arbitrary code

// Safer: use JSON with strict schema validation
MyClass obj = objectMapper.readValue(json, MyClass.class);

Authentication Patterns

Password Handling

import bcrypt

def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12)).decode()

def verify_password(password: str, hashed: str) -> bool:
    return bcrypt.checkpw(password.encode(), hashed.encode())

JWT Best Practices

import jwt
from datetime import datetime, timedelta

def create_token(user_id: str, secret: str) -> str:
    payload = {
        'sub': user_id,
        'iat': datetime.utcnow(),
        'exp': datetime.utcnow() + timedelta(hours=1),
        'jti': generate_unique_id()  # Prevent replay
    }
    return jwt.encode(payload, secret, algorithm='HS256')

def verify_token(token: str, secret: str) -> dict:
    return jwt.decode(token, secret, algorithms=['HS256'])

Session Management

// HttpOnly, Secure, SameSite cookies
Cookie sessionCookie = new Cookie("session", sessionId);
sessionCookie.setHttpOnly(true);
sessionCookie.setSecure(true);
sessionCookie.setAttribute("SameSite", "Strict");
sessionCookie.setMaxAge(3600); // 1 hour
response.addCookie(sessionCookie);

Defensive Patterns

Fail Securely

def withdraw(account, amount):
    if amount <= 0:
        raise ValueError("Invalid amount")
    if account.balance < amount:
        raise InsufficientFunds("Not enough balance")
    
    # Atomic operation: deduct first, then transfer
    account.balance -= amount
    transaction.record(account, amount)

Defense in Depth

┌─────────────────────────────────────────┐
│         WAF / CDN (Layer 7)             │
├─────────────────────────────────────────┤
│         API Gateway (Rate Limit)        │
├─────────────────────────────────────────┤
│         Application (Input Validation)  │
├─────────────────────────────────────────┤
│         Database (Parameterized Query)  │
├─────────────────────────────────────────┤
│         Audit Logs (Monitoring)           │
└─────────────────────────────────────────┘

Secure Defaults

  • New users have no permissions until explicitly granted
  • Features are disabled until enabled
  • Errors reveal minimal information to attackers
  • Logging is verbose for security events but never logs secrets

Language-Specific Checklist

LanguageKey RisksMitigations
PythonPickle RCE, eval/execUse JSON, avoid eval, lint with Bandit
JavaDeserialization, XXEUse Jackson safely, disable DTDs
JavaScriptPrototype pollution, XSSValidate objects, escape output
GoRace conditions, panic leaksUse race detector, recover panics
RustUnsafe blocks, unwrap abuseMinimize unsafe, use ? operator

Common Mistakes

  • Logging sensitive data — never log passwords, tokens, or PII
  • Ignoring compiler warnings — warnings often indicate security issues
  • Copy-pasting code from Stack Overflow — verify security implications
  • Using eval or equivalent — almost always unnecessary and dangerous
  • Relying solely on client-side validation — always validate server-side

FAQ

Should I write my own crypto? No. Use well-vetted libraries: libsodium, OpenSSL, Bouncy Castle, or platform-native crypto.

How do I handle secrets in environment variables? Environment variables are better than hardcoding but still visible to process dumps. Use dedicated secret managers for production.

What is the most important secure coding principle? Validate every input, fail securely, and minimize the attack surface. Complexity is the enemy of security.