520 lines
22 KiB
Bash
520 lines
22 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
#
|
||
|
|
# Security Test Suite for Contact Form
|
||
|
|
# Tests all security features against a live server
|
||
|
|
#
|
||
|
|
# Usage:
|
||
|
|
# ./security_tests.sh [SERVER_URL]
|
||
|
|
#
|
||
|
|
# Example:
|
||
|
|
# ./security_tests.sh http://localhost:8080
|
||
|
|
# ./security_tests.sh https://cv.example.com
|
||
|
|
#
|
||
|
|
|
||
|
|
set -e # Exit on error
|
||
|
|
|
||
|
|
# Colors for output
|
||
|
|
RED='\033[0;31m'
|
||
|
|
GREEN='\033[0;32m'
|
||
|
|
YELLOW='\033[1;33m'
|
||
|
|
BLUE='\033[0;34m'
|
||
|
|
NC='\033[0m' # No Color
|
||
|
|
|
||
|
|
# Server URL (default to localhost)
|
||
|
|
SERVER_URL="${1:-http://localhost:8080}"
|
||
|
|
API_URL="${SERVER_URL}/api/contact"
|
||
|
|
|
||
|
|
# Test counters
|
||
|
|
TOTAL_TESTS=0
|
||
|
|
PASSED_TESTS=0
|
||
|
|
FAILED_TESTS=0
|
||
|
|
|
||
|
|
# Helper functions
|
||
|
|
print_header() {
|
||
|
|
echo ""
|
||
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||
|
|
echo -e "${BLUE}$1${NC}"
|
||
|
|
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||
|
|
}
|
||
|
|
|
||
|
|
print_test() {
|
||
|
|
echo -e "${YELLOW}→ $1${NC}"
|
||
|
|
}
|
||
|
|
|
||
|
|
print_pass() {
|
||
|
|
echo -e "${GREEN}✓ $1${NC}"
|
||
|
|
((PASSED_TESTS++))
|
||
|
|
}
|
||
|
|
|
||
|
|
print_fail() {
|
||
|
|
echo -e "${RED}✗ $1${NC}"
|
||
|
|
((FAILED_TESTS++))
|
||
|
|
}
|
||
|
|
|
||
|
|
test_result() {
|
||
|
|
local test_name="$1"
|
||
|
|
local expected_code="$2"
|
||
|
|
local actual_code="$3"
|
||
|
|
local response="$4"
|
||
|
|
|
||
|
|
((TOTAL_TESTS++))
|
||
|
|
|
||
|
|
if [ "$actual_code" -eq "$expected_code" ]; then
|
||
|
|
print_pass "$test_name (expected $expected_code, got $actual_code)"
|
||
|
|
return 0
|
||
|
|
else
|
||
|
|
print_fail "$test_name (expected $expected_code, got $actual_code)"
|
||
|
|
echo " Response: ${response:0:200}"
|
||
|
|
return 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# Calculate submit time (5 seconds ago)
|
||
|
|
get_submit_time() {
|
||
|
|
echo $(( $(date +%s) * 1000 - 5000 ))
|
||
|
|
}
|
||
|
|
|
||
|
|
# Get submit time that's too fast (500ms ago)
|
||
|
|
get_fast_submit_time() {
|
||
|
|
echo $(( $(date +%s) * 1000 - 500 ))
|
||
|
|
}
|
||
|
|
|
||
|
|
# Check if server is running
|
||
|
|
check_server() {
|
||
|
|
print_header "Checking Server Availability"
|
||
|
|
|
||
|
|
if curl -s -o /dev/null -w "%{http_code}" "$SERVER_URL" > /dev/null 2>&1; then
|
||
|
|
print_pass "Server is running at $SERVER_URL"
|
||
|
|
return 0
|
||
|
|
else
|
||
|
|
print_fail "Server is not accessible at $SERVER_URL"
|
||
|
|
echo "Please start the server first: go run main.go"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 1: Browser-Only Middleware - Block curl
|
||
|
|
test_block_curl() {
|
||
|
|
print_header "Test 1: Browser-Only Middleware - Block HTTP Clients"
|
||
|
|
|
||
|
|
# Test curl (default user agent)
|
||
|
|
print_test "Testing curl blocking"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block curl" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test wget user agent
|
||
|
|
print_test "Testing wget blocking"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Wget/1.20.3" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block wget" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test postman
|
||
|
|
print_test "Testing Postman blocking"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: PostmanRuntime/7.26.8" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block Postman" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test python requests
|
||
|
|
print_test "Testing Python requests blocking"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: python-requests/2.25.1" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block Python requests" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test empty user agent
|
||
|
|
print_test "Testing empty User-Agent blocking"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent:" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block empty User-Agent" 403 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 2: Browser-Only Middleware - Require Referer/Origin
|
||
|
|
test_require_referer_origin() {
|
||
|
|
print_header "Test 2: Browser-Only Middleware - Referer/Origin Headers"
|
||
|
|
|
||
|
|
# Test without Referer or Origin
|
||
|
|
print_test "Testing request without Referer/Origin (should block)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block without Referer/Origin" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test with Referer
|
||
|
|
print_test "Testing request with Referer (should allow)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message here&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Allow with Referer" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test with Origin
|
||
|
|
print_test "Testing request with Origin (should allow)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "Origin: ${SERVER_URL}" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test2@example.com&name=Test2&subject=Test&message=Another test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Allow with Origin" 200 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 3: Browser-Only Middleware - Require Browser Headers
|
||
|
|
test_require_browser_headers() {
|
||
|
|
print_header "Test 3: Browser-Only Middleware - Browser Headers"
|
||
|
|
|
||
|
|
# Test without browser headers
|
||
|
|
print_test "Testing request without browser headers (should block)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=Test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Block without browser headers" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test with HX-Request header
|
||
|
|
print_test "Testing request with HX-Request header (should allow)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test3@example.com&name=Test3&subject=Test&message=Message with HX header&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Allow with HX-Request" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test with X-Requested-With header
|
||
|
|
print_test "Testing request with X-Requested-With header (should allow)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "X-Requested-With: XMLHttpRequest" \
|
||
|
|
-d "email=test4@example.com&name=Test4&subject=Test&message=Message with XMLHttpRequest header&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Allow with X-Requested-With" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Test with X-Browser-Request header
|
||
|
|
print_test "Testing request with X-Browser-Request header (should allow)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "X-Browser-Request: true" \
|
||
|
|
-d "email=test5@example.com&name=Test5&subject=Test&message=Message with browser request header&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Allow with X-Browser-Request" 200 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 4: Input Validation - Email Format
|
||
|
|
test_email_validation() {
|
||
|
|
print_header "Test 4: Input Validation - Email Format"
|
||
|
|
|
||
|
|
# Valid email
|
||
|
|
print_test "Testing valid email"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=valid@example.com&name=Test&subject=Test&message=Valid email test message&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Valid email accepted" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Invalid email - no @
|
||
|
|
print_test "Testing invalid email (no @)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=notanemail&name=Test&subject=Test&message=Invalid email test&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Invalid email rejected (no @)" 400 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Invalid email - no domain
|
||
|
|
print_test "Testing invalid email (no domain)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test@&name=Test&subject=Test&message=Invalid email test&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Invalid email rejected (no domain)" 400 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Empty email
|
||
|
|
print_test "Testing empty email"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=&name=Test&subject=Test&message=Empty email test&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Empty email rejected" 400 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 5: Input Validation - Message Length
|
||
|
|
test_message_validation() {
|
||
|
|
print_header "Test 5: Input Validation - Message Length"
|
||
|
|
|
||
|
|
# Valid message
|
||
|
|
print_test "Testing valid message length"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=This is a valid message with sufficient length.&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Valid message accepted" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Empty message
|
||
|
|
print_test "Testing empty message"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Empty message rejected" 400 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Too long message (> 5000 chars)
|
||
|
|
print_test "Testing message too long (>5000 chars)"
|
||
|
|
long_message=$(printf 'a%.0s' {1..5001})
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=test@example.com&name=Test&subject=Test&message=${long_message}&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Too long message rejected" 400 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 6: Bot Protection - Honeypot
|
||
|
|
test_honeypot() {
|
||
|
|
print_header "Test 6: Bot Protection - Honeypot Field"
|
||
|
|
|
||
|
|
# Honeypot empty (human)
|
||
|
|
print_test "Testing honeypot empty (human behavior)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=human@example.com&name=Human&subject=Test&message=I am a real human user.&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Honeypot empty - accepted" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Honeypot filled (bot)
|
||
|
|
print_test "Testing honeypot filled (bot behavior)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=bot@example.com&name=Bot&subject=Spam&message=This is spam!&website=http://spam-site.com&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
# Honeypot returns 200 to fool bots, but doesn't actually send email
|
||
|
|
test_result "Honeypot filled - fake success (bot fooled)" 200 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 7: Bot Protection - Timing
|
||
|
|
test_timing_validation() {
|
||
|
|
print_header "Test 7: Bot Protection - Form Submission Timing"
|
||
|
|
|
||
|
|
# Valid timing (5 seconds)
|
||
|
|
print_test "Testing normal submission timing (5 seconds)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=slow@example.com&name=Slow&subject=Test&message=I took my time filling this out.&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Normal timing accepted" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Too fast (< 2 seconds)
|
||
|
|
print_test "Testing fast submission (< 2 seconds)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=fast@example.com&name=Fast&subject=Test&message=I submitted instantly!&website=&submit_time=$(get_fast_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Too fast submission rejected" 400 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 8: Rate Limiting
|
||
|
|
test_rate_limiting() {
|
||
|
|
print_header "Test 8: Rate Limiting (5 requests per hour)"
|
||
|
|
|
||
|
|
echo "Sending 6 requests rapidly..."
|
||
|
|
|
||
|
|
for i in {1..6}; do
|
||
|
|
print_test "Request #$i"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=rate${i}@example.com&name=RateTest${i}&subject=Test&message=Rate limit test message number ${i}.&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
|
||
|
|
if [ "$i" -le 5 ]; then
|
||
|
|
# First 5 should succeed
|
||
|
|
test_result "Request $i allowed" 200 "$http_code" "$body"
|
||
|
|
else
|
||
|
|
# 6th should be rate limited
|
||
|
|
test_result "Request $i rate limited" 429 "$http_code" "$body"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Small delay between requests
|
||
|
|
sleep 0.1
|
||
|
|
done
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo -e "${YELLOW}Note: Rate limit resets after 1 hour${NC}"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Test 9: Real-World Attack Scenarios
|
||
|
|
test_attack_scenarios() {
|
||
|
|
print_header "Test 9: Real-World Attack Scenarios"
|
||
|
|
|
||
|
|
# Scenario 1: Sophisticated bot with browser-like headers but honeypot filled
|
||
|
|
print_test "Scenario 1: Sophisticated bot (browser headers + honeypot)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=smartbot@example.com&name=SmartBot&subject=Offer&message=Check out our amazing product!&website=http://smart-bot.com&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Smart bot caught by honeypot" 200 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Scenario 2: Script kiddie with curl
|
||
|
|
print_test "Scenario 2: Script kiddie using curl"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-d "email=hacker@example.com&name=Hacker&subject=Pwned&message=You got hacked!&website=&submit_time=$(get_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Script kiddie blocked by BrowserOnly" 403 "$http_code" "$body"
|
||
|
|
|
||
|
|
# Scenario 3: Automated form filler (fast submission)
|
||
|
|
print_test "Scenario 3: Automated form filler (too fast)"
|
||
|
|
response=$(curl -s -w "\n%{http_code}" -X POST "$API_URL" \
|
||
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
|
|
-H "User-Agent: Mozilla/5.0" \
|
||
|
|
-H "Referer: ${SERVER_URL}/" \
|
||
|
|
-H "HX-Request: true" \
|
||
|
|
-d "email=autobot@example.com&name=AutoBot&subject=Auto&message=Automatically filled form!&website=&submit_time=$(get_fast_submit_time)")
|
||
|
|
http_code=$(echo "$response" | tail -n1)
|
||
|
|
body=$(echo "$response" | head -n-1)
|
||
|
|
test_result "Auto-filler caught by timing check" 400 "$http_code" "$body"
|
||
|
|
}
|
||
|
|
|
||
|
|
# Summary
|
||
|
|
print_summary() {
|
||
|
|
print_header "Test Summary"
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo -e "Total Tests: ${BLUE}${TOTAL_TESTS}${NC}"
|
||
|
|
echo -e "Passed: ${GREEN}${PASSED_TESTS}${NC}"
|
||
|
|
echo -e "Failed: ${RED}${FAILED_TESTS}${NC}"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
if [ "$FAILED_TESTS" -eq 0 ]; then
|
||
|
|
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||
|
|
echo -e "${GREEN}✓ ALL SECURITY TESTS PASSED!${NC}"
|
||
|
|
echo -e "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||
|
|
exit 0
|
||
|
|
else
|
||
|
|
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||
|
|
echo -e "${RED}✗ SOME TESTS FAILED${NC}"
|
||
|
|
echo -e "${RED}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# Main execution
|
||
|
|
main() {
|
||
|
|
clear
|
||
|
|
echo -e "${BLUE}"
|
||
|
|
echo "╔══════════════════════════════════════════════════════════════════════╗"
|
||
|
|
echo "║ ║"
|
||
|
|
echo "║ CONTACT FORM SECURITY TEST SUITE ║"
|
||
|
|
echo "║ ║"
|
||
|
|
echo "╚══════════════════════════════════════════════════════════════════════╝"
|
||
|
|
echo -e "${NC}"
|
||
|
|
echo ""
|
||
|
|
echo "Server: $SERVER_URL"
|
||
|
|
echo "Endpoint: $API_URL"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
check_server
|
||
|
|
test_block_curl
|
||
|
|
test_require_referer_origin
|
||
|
|
test_require_browser_headers
|
||
|
|
test_email_validation
|
||
|
|
test_message_validation
|
||
|
|
test_honeypot
|
||
|
|
test_timing_validation
|
||
|
|
test_rate_limiting
|
||
|
|
test_attack_scenarios
|
||
|
|
print_summary
|
||
|
|
}
|
||
|
|
|
||
|
|
# Run main
|
||
|
|
main
|