AWS Security ChangesHomeSearch

AWS code-library medium security documentation change

Service: code-library · 2026-05-01 · Security-related medium

File: code-library/latest/ug/lambda_example_api_gateway_GettingStarted_087_section.md

Summary

Enhanced Lambda API Gateway tutorial with security improvements: added input validation, secure parameter handling, error logging, injection sanitization, and robust error handling throughout the deployment script.

Security assessment

Changes include concrete security enhancements: 1) Input validation for AWS account/region in script, 2) Safe handling of user inputs (query/headers/body) with type checking, 3) Sanitization of 'greeter' parameter to prevent injection attacks, 4) Structured error handling that prevents sensitive leakages, 5) Secure shell options (set -euo pipefail), 6) Explicit error handling for AWS CLI operations. These directly mitigate common web security risks like injection and improper error handling.

Diff

diff --git a/code-library/latest/ug/lambda_example_api_gateway_GettingStarted_087_section.md b/code-library/latest/ug/lambda_example_api_gateway_GettingStarted_087_section.md
index b54fde3d2..7db17f80f 100644
--- a//code-library/latest/ug/lambda_example_api_gateway_GettingStarted_087_section.md
+++ b//code-library/latest/ug/lambda_example_api_gateway_GettingStarted_087_section.md
@@ -40,0 +41,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    set -euo pipefail
+    
@@ -52,0 +55,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    # Validate inputs
+    if [[ -z "$ACCOUNT_ID" ]] || [[ -z "$REGION" ]]; then
+        echo "Error: Failed to retrieve AWS account information" >&2
+        exit 1
+    fi
+    
@@ -55 +63 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create Lambda function code
+    # Create Lambda function code with input validation
@@ -57,0 +66 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    import logging
@@ -59,4 +68,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    def lambda_handler(event, context):
-        print(event)
-        
-        greeter = 'World'
+    logger = logging.getLogger()
+    logger.setLevel(logging.INFO)
@@ -63,0 +71 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    def lambda_handler(event, context):
@@ -65,5 +73 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if (event['queryStringParameters']) and (event['queryStringParameters']['greeter']) and (
-                    event['queryStringParameters']['greeter'] is not None):
-                greeter = event['queryStringParameters']['greeter']
-        except KeyError:
-            print('No greeter')
+            logger.info("Received event: %s", json.dumps(event))
@@ -71,6 +75 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        try:
-            if (event['multiValueHeaders']) and (event['multiValueHeaders']['greeter']) and (
-                    event['multiValueHeaders']['greeter'] is not None):
-                greeter = " and ".join(event['multiValueHeaders']['greeter'])
-        except KeyError:
-            print('No greeter')
+            greeter = 'World'
@@ -77,0 +77,24 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+            # Safely retrieve greeter from query string parameters
+            query_params = event.get('queryStringParameters') or {}
+            if isinstance(query_params, dict) and 'greeter' in query_params:
+                greeter_value = query_params.get('greeter')
+                if isinstance(greeter_value, str) and greeter_value:
+                    greeter = greeter_value
+            
+            # Safely retrieve greeter from multi-value headers
+            multi_headers = event.get('multiValueHeaders') or {}
+            if isinstance(multi_headers, dict) and 'greeter' in multi_headers:
+                greeter_list = multi_headers.get('greeter', [])
+                if isinstance(greeter_list, list) and greeter_list:
+                    greeter = " and ".join(str(g) for g in greeter_list if g)
+            
+            # Safely retrieve greeter from headers
+            headers = event.get('headers') or {}
+            if isinstance(headers, dict) and 'greeter' in headers:
+                greeter_value = headers.get('greeter')
+                if isinstance(greeter_value, str) and greeter_value:
+                    greeter = greeter_value
+            
+            # Safely retrieve greeter from body
+            body = event.get('body')
+            if body and isinstance(body, str):
@@ -79,15 +102,12 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            if (event['headers']) and (event['headers']['greeter']) and (
-                    event['headers']['greeter'] is not None):
-                greeter = event['headers']['greeter']
-        except KeyError:
-            print('No greeter')
-        
-        if (event['body']) and (event['body'] is not None):
-            body = json.loads(event['body'])
-            try:
-                if (body['greeter']) and (body['greeter'] is not None):
-                    greeter = body['greeter']
-            except KeyError:
-                print('No greeter')
-        
-        res = {
+                    body_dict = json.loads(body)
+                    if isinstance(body_dict, dict) and 'greeter' in body_dict:
+                        greeter_value = body_dict.get('greeter')
+                        if isinstance(greeter_value, str) and greeter_value:
+                            greeter = greeter_value
+                except (json.JSONDecodeError, ValueError) as e:
+                    logger.warning("Failed to parse body: %s", str(e))
+            
+            # Sanitize greeter to prevent injection
+            greeter = greeter.replace('"', '\\"').replace("'", "\\'")
+            
+            response = {
@@ -96 +116 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-                "Content-Type": "*/*"
+                    "Content-Type": "application/json"
@@ -98 +118 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-            "body": "Hello, " + greeter + "!"
+                "body": json.dumps({"message": f"Hello, {greeter}!"})
@@ -101 +121,12 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        return res
+            logger.info("Response: %s", json.dumps(response))
+            return response
+            
+        except Exception as e:
+            logger.error("Unexpected error: %s", str(e), exc_info=True)
+            return {
+                "statusCode": 500,
+                "headers": {
+                    "Content-Type": "application/json"
+                },
+                "body": json.dumps({"error": "Internal server error"})
+            }
@@ -105 +136,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    zip function.zip lambda_function.py
+    zip -q function.zip lambda_function.py || {
+        echo "Error: Failed to create function.zip" >&2
+        exit 1
+    }
@@ -125 +159 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create IAM role
+    # Create IAM role with error handling
@@ -128 +162,5 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --assume-role-policy-document file://trust-policy.json
+        --assume-role-policy-document file://trust-policy.json \
+        --description "Temporary role for Lambda execution" || {
+        echo "Error: Failed to create IAM role" >&2
+        exit 1
+    }
@@ -133 +171,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
+        --policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" || {
+        echo "Error: Failed to attach IAM policy" >&2
+        exit 1
+    }
@@ -140 +181 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create Lambda function
+    # Create Lambda function with Python 3.11 (more recent runtime)
@@ -143 +184 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --runtime python3.9 \
+        --runtime python3.11 \
@@ -146 +187,7 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --zip-file fileb://function.zip
+        --zip-file fileb://function.zip \
+        --timeout 30 \
+        --memory-size 128 \
+        --environment "Variables={LOG_LEVEL=INFO}" || {
+        echo "Error: Failed to create Lambda function" >&2
+        exit 1
+    }
@@ -150,2 +197,2 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create REST API
-    aws apigateway create-rest-api \
+    # Create REST API with minimum logging
+    API_RESPONSE=$(aws apigateway create-rest-api \
@@ -153 +200,3 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --endpoint-configuration types=REGIONAL
+        --endpoint-configuration types=REGIONAL \
+        --description "API for Lambda proxy integration tutorial" \
+        --output json)
@@ -155,2 +204,6 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Get API ID
-    API_ID=$(aws apigateway get-rest-apis --query "items[?name=='$API_NAME'].id" --output text)
+    API_ID=$(echo "$API_RESPONSE" | grep -o '"id": "[^"]*"' | head -1 | cut -d'"' -f4)
+    
+    if [[ -z "$API_ID" ]]; then
+        echo "Error: Failed to create API Gateway" >&2
+        exit 1
+    fi
@@ -165 +218,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --path-part helloworld
+        --path-part helloworld || {
+        echo "Error: Failed to create resource" >&2
+        exit 1
+    }
@@ -170 +226 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-    # Create ANY method
+    # Create ANY method with no authorization (intentional for tutorial)
@@ -175 +231,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --authorization-type NONE
+        --authorization-type NONE || {
+        echo "Error: Failed to create method" >&2
+        exit 1
+    }
@@ -186 +245,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --uri "$LAMBDA_URI"
+        --uri "$LAMBDA_URI" || {
+        echo "Error: Failed to create integration" >&2
+        exit 1
+    }
@@ -188,0 +251 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
+    STATEMENT_ID="apigateway-invoke-$(openssl rand -hex 4)"
@@ -193 +256 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --statement-id "apigateway-invoke-$(openssl rand -hex 4)" \
+        --statement-id "$STATEMENT_ID" \
@@ -196 +259,4 @@ There's more on GitHub. Find the complete example and learn how to set up and ru
-        --source-arn "$SOURCE_ARN"