AWS Security ChangesHomeSearch

AWS code-library medium security documentation change

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

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

Summary

Enhanced Lambda function with input validation, error handling, and security improvements including input sanitization and proper error responses. Updated shell script with robust error checking and resource cleanup.

Security assessment

Added explicit input validation and sanitization (greeter.replace) to prevent potential injection attacks. Implemented proper error handling to avoid leaking stack traces (returns generic 500 errors). Added Content-Type headers to prevent content-sniffing vulnerabilities. These changes directly address security weaknesses in input handling and error disclosure.

Diff

diff --git a/code-library/latest/ug/sts_example_api_gateway_GettingStarted_087_section.md b/code-library/latest/ug/sts_example_api_gateway_GettingStarted_087_section.md
index a54a04f4e..f0be399f8 100644
--- a//code-library/latest/ug/sts_example_api_gateway_GettingStarted_087_section.md
+++ b//code-library/latest/ug/sts_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"