Security-First Development - Building Secure Applications from the Ground Up
by Thomas Carman
Making Security a Priority, Not an Afterthought
In today’s threat landscape, security can’t be bolted on at the end—it must be built into every layer of your application. Here’s what I’ve learned about building secure software from my recent projects.
The Security Mindset
Assume Breach
- Design with the assumption that attackers will get in
- Implement defense in depth
- Limit blast radius of potential breaches
- Have incident response plans ready
Trust Nothing
- Validate all inputs
- Verify all outputs
- Authenticate everything
- Authorize every action
OWASP Top 10 in Practice
1. Injection Attacks
Prevention Strategies:
// Always use parameterized queries
// Never concatenate user input into SQL
// Use ORM with proper escaping
// Input validation
function sanitizeInput(input) {
// Whitelist approach - only allow expected characters
// Use libraries like DOMPurify for HTML
// Validate against schema
}
Tools Used:
- Static analysis with CodeQL
- Dynamic testing with SQLMap
- Input fuzzing
2. Authentication & Session Management
Robust Authentication:
- Bcrypt for password hashing (minimum 12 rounds)
- Multi-factor authentication (MFA)
- Account lockout after failed attempts
- Password complexity requirements
- Breach password detection
Session Security:
// Secure session configuration
{
httpOnly: true, // Prevent XSS access
secure: true, // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: 3600000, // 1 hour
rolling: true // Refresh on activity
}
JWT Best Practices:
- Short expiration times (15 minutes)
- Refresh token rotation
- Token blacklisting for logout
- Never store sensitive data in payload
3. Cross-Site Scripting (XSS)
Defense Layers:
- Input Validation: Whitelist acceptable characters
- Output Encoding: Context-aware escaping
- Content Security Policy: Restrict resource loading
- HTTPOnly Cookies: Prevent JS access to tokens
CSP Implementation:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{random}';
style-src 'self' 'unsafe-inline';
img-src 'self' https://trusted-cdn.com;
4. Sensitive Data Exposure
Encryption Strategy:
- TLS 1.3 for all communications
- AES-256 for data at rest
- Separate encryption keys per environment
- Regular key rotation
- Hardware Security Modules (HSM) for key storage
Secrets Management:
- Never commit secrets to git
- Use environment variables or secret managers
- Rotate credentials regularly
- Audit secret access
API Security
Authentication:
- API keys for service-to-service
- OAuth 2.0 for user-to-service
- JWT for stateless auth
- Mutual TLS for high-security APIs
Rate Limiting:
// Prevent abuse and DoS
- Per-user limits: 100 requests/minute
- Per-IP limits: 1000 requests/minute
- Exponential backoff for repeated violations
- Different limits per endpoint criticality
Input Validation:
// Schema validation for all inputs
const schema = {
email: "email",
age: "integer|min:0|max:150",
role: "in:user,admin,moderator",
};
Database Security
Access Control:
- Principle of least privilege
- Separate read/write users
- Application-specific database users
- No shared credentials
Encryption:
- Transparent Data Encryption (TDE)
- Column-level encryption for PII
- Encrypted backups
- Secure key management
Audit Logging:
- Log all data access
- Track modification history
- Regular audit reviews
- Immutable audit logs
Infrastructure Security
Container Security:
- Minimal base images (distroless when possible)
- No secrets in images
- Regular vulnerability scanning
- Non-root user execution
- Read-only file systems
Network Security:
- Zero-trust networking
- Service mesh for mTLS
- Network segmentation
- WAF for public endpoints
Cloud Security:
- IAM with least privilege
- Resource tagging for governance
- Automated compliance checking
- Regular security audits
Supply Chain Security
Dependency Management:
# Regular scanning
npm audit fix
# or
snyk test
# Lock file integrity
npm ci --ignore-scripts
# Verify package signatures
npm verify
Best Practices:
- Pin dependency versions
- Review dependency updates
- Use private npm registry
- Scan for known vulnerabilities
- Monitor for typosquatting
GitHub Actions Security:
- Pin actions to commit SHA
- Use separate tokens per action
- Minimize permissions
- Regular audit of workflows
Security Testing
Automated Testing:
- SAST (Static): CodeQL, SonarQube
- DAST (Dynamic): OWASP ZAP, Burp Suite
- SCA (Dependencies): Snyk, Dependabot
- Container Scanning: Trivy, Clair
Manual Testing:
- Penetration testing annually
- Code reviews with security focus
- Threat modeling for new features
- Red team exercises
Monitoring & Incident Response
Security Monitoring:
- Failed authentication attempts
- Unusual access patterns
- Privilege escalation attempts
- Data exfiltration indicators
Alerting:
// Alert on suspicious patterns
- Multiple failed logins
- Access from unusual locations
- Bulk data downloads
- Admin action outside business hours
Incident Response Plan:
- Detect: Automated monitoring
- Contain: Isolate affected systems
- Eradicate: Remove threat
- Recover: Restore normal operations
- Learn: Post-mortem analysis
Compliance & Privacy
GDPR Considerations:
- Data minimization
- Right to deletion
- Data portability
- Consent management
- Privacy by design
Implementation:
- User data export functionality
- Automated data deletion
- Audit trails
- Privacy policy enforcement
Secure Development Lifecycle
Phase 1: Requirements
- Identify security requirements
- Threat modeling
- Privacy impact assessment
Phase 2: Design
- Security architecture review
- Third-party security assessment
- Data flow diagrams
Phase 3: Implementation
- Security code reviews
- Static analysis in CI/CD
- Secure coding guidelines
Phase 4: Testing
- Security test cases
- Penetration testing
- Vulnerability scanning
Phase 5: Deployment
- Security hardening
- Configuration review
- Secrets management
Phase 6: Maintenance
- Regular updates
- Vulnerability patching
- Security monitoring
Real-World Security Wins
Case 1: Preventing SQL Injection
- Migrated from string concatenation to parameterized queries
- Implemented input validation
- Added WAF rules
- Result: Zero SQL injection vulnerabilities
Case 2: Securing API Keys
- Moved from hardcoded keys to secret manager
- Implemented key rotation
- Added access logging
- Automated key expiration
Case 3: XSS Protection
- Implemented CSP headers
- Added output encoding
- Regular security audits
- Developer security training
Common Security Mistakes
❌ Trusting client-side validation
❌ Rolling your own crypto
❌ Storing passwords in plain text
❌ Ignoring security headers
❌ Not updating dependencies
❌ Exposing stack traces in production
❌ Using default credentials
❌ Insufficient logging
Security Tools in My Arsenal
Development:
- Git-secrets for commit scanning
- Pre-commit hooks for security checks
- IDE security plugins
CI/CD:
- CodeQL for semantic code analysis
- Trivy for container scanning
- OWASP Dependency-Check
Production:
- WAF (Web Application Firewall)
- IDS/IPS (Intrusion Detection/Prevention)
- SIEM (Security Information and Event Management)
Continuous Improvement
Stay Updated:
- Follow security advisories
- Subscribe to CVE feeds
- Attend security conferences
- Participate in CTF competitions
Team Training:
- Regular security workshops
- Secure coding training
- Incident response drills
- Security champions program
The Bottom Line
Security is everyone’s responsibility. It requires:
- Constant vigilance
- Regular training
- Automated tooling
- Cultural commitment
The cost of a breach far exceeds the investment in security. Build it in from day one, and sleep better at night.
Results
Security metrics after 6 months:
- Zero critical vulnerabilities in production
- 100% security scan coverage in CI/CD
- 99% patch compliance within 7 days
- Zero security incidents
- Successful pen test results
Security is a journey, not a destination. What security practices have you found most effective?