A comprehensive guide to implementing robust security patterns and practices across software development and infrastructure operations.
Security Best Practices Cheatsheet
A comprehensive guide to implementing robust security patterns and practices across software development and infrastructure operations.
Overview
Security best practices encompass a holistic approach to protecting systems, data, and users from threats through proactive measures, continuous monitoring, and rapid incident response.
graph TB
subgraph "Security Architecture"
A[Security Governance] --> B[Preventive Controls]
A --> C[Detective Controls]
A --> D[Corrective Controls]
B --> E[Access Control]
B --> F[Encryption]
B --> G[Secure Coding]
C --> H[Monitoring]
C --> I[Auditing]
C --> J[Vulnerability Scanning]
D --> K[Incident Response]
D --> L[Patch Management]
D --> M[Disaster Recovery]
end
subgraph "Defence in Depth"
N[Perimeter] --> O[Network]
O --> P[Host]
P --> Q[Application]
Q --> R[Data]
end
A --> N
Principle of Least Privilege
Key Concepts
Concept
Description
Minimal Access
Users and services receive only the permissions necessary to perform their tasks
Need-to-Know Basis
Access to information is restricted to those who require it for their role
Separation of Duties
Critical tasks are divided among multiple individuals to prevent fraud and errors
Time-Limited Access
Elevated privileges are granted temporarily and automatically revoked
Role-Based Access Control (RBAC)
Permissions are assigned based on roles rather than individual users
Common Patterns
Linux/Unix Permission Management
# View current permissions
ls-la/path/to/resource
# Set restrictive file permissions (owner read/write only)
chmod600sensitive-file.txt
# Set directory permissions (owner only)
chmod700/secure/directory
# Remove group and other access
chmodgo-rwx/path/to/resource
# Set ownership
chownappuser:appgroup/var/app/data
# Use ACLs for fine-grained control
setfacl-mu:specificuser:r/path/to/file
getfacl/path/to/file
# Role with minimal permissionsapiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:namespace:productionname:pod-readerrules:-apiGroups:[""]resources:["pods"]verbs:["get","list","watch"]---# RoleBindingapiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:read-podsnamespace:productionsubjects:-kind:ServiceAccountname:monitoring-sanamespace:productionroleRef:kind:Rolename:pod-readerapiGroup:rbac.authorization.k8s.io
Database Access Control
-- Create role with specific permissionsCREATEROLEapp_readonly;GRANTSELECTONschema_name.*TOapp_readonly;-- Create user with limited privilegesCREATEUSER'app_service'@'localhost'IDENTIFIEDBY'secure_password';GRANTSELECT,INSERTONapp_db.transactionsTO'app_service'@'localhost';-- Revoke unnecessary privilegesREVOKEALLPRIVILEGESON*.*FROM'app_service'@'localhost';-- View granted privilegesSHOWGRANTSFOR'app_service'@'localhost';
Examples
Service Account Best Practice:
# Kubernetes: Disable automounting of service account tokenapiVersion:v1kind:ServiceAccountmetadata:name:restricted-saautomountServiceAccountToken:false---# Pod using restricted service accountapiVersion:v1kind:Podmetadata:name:secure-podspec:serviceAccountName:restricted-saautomountServiceAccountToken:falsesecurityContext:runAsNonRoot:truerunAsUser:1000readOnlyRootFilesystem:true
Regular Security Audits
Key Concepts
Concept
Description
Vulnerability Assessment
Systematic review of security weaknesses in systems
Penetration Testing
Simulated attacks to identify exploitable vulnerabilities
Compliance Auditing
Verification against regulatory and policy requirements
Configuration Review
Analysis of system configurations against security baselines
Log Analysis
Review of audit trails for suspicious activities
Common Commands and Tools
System Auditing
# Linux audit system
sudoauditctl-l# List current rules
sudoausearch-kfailed_login# Search audit logs
sudoaureport--auth# Authentication report# Check for SUID/SGID files
find/-typef\(-perm-4000-o-perm-2000\)-execls-l{}\;2>/dev/null
# Find world-writable files
find/-typef-perm-002-execls-l{}\;2>/dev/null
# Check listening ports
ss-tulpn
netstat-tulpn
# Review failed login attempts
grep"Failed password"/var/log/auth.log|tail-20
lastb|head-20
# Check user accounts
awk-F:'($3 == 0) {print $1}'/etc/passwd# Find users with UID 0
cat/etc/passwd|grep-vnologin|grep-vfalse# Users with shell access
## Monthly Security Audit Checklist### Access Control- [ ] Review user accounts and remove unused accounts
- [ ] Verify service account permissions
- [ ] Check for orphaned resources
- [ ] Review API key rotation status
### Network Security- [ ] Review firewall rules
- [ ] Check security group configurations
- [ ] Verify VPN access logs
- [ ] Scan for open ports
### Data Protection- [ ] Verify encryption at rest
- [ ] Check certificate expiration dates
- [ ] Review backup integrity
- [ ] Test data recovery procedures
### Logging and Monitoring- [ ] Verify log retention policies
- [ ] Review alerting thresholds
- [ ] Check SIEM rule effectiveness
- [ ] Analyse anomaly detection reports
Incident Response Planning
Key Concepts
Phase
Description
Preparation
Establishing policies, procedures, and tools before incidents occur
Identification
Detecting and determining whether an event is a security incident
Containment
Limiting the scope and impact of the incident
Eradication
Removing the threat from the environment
Recovery
Restoring systems to normal operation
Lessons Learned
Documenting findings and improving processes
Incident Response Flow
flowchart TD
A[Security Event Detected] --> B{Is it an Incident?}
B -->|No| C[Document and Close]
B -->|Yes| D[Classify Severity]
D --> E{Severity Level}
E -->|Critical| F[Immediate Escalation]
E -->|High| G[Urgent Response]
E -->|Medium| H[Standard Response]
E -->|Low| I[Scheduled Response]
F --> J[Containment Actions]
G --> J
H --> J
I --> J
J --> K[Evidence Collection]
K --> L[Threat Eradication]
L --> M[System Recovery]
M --> N[Post-Incident Review]
N --> O[Update Procedures]
O --> P[Close Incident]
Common Patterns and Scripts
Initial Response Script
#!/bin/bash# incident-response-initial.sh# Initial incident response data collectionINCIDENT_ID="IR-$(date+%Y%m%d-%H%M%S)"OUTPUT_DIR="/var/incident-response/${INCIDENT_ID}"
mkdir-p"${OUTPUT_DIR}"echo"Collecting incident data for ${INCIDENT_ID}..."# System information
uname-a>"${OUTPUT_DIR}/system_info.txt"
uptime>>"${OUTPUT_DIR}/system_info.txt"# Network connections
ss-tulpn>"${OUTPUT_DIR}/network_connections.txt"
netstat-rn>"${OUTPUT_DIR}/routing_table.txt"# Process information
psauxwww>"${OUTPUT_DIR}/process_list.txt"
lsof-i>"${OUTPUT_DIR}/open_files_network.txt"# User information
who>"${OUTPUT_DIR}/logged_in_users.txt"
last-100>"${OUTPUT_DIR}/recent_logins.txt"# Recent file modifications
find/etc-mtime-1-typef>"${OUTPUT_DIR}/recently_modified_etc.txt"
find/var/log-mtime-1-typef>"${OUTPUT_DIR}/recently_modified_logs.txt"# Copy relevant logs
cp/var/log/auth.log"${OUTPUT_DIR}/"
cp/var/log/syslog"${OUTPUT_DIR}/"# Create hash of collected files
find"${OUTPUT_DIR}"-typef-execsha256sum{}\;>"${OUTPUT_DIR}/file_hashes.txt"echo"Initial data collection complete: ${OUTPUT_DIR}"
Containment Actions
# Network isolation# Block specific IP
iptables-AINPUT-s<malicious_ip>-jDROP
iptables-AOUTPUT-d<malicious_ip>-jDROP
# Isolate compromised host
iptables-AINPUT-ieth0-jDROP
iptables-AOUTPUT-oeth0-jDROP
# AWS Security Group isolation
awsec2modify-instance-attribute\--instance-idi-1234567890abcdef0\--groupssg-isolation-group
# Kubernetes pod isolation
kubectllabelpodcompromised-podquarantine=true
kubectlapply-f-<<EOFapiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: quarantine-policyspec: podSelector: matchLabels: quarantine: "true" policyTypes: - Ingress - EgressEOF# Disable user account
usermod-Lsuspicious_user
passwd-lsuspicious_user
# Revoke AWS credentials
awsiamupdate-access-key--access-key-idAKIA...--statusInactive--user-namecompromised-user
Verify all input data meets expected format and constraints
Output Encoding
Encode data appropriately for its output context
Parameterised Queries
Use prepared statements to prevent SQL injection
Authentication & Session Management
Implement secure identity verification
Error Handling
Handle errors without exposing sensitive information
Cryptography
Use strong, well-tested cryptographic implementations
Common Patterns
Input Validation
# Python input validationimportrefromtypingimportOptionaldefvalidate_email(email:str)->bool:"""Validate email format."""pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'returnbool(re.match(pattern,email))defvalidate_username(username:str)->bool:"""Validate username: alphanumeric, 3-20 characters."""pattern=r'^[a-zA-Z0-9_]{3,20}$'returnbool(re.match(pattern,username))defsanitise_input(user_input:str)->str:"""Remove potentially dangerous characters."""# Remove null bytessanitised=user_input.replace('\x00','')# Limit lengthsanitised=sanitised[:1000]returnsanitised# Using Pydantic v2 for validationfrompydanticimportBaseModel,EmailStr,Field,field_validatorclassUserInput(BaseModel):email:EmailStr# Pydantic v2: Field(regex=...) was renamed to pattern=username:str=Field(...,min_length=3,max_length=20,pattern=r'^[a-zA-Z0-9_]+$')age:int=Field(...,ge=0,le=150)# Pydantic v2: @validator is deprecated in favour of @field_validator@field_validator('username')@classmethoddefusername_must_not_contain_spaces(cls,v):if' 'inv:raiseValueError('Username must not contain spaces')returnv
SQL Injection Prevention
# WRONG - Vulnerable to SQL injectioncursor.execute(f"SELECT * FROM users WHERE username = '{username}'")# CORRECT - Parameterised querycursor.execute("SELECT * FROM users WHERE username = %s",(username,))# SQLAlchemy ORM (safe by default)fromsqlalchemy.ormimportSessionfrommodelsimportUserdefget_user(db:Session,username:str):returndb.query(User).filter(User.username==username).first()# Raw SQL with SQLAlchemy (parameterised)fromsqlalchemyimporttextresult=db.execute(text("SELECT * FROM users WHERE username = :username"),{"username":username})
Cross-Site Scripting (XSS) Prevention
# Python - HTML encodingfrommarkupsafeimportescapeuser_input="<script>alert('xss')</script>"safe_output=escape(user_input)# Result: <script>alert('xss')</script># Django template (auto-escapes by default)# templates/user_profile.html# {{ user.name }} <!-- Automatically escaped --># Jinja2 with autoescapefromjinja2importEnvironment,select_autoescapeenv=Environment(autoescape=select_autoescape(['html','xml']))
// JavaScript - DOM manipulation// WRONG - innerHTML with user inputelement.innerHTML=userInput;// CORRECT - textContent for textelement.textContent=userInput;// CORRECT - Use DOMPurify for HTMLimportDOMPurifyfrom'dompurify';element.innerHTML=DOMPurify.sanitize(userInput);
Secure Password Handling
# Python password hashing with bcryptimportbcryptdefhash_password(password:str)->bytes:"""Hash password with bcrypt."""salt=bcrypt.gensalt(rounds=12)returnbcrypt.hashpw(password.encode('utf-8'),salt)defverify_password(password:str,hashed:bytes)->bool:"""Verify password against hash."""returnbcrypt.checkpw(password.encode('utf-8'),hashed)# Using passlib (recommended)frompasslib.contextimportCryptContextpwd_context=CryptContext(schemes=["bcrypt"],deprecated="auto")defhash_password(password:str)->str:returnpwd_context.hash(password)defverify_password(plain_password:str,hashed_password:str)->bool:returnpwd_context.verify(plain_password,hashed_password)
Secure API Design
# FastAPI with security best practicesfromfastapiimportFastAPI,Depends,HTTPException,statusfromfastapi.securityimportOAuth2PasswordBearerimportjwt# PyJWT — prefer over python-jose, which has unpatched CVEs (CVE-2024-33663/33664)fromdatetimeimportdatetime,timedelta,timezoneapp=FastAPI()oauth2_scheme=OAuth2PasswordBearer(tokenUrl="token")SECRET_KEY="your-secret-key"# Use environment variableALGORITHM="HS256"ACCESS_TOKEN_EXPIRE_MINUTES=30defcreate_access_token(data:dict)->str:to_encode=data.copy()expire=datetime.now(timezone.utc)+timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)to_encode.update({"exp":expire})returnjwt.encode(to_encode,SECRET_KEY,algorithm=ALGORITHM)asyncdefget_current_user(token:str=Depends(oauth2_scheme)):credentials_exception=HTTPException(status_code=status.HTTP_401_UNAUTHORIZED,detail="Could not validate credentials",headers={"WWW-Authenticate":"Bearer"},)try:payload=jwt.decode(token,SECRET_KEY,algorithms=[ALGORITHM])username:str=payload.get("sub")ifusernameisNone:raisecredentials_exceptionexceptjwt.InvalidTokenError:raisecredentials_exceptionreturnusername@app.get("/protected")asyncdefprotected_route(current_user:str=Depends(get_current_user)):return{"message":f"Hello {current_user}"}
# Ubuntu/Debian
sudoaptupdate
sudoaptlist--upgradable
sudoaptupgrade-y
sudoaptdist-upgrade-y
# Check for security updates only
sudoaptlist--upgradable2>/dev/null|grep-isecurity
# Unattended upgrades for security patches
sudoaptinstallunattended-upgrades
sudodpkg-reconfigureunattended-upgrades
# View update history
cat/var/log/apt/history.log
# RHEL/CentOS/Rocky
sudodnfcheck-update
sudodnfupdate-y
sudodnfupdate--security
# List security advisories
sudodnfupdateinfolistsecurity
# Check kernel version
uname-r
Container Image Updates
# Rebuild with latest base image
dockerbuild--no-cache-tmyapp:latest.
# Pull latest base images
dockerpullpython:3.11-slim
dockerpullnode:20-alpine
# Update base image in Dockerfile# FROM python:3.11-slim@sha256:abc123... # Pin to digest# Kubernetes rolling update
kubectlsetimagedeployment/myappcontainer=myapp:v2.0.1
kubectlrolloutstatusdeployment/myapp
kubectlrolloutundodeployment/myapp# Rollback if needed
flowchart LR
A[Identify Vulnerabilities] --> B[Assess Risk]
B --> C[Prioritise Patches]
C --> D[Test in Staging]
D --> E{Tests Pass?}
E -->|No| F[Investigate Issues]
F --> D
E -->|Yes| G[Schedule Deployment]
G --> H[Deploy to Production]
H --> I[Verify & Monitor]
I --> J[Document Changes]
Multi-Factor Authentication
Key Concepts
Factor
Type
Examples
Something You Know
Knowledge
Password, PIN, security questions
Something You Have
Possession
Hardware token, mobile device, smart card
Something You Are
Inherence
Fingerprint, facial recognition, voice
Implementation Patterns
TOTP (Time-based One-Time Password)
# Python TOTP implementation with pyotpimportpyotpimportqrcodefromioimportBytesIOdefgenerate_totp_secret()->str:"""Generate a new TOTP secret."""returnpyotp.random_base32()defget_totp_uri(secret:str,user_email:str,issuer:str)->str:"""Generate provisioning URI for authenticator apps."""totp=pyotp.TOTP(secret)returntotp.provisioning_uri(name=user_email,issuer_name=issuer)defgenerate_qr_code(uri:str)->bytes:"""Generate QR code for TOTP URI."""qr=qrcode.QRCode(version=1,box_size=10,border=5)qr.add_data(uri)qr.make(fit=True)img=qr.make_image(fill_colour='black',back_colour='white')buffer=BytesIO()img.save(buffer,format='PNG')returnbuffer.getvalue()defverify_totp(secret:str,token:str)->bool:"""Verify TOTP token."""totp=pyotp.TOTP(secret)returntotp.verify(token,valid_window=1)# Usage examplesecret=generate_totp_secret()uri=get_totp_uri(secret,"user@example.com","MyApp")qr_code=generate_qr_code(uri)# Verify user's tokenuser_token="123456"is_valid=verify_totp(secret,user_token)
WebAuthn/FIDO2 Implementation
# FastAPI WebAuthn implementationfromfastapiimportFastAPI,HTTPExceptionfromwebauthnimport(generate_registration_options,verify_registration_response,generate_authentication_options,verify_authentication_response,)fromwebauthn.helpers.structsimport(AuthenticatorSelectionCriteria,UserVerificationRequirement,)app=FastAPI()RP_ID="example.com"RP_NAME="Example Application"ORIGIN="https://example.com"@app.post("/webauthn/register/begin")asyncdefregistration_begin(user_id:str,username:str):options=generate_registration_options(rp_id=RP_ID,rp_name=RP_NAME,user_id=user_id.encode(),user_name=username,user_display_name=username,authenticator_selection=AuthenticatorSelectionCriteria(user_verification=UserVerificationRequirement.PREFERRED,),)# Store challenge in sessionreturnoptions@app.post("/webauthn/register/complete")asyncdefregistration_complete(credential:dict,expected_challenge:bytes):try:verification=verify_registration_response(credential=credential,expected_challenge=expected_challenge,expected_rp_id=RP_ID,expected_origin=ORIGIN,)# Store credential in databasereturn{"status":"success","credential_id":verification.credential_id}exceptExceptionase:raiseHTTPException(status_code=400,detail=str(e))
SSH Key-based Authentication with MFA
# /etc/ssh/sshd_config
PubkeyAuthenticationyes
PasswordAuthenticationno
ChallengeResponseAuthenticationyes
AuthenticationMethodspublickey,keyboard-interactive
# Install Google Authenticator PAM
sudoaptinstalllibpam-google-authenticator
# Configure PAM for SSH# /etc/pam.d/sshd
authrequiredpam_google_authenticator.so
# User setup
google-authenticator-t-d-f-r3-R30-w3