You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-commits@axis.apache.org by ro...@apache.org on 2026/01/30 23:21:16 UTC
(axis-axis2-c-core) 01/07: AXIS2C-1708 Modern security hardening: Add HTTP/2 penetration test infrastructure
This is an automated email from the ASF dual-hosted git repository.
robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git
commit e65277dd73f957d61bd3a3fa6980b1afd607df00
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Jan 30 09:43:26 2026 -1000
AXIS2C-1708 Modern security hardening: Add HTTP/2 penetration test infrastructure
Add comprehensive HTTP/2 JSON penetration test script for security validation:
Test Categories:
- JSON parsing attacks (deep nesting, huge strings, malformed input)
- Integer overflow conditions (INT64_MAX, negative values)
- Concurrent request handling (race condition detection)
- HTTP/2 specific attacks (header overflow)
- Financial service DoS (Monte Carlo simulation abuse)
Features:
- Uses curl --http2 (no additional dependencies)
- Graceful handling when server unavailable
- Detailed logging to /tmp/h2_pentest_<timestamp>/
- Color-coded pass/fail/blocked output
- Designed for ASAN-enabled services
Usage: ./test/security/h2_penetration_test.sh https://localhost:8443
Co-Authored-By: Claude Opus 4.5 <no...@anthropic.com>
---
docs/SECURITY.md | 29 +++
test/security/h2_penetration_test.sh | 455 +++++++++++++++++++++++++++++++++++
2 files changed, 484 insertions(+)
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
index 2ea102f38..bcb737107 100644
--- a/docs/SECURITY.md
+++ b/docs/SECURITY.md
@@ -658,3 +658,32 @@ Do not report security issues via public GitHub issues or mailing lists.
### HTTP/2 Security
- [nghttp2 Security Advisories](https://github.com/nghttp2/nghttp2/security)
- [HTTP/2 (RFC 7540) Security Considerations](https://datatracker.ietf.org/doc/html/rfc7540#section-10)
+
+## HTTP/2 Penetration Testing
+
+For HTTP/2 JSON web services (Axis2/C 2.0.0+), a dedicated penetration test script is available:
+
+```bash
+# Run against deployed services
+./test/security/h2_penetration_test.sh https://localhost:8443
+
+# Tests include:
+# - Deeply nested JSON (stack exhaustion)
+# - Huge string values (memory exhaustion)
+# - Malformed JSON variants
+# - Integer overflow conditions
+# - Concurrent request handling
+# - HTTP/2 header overflow
+```
+
+### Running with ASAN (Recommended)
+
+Build and deploy services with AddressSanitizer for memory error detection:
+
+```bash
+./configure --enable-asan --enable-http2 --enable-json ...
+make && make install
+
+# Deploy to Apache httpd, then run penetration tests
+# Check server logs for ASAN error reports
+```
diff --git a/test/security/h2_penetration_test.sh b/test/security/h2_penetration_test.sh
new file mode 100755
index 000000000..4aeebb64f
--- /dev/null
+++ b/test/security/h2_penetration_test.sh
@@ -0,0 +1,455 @@
+#!/bin/bash
+#
+# HTTP/2 JSON Security Penetration Tests for Axis2/C 2.0.0
+#
+# Tests the BigDataH2Service and FinancialBenchmarkService against:
+# - JSON parsing attacks (deep nesting, huge strings, malformed input)
+# - Memory exhaustion attempts
+# - Integer overflow conditions
+# - Concurrent request handling
+#
+# Prerequisites:
+# - Services deployed to Apache httpd with mod_h2 enabled
+# - curl with HTTP/2 support (check: curl --version | grep HTTP2)
+# - Optional: Build with --enable-asan for memory error detection
+#
+# Usage:
+# ./h2_penetration_test.sh [base_url]
+# ./h2_penetration_test.sh https://localhost:8443
+#
+# Output:
+# Results saved to /tmp/h2_pentest_<timestamp>/
+#
+
+set -e
+
+# Configuration
+BASE_URL="${1:-https://localhost:8443}"
+BIGDATA_ENDPOINT="${BASE_URL}/axis2/services/BigDataH2Service"
+FINANCIAL_ENDPOINT="${BASE_URL}/axis2/services/FinancialBenchmarkService"
+TIMESTAMP=$(date +%Y%m%d_%H%M%S)
+RESULTS_DIR="/tmp/h2_pentest_${TIMESTAMP}"
+CURL_OPTS="--http2 -s -w '\nHTTP_CODE:%{http_code}\nTIME:%{time_total}s\n'"
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Create results directory
+mkdir -p "$RESULTS_DIR"
+echo "Results will be saved to: $RESULTS_DIR"
+
+# Logging
+log_test() {
+ local name="$1"
+ local status="$2"
+ local details="$3"
+
+ if [ "$status" = "PASS" ]; then
+ echo -e "${GREEN}[PASS]${NC} $name"
+ elif [ "$status" = "FAIL" ]; then
+ echo -e "${RED}[FAIL]${NC} $name - $details"
+ elif [ "$status" = "BLOCKED" ]; then
+ echo -e "${GREEN}[BLOCKED]${NC} $name - Attack correctly rejected"
+ else
+ echo -e "${YELLOW}[INFO]${NC} $name - $details"
+ fi
+
+ echo "[$(date '+%H:%M:%S')] $status: $name - $details" >> "$RESULTS_DIR/test.log"
+}
+
+# Check prerequisites
+check_prerequisites() {
+ echo "=== Checking Prerequisites ==="
+
+ if ! curl --version | grep -q "HTTP2"; then
+ echo "ERROR: curl does not support HTTP/2"
+ exit 1
+ fi
+ log_test "curl HTTP/2 support" "PASS" ""
+
+ # Check if server is reachable
+ if ! curl -k -s --http2 -o /dev/null -w "%{http_code}" "${BASE_URL}" 2>/dev/null | grep -q "200\|404\|403"; then
+ log_test "Server connectivity" "INFO" "Server may not be running at ${BASE_URL}"
+ echo ""
+ echo "NOTE: Tests will be generated but may fail if server is not running."
+ echo " Start Apache httpd with mod_h2 and deploy services first."
+ echo ""
+ return 1
+ fi
+ log_test "Server connectivity" "PASS" ""
+ return 0
+}
+
+# =============================================================================
+# JSON PARSING ATTACKS
+# =============================================================================
+
+test_deeply_nested_json() {
+ echo ""
+ echo "=== Test: Deeply Nested JSON (DoS via recursion) ==="
+
+ # Generate JSON with 300 levels of nesting (should exceed AXIS2_JSON_MAX_NESTING_DEPTH)
+ local depth=300
+ local json="{"
+ for i in $(seq 1 $depth); do
+ json="${json}\"level${i}\":{"
+ done
+ json="${json}\"data\":\"test\""
+ for i in $(seq 1 $depth); do
+ json="${json}}"
+ done
+ json="${json}}"
+
+ echo "$json" > "$RESULTS_DIR/nested_json_payload.json"
+
+ local response=$(curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "$json" \
+ -w "\nHTTP_CODE:%{http_code}" \
+ "${BIGDATA_ENDPOINT}/processData" 2>&1)
+
+ echo "$response" > "$RESULTS_DIR/test_nested_json_response.txt"
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+
+ if [ "$http_code" = "400" ] || [ "$http_code" = "413" ] || [ "$http_code" = "500" ]; then
+ log_test "Deeply nested JSON (${depth} levels)" "BLOCKED" "HTTP $http_code - Server rejected excessive nesting"
+ elif [ "$http_code" = "200" ]; then
+ log_test "Deeply nested JSON (${depth} levels)" "FAIL" "HTTP $http_code - Server accepted dangerous input"
+ else
+ log_test "Deeply nested JSON (${depth} levels)" "INFO" "HTTP $http_code"
+ fi
+}
+
+test_huge_string_value() {
+ echo ""
+ echo "=== Test: Huge String Value (Memory exhaustion) ==="
+
+ # Generate 10MB string
+ local size_mb=10
+ local huge_string=$(python3 -c "print('A' * (${size_mb} * 1024 * 1024))" 2>/dev/null || \
+ head -c $((size_mb * 1024 * 1024)) /dev/zero | tr '\0' 'A')
+
+ local json="{\"datasetId\":\"${huge_string}\"}"
+
+ echo "Payload size: $(echo -n "$json" | wc -c) bytes"
+
+ local response=$(curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "$json" \
+ -w "\nHTTP_CODE:%{http_code}\nTIME:%{time_total}s" \
+ --max-time 30 \
+ "${BIGDATA_ENDPOINT}/processData" 2>&1)
+
+ echo "$response" | tail -5 > "$RESULTS_DIR/test_huge_string_response.txt"
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+ local time=$(echo "$response" | grep "TIME:" | cut -d: -f2)
+
+ if [ "$http_code" = "413" ] || [ "$http_code" = "400" ]; then
+ log_test "Huge string value (${size_mb}MB)" "BLOCKED" "HTTP $http_code - Server rejected large payload"
+ elif [ "$http_code" = "200" ]; then
+ log_test "Huge string value (${size_mb}MB)" "INFO" "HTTP $http_code in ${time} - Server processed (check ASAN output)"
+ else
+ log_test "Huge string value (${size_mb}MB)" "INFO" "HTTP $http_code in ${time}"
+ fi
+}
+
+test_malformed_json() {
+ echo ""
+ echo "=== Test: Malformed JSON Variants ==="
+
+ local -a payloads=(
+ '{"unclosed": "string'
+ '{"missing": value}'
+ '{key: "unquoted"}'
+ '{"trailing": "comma",}'
+ '{"duplicate": 1, "duplicate": 2}'
+ '["unclosed array"'
+ '{"unicode": "\uD800"}' # Invalid surrogate
+ '{"null_byte": "test\x00evil"}'
+ )
+
+ local -a names=(
+ "Unclosed string"
+ "Missing value quotes"
+ "Unquoted key"
+ "Trailing comma"
+ "Duplicate keys"
+ "Unclosed array"
+ "Invalid unicode surrogate"
+ "Embedded null byte"
+ )
+
+ for i in "${!payloads[@]}"; do
+ local response=$(curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "${payloads[$i]}" \
+ -w "\nHTTP_CODE:%{http_code}" \
+ "${BIGDATA_ENDPOINT}/processData" 2>&1)
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+
+ if [ "$http_code" = "400" ]; then
+ log_test "Malformed JSON: ${names[$i]}" "BLOCKED" "HTTP 400"
+ else
+ log_test "Malformed JSON: ${names[$i]}" "INFO" "HTTP $http_code"
+ fi
+ done
+}
+
+# =============================================================================
+# INTEGER OVERFLOW ATTACKS
+# =============================================================================
+
+test_integer_overflow() {
+ echo ""
+ echo "=== Test: Integer Overflow Conditions ==="
+
+ local -a values=(
+ "9223372036854775807" # INT64_MAX
+ "-9223372036854775808" # INT64_MIN
+ "9223372036854775808" # INT64_MAX + 1
+ "18446744073709551615" # UINT64_MAX
+ "99999999999999999999999999999999" # Way too big
+ "-1" # Negative size
+ "0" # Zero size
+ )
+
+ local -a names=(
+ "INT64_MAX"
+ "INT64_MIN"
+ "INT64_MAX+1 overflow"
+ "UINT64_MAX"
+ "Enormous number"
+ "Negative size"
+ "Zero size"
+ )
+
+ for i in "${!values[@]}"; do
+ local json="{\"datasetSize\": ${values[$i]}}"
+
+ local response=$(curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "$json" \
+ -w "\nHTTP_CODE:%{http_code}" \
+ --max-time 10 \
+ "${BIGDATA_ENDPOINT}/processData" 2>&1)
+
+ echo "$response" > "$RESULTS_DIR/test_integer_${i}_response.txt"
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+
+ if [ "$http_code" = "400" ]; then
+ log_test "Integer: ${names[$i]}" "BLOCKED" "HTTP 400 - Invalid value rejected"
+ elif [ "$http_code" = "200" ]; then
+ log_test "Integer: ${names[$i]}" "INFO" "HTTP 200 - Check ASAN for overflow"
+ else
+ log_test "Integer: ${names[$i]}" "INFO" "HTTP $http_code"
+ fi
+ done
+}
+
+# =============================================================================
+# CONCURRENT REQUEST ATTACKS
+# =============================================================================
+
+test_concurrent_requests() {
+ echo ""
+ echo "=== Test: Concurrent Request Handling (Race Conditions) ==="
+
+ local num_requests=50
+ local json='{"datasetId":"concurrent_test","datasetSize":1024,"analyticsType":"standard"}'
+
+ echo "Sending $num_requests concurrent requests..."
+
+ local pids=()
+ for i in $(seq 1 $num_requests); do
+ curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "$json" \
+ -o "$RESULTS_DIR/concurrent_${i}.txt" \
+ -w "%{http_code}" \
+ "${BIGDATA_ENDPOINT}/processData" &
+ pids+=($!)
+ done
+
+ # Wait for all requests
+ local success=0
+ local failed=0
+ for pid in "${pids[@]}"; do
+ if wait $pid; then
+ ((success++))
+ else
+ ((failed++))
+ fi
+ done
+
+ log_test "Concurrent requests ($num_requests)" "INFO" "Success: $success, Failed: $failed"
+
+ # Check for any crashes or ASAN errors in server logs
+ echo "Check server logs and ASAN output for race condition indicators"
+}
+
+# =============================================================================
+# FINANCIAL SERVICE SPECIFIC TESTS
+# =============================================================================
+
+test_monte_carlo_dos() {
+ echo ""
+ echo "=== Test: Monte Carlo Computation DoS ==="
+
+ # Request extremely large number of simulations
+ local json='{
+ "portfolioId": "test",
+ "simulationCount": 999999999,
+ "confidenceLevel": 0.99,
+ "timeHorizon": 252
+ }'
+
+ local response=$(curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "$json" \
+ -w "\nHTTP_CODE:%{http_code}\nTIME:%{time_total}s" \
+ --max-time 30 \
+ "${FINANCIAL_ENDPOINT}/calculateVaR" 2>&1)
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+ local time=$(echo "$response" | grep "TIME:" | cut -d: -f2)
+
+ if [ "$http_code" = "400" ] || [ "$http_code" = "413" ]; then
+ log_test "Monte Carlo DoS (huge simulation count)" "BLOCKED" "HTTP $http_code"
+ else
+ log_test "Monte Carlo DoS (huge simulation count)" "INFO" "HTTP $http_code in ${time}"
+ fi
+}
+
+test_portfolio_size_overflow() {
+ echo ""
+ echo "=== Test: Portfolio Size Overflow ==="
+
+ # Generate array with many assets
+ local assets=""
+ for i in $(seq 1 1000); do
+ [ -n "$assets" ] && assets="${assets},"
+ assets="${assets}{\"symbol\":\"ASSET${i}\",\"weight\":0.001,\"volatility\":0.2}"
+ done
+
+ local json="{\"portfolioId\":\"overflow_test\",\"assets\":[${assets}]}"
+
+ echo "Payload size: $(echo -n "$json" | wc -c) bytes"
+
+ local response=$(curl -k --http2 -s -X POST \
+ -H "Content-Type: application/json" \
+ -d "$json" \
+ -w "\nHTTP_CODE:%{http_code}\nTIME:%{time_total}s" \
+ --max-time 30 \
+ "${FINANCIAL_ENDPOINT}/calculateVariance" 2>&1)
+
+ echo "$response" | tail -5 > "$RESULTS_DIR/test_portfolio_overflow_response.txt"
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+ local time=$(echo "$response" | grep "TIME:" | cut -d: -f2)
+
+ log_test "Portfolio with 1000 assets" "INFO" "HTTP $http_code in ${time} - Check ASAN for O(n²) memory issues"
+}
+
+# =============================================================================
+# HTTP/2 SPECIFIC ATTACKS
+# =============================================================================
+
+test_http2_header_overflow() {
+ echo ""
+ echo "=== Test: HTTP/2 Header Overflow ==="
+
+ # Create many custom headers
+ local headers=""
+ for i in $(seq 1 100); do
+ headers="${headers} -H 'X-Custom-Header-${i}: $(head -c 1000 /dev/urandom | base64 | head -c 500)'"
+ done
+
+ local response=$(eval "curl -k --http2 -s -X POST \
+ -H 'Content-Type: application/json' \
+ $headers \
+ -d '{\"test\":true}' \
+ -w '\nHTTP_CODE:%{http_code}' \
+ --max-time 10 \
+ '${BIGDATA_ENDPOINT}/processData'" 2>&1)
+
+ local http_code=$(echo "$response" | grep "HTTP_CODE:" | cut -d: -f2)
+
+ if [ "$http_code" = "431" ] || [ "$http_code" = "400" ]; then
+ log_test "HTTP/2 header overflow (100 large headers)" "BLOCKED" "HTTP $http_code"
+ else
+ log_test "HTTP/2 header overflow (100 large headers)" "INFO" "HTTP $http_code"
+ fi
+}
+
+# =============================================================================
+# MAIN EXECUTION
+# =============================================================================
+
+main() {
+ echo "=============================================="
+ echo "HTTP/2 JSON Security Penetration Tests"
+ echo "Axis2/C 2.0.0 Security Hardening Validation"
+ echo "=============================================="
+ echo ""
+ echo "Target: $BASE_URL"
+ echo "Time: $(date)"
+ echo ""
+
+ local server_available=true
+ check_prerequisites || server_available=false
+
+ if [ "$server_available" = "false" ]; then
+ echo ""
+ echo "Server not available. Generating test payloads only."
+ echo "Payloads saved to: $RESULTS_DIR/"
+ echo ""
+ echo "To run tests:"
+ echo " 1. Start Apache httpd with mod_h2"
+ echo " 2. Deploy BigDataH2Service and FinancialBenchmarkService"
+ echo " 3. Re-run: $0 $BASE_URL"
+ echo ""
+
+ # Still generate some payloads for manual testing
+ test_deeply_nested_json 2>/dev/null || true
+ else
+ # Run all tests
+ test_deeply_nested_json
+ test_huge_string_value
+ test_malformed_json
+ test_integer_overflow
+ test_concurrent_requests
+ test_monte_carlo_dos
+ test_portfolio_size_overflow
+ test_http2_header_overflow
+ fi
+
+ echo ""
+ echo "=============================================="
+ echo "Test Summary"
+ echo "=============================================="
+ echo ""
+ echo "Results saved to: $RESULTS_DIR/"
+ echo "Test log: $RESULTS_DIR/test.log"
+ echo ""
+
+ if [ -f "$RESULTS_DIR/test.log" ]; then
+ echo "Summary:"
+ grep -c "PASS\|BLOCKED" "$RESULTS_DIR/test.log" 2>/dev/null && echo " tests passed/blocked"
+ grep -c "FAIL" "$RESULTS_DIR/test.log" 2>/dev/null && echo " tests failed" || echo "0 tests failed"
+ fi
+
+ echo ""
+ echo "IMPORTANT: Check ASAN output on the server for memory errors!"
+ echo " - Look for: heap-buffer-overflow, use-after-free, double-free"
+ echo " - Server logs: /var/log/apache2/error.log or similar"
+ echo ""
+}
+
+main "$@"