Security Practices

Practices

Secure development lifecycle practices for NUP projects

Security practices ensure that software is developed with security considerations throughout the entire lifecycle. This practice covers secure coding, security training, and vulnerability management.

Secure Development Lifecycle

Secure Development Lifecycle
Secure Development Lifecycle

Security Training

Required Training Topics

TopicFrequencyAudience
OWASP Top 10AnnualAll developers
Secure CodingAnnualDevelopers
Security AwarenessAnnualAll staff
Incident ResponseAnnualOperations team
ComplianceAs neededRelevant roles

Training Resources

ResourceProviderType
OWASP WebGoatOWASPHands-on lab
HackTheBoxHackTheBoxCTF platform
SANS TrainingSANSCertifications
PluralsightPluralsightVideo courses

Training Verification

training_requirements:
  developers:
    - course: "OWASP Top 10"
      frequency: "annual"
      verification: "certificate"

    - course: "Secure Coding Practices"
      frequency: "annual"
      verification: "quiz_score >= 80%"

  operations:
    - course: "Security Incident Response"
      frequency: "annual"
      verification: "drill_participation"

  all_staff:
    - course: "Security Awareness"
      frequency: "annual"
      verification: "completion"

Threat Modeling

STRIDE Framework

ThreatDescriptionMitigation
SpoofingPretending to be someone elseAuthentication
TamperingModifying dataIntegrity checks, signatures
RepudiationDenying actionsAudit logging
Information DisclosureExposing informationEncryption, access control
Denial of ServiceDisrupting serviceRate limiting, scaling
Elevation of PrivilegeGaining unauthorized accessAuthorization, least privilege

Threat Model Process

1. IDENTIFY ASSETS
   - What are we protecting?
   - Data, systems, processes

2. CREATE ARCHITECTURE OVERVIEW
   - Data flow diagrams
   - Trust boundaries
   - Entry points

3. DECOMPOSE APPLICATION
   - Components
   - Data stores
   - External dependencies

4. IDENTIFY THREATS
   - Use STRIDE for each component
   - Document potential attacks

5. DOCUMENT MITIGATIONS
   - Controls for each threat
   - Residual risk acceptance

6. VALIDATE
   - Review with security team
   - Update as system evolves

Secure Coding Practices

Input Validation

// BAD: No validation
function createUser(email: string, name: string) {
  db.query(`INSERT INTO users (email, name) VALUES ('${email}', '${name}')`);
}

// GOOD: Parameterized queries and validation
import { z } from 'zod';

const CreateUserSchema = z.object({
  email: z.string().email().max(255),
  name: z.string().min(1).max(100).regex(/^[a-zA-Z\s]+$/),
});

async function createUser(input: unknown) {
  const { email, name } = CreateUserSchema.parse(input);
  await db.query('INSERT INTO users (email, name) VALUES ($1, $2)', [email, name]);
}

Authentication

// Password hashing with bcrypt
import bcrypt from 'bcrypt';

const SALT_ROUNDS = 12;

async function hashPassword(password: string): Promise<string> {
  return bcrypt.hash(password, SALT_ROUNDS);
}

async function verifyPassword(password: string, hash: string): Promise<boolean> {
  return bcrypt.compare(password, hash);
}

Authorization

// Role-based access control
type Role = 'admin' | 'manager' | 'user';
type Permission = 'read' | 'write' | 'delete' | 'admin';

const rolePermissions: Record<Role, Permission[]> = {
  admin: ['read', 'write', 'delete', 'admin'],
  manager: ['read', 'write', 'delete'],
  user: ['read'],
};

function hasPermission(userRole: Role, requiredPermission: Permission): boolean {
  return rolePermissions[userRole].includes(requiredPermission);
}

// Usage in middleware
function requirePermission(permission: Permission) {
  return (req: Request, res: Response, next: NextFunction) => {
    if (!hasPermission(req.user.role, permission)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

Sensitive Data Handling

// Redact sensitive data in logs
function sanitizeForLogging(obj: object): object {
  const sensitiveFields = ['password', 'ssn', 'creditCard', 'token'];

  return JSON.parse(JSON.stringify(obj), (key, value) => {
    if (sensitiveFields.includes(key.toLowerCase())) {
      return '[REDACTED]';
    }
    return value;
  });
}

// Encrypt sensitive data at rest
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';

const ALGORITHM = 'aes-256-gcm';

function encrypt(text: string, key: Buffer): { encrypted: string; iv: string; tag: string } {
  const iv = randomBytes(16);
  const cipher = createCipheriv(ALGORITHM, key, iv);

  let encrypted = cipher.update(text, 'utf8', 'hex');
  encrypted += cipher.final('hex');

  return {
    encrypted,
    iv: iv.toString('hex'),
    tag: cipher.getAuthTag().toString('hex'),
  };
}

Security Headers

// Express.js security headers with Helmet
import helmet from 'helmet';

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
      connectSrc: ["'self'", "https://api.example.com"],
      fontSrc: ["'self'"],
      objectSrc: ["'none'"],
      mediaSrc: ["'self'"],
      frameSrc: ["'none'"],
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true,
  },
  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
}));

Vulnerability Management

Vulnerability Response Process

Vulnerability Response
Vulnerability Response

Severity-Based SLAs

SeverityCVSS ScoreResponse TimeResolution Time
Critical9.0-10.04 hours24 hours
High7.0-8.924 hours7 days
Medium4.0-6.97 days30 days
Low0.1-3.930 days90 days

Dependency Scanning Configuration

# .github/workflows/security.yml
name: Security Scanning

on:
  push:
    branches: [main, develop]
  pull_request:
  schedule:
    - cron: '0 0 * * *'  # Daily

jobs:
  dependency-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Snyk to check for vulnerabilities
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        with:
          args: --severity-threshold=high

      - name: Upload Snyk results
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: snyk.sarif

Security Code Review Checklist

Authentication & Authorization

  • Password strength requirements enforced
  • Passwords hashed with bcrypt/Argon2 (cost factor >= 10)
  • Session tokens are cryptographically random
  • Session invalidation on logout
  • MFA implemented for sensitive operations
  • Authorization checked on every request

Input Handling

  • All input validated and sanitized
  • Parameterized queries used (no SQL injection)
  • Output encoding applied (no XSS)
  • File uploads validated (type, size, name)
  • Rate limiting implemented

Data Protection

  • Sensitive data encrypted at rest
  • TLS 1.2+ for data in transit
  • PII minimization applied
  • Secrets not hardcoded
  • Secure logging (no sensitive data)

Error Handling

  • Generic error messages to users
  • Detailed errors only in logs
  • No stack traces in production
  • Failed operations fail securely

Compliance

This section fulfills ISO 13485 requirements for risk management (7.1) and design verification (7.3.6), and ISO 27001 requirements for secure development lifecycle (A.8.25), secure coding (A.8.28), security testing (A.8.29), and vulnerability management (A.8.8).

View full compliance matrix

Sign in or sign up

Enter your work email to receive a temporary sign-in link.

By continuing, you agree to our Terms of Service and Privacy Policy.