hastebin/test-security.sh

305 lines
8.6 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# Security Headers Testing Script for Hastebin
# This script tests various security header configurations by running curl commands
# to verify headers are correctly set and the application works properly.
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
PORT=7777
HOST=localhost
SERVER_START_WAIT=5 # seconds
KILL_WAIT=2 # seconds
# Utility functions
print_header() {
echo -e "\n${BLUE}$1${NC}"
echo -e "${BLUE}$(printf '=%.0s' $(seq 1 ${#1}))${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_info() {
echo -e "${YELLOW} $1${NC}"
}
# Kill any running server instance
kill_server() {
pkill -f "node test-local.js" >/dev/null 2>&1
sleep $KILL_WAIT
}
# Start server with specified environment variables
start_server() {
print_info "Starting server with: $1"
# Use nohup to ensure the process continues running even if the script is interrupted
eval "HASTEBIN_STORAGE_TYPE=file $1 node test-local.js > /tmp/hastebin-test.log 2>&1 &"
# Store the PID for later cleanup
SERVER_PID=$!
# Wait for server to start and log the process ID
print_info "Started server process with PID: $SERVER_PID, waiting ${SERVER_START_WAIT}s..."
sleep $SERVER_START_WAIT
# Check if the server is actually running
if ! ps -p $SERVER_PID > /dev/null; then
print_error "Server failed to start! Check logs at /tmp/hastebin-test.log"
cat /tmp/hastebin-test.log | head -n 20
return 1
fi
return 0
}
# Check if a header exists and matches expected value
check_header() {
local header="$1"
local expected="$2"
local response="$3"
# Extract the header value from response
local value=$(echo "$response" | grep -i "^$header:" | sed "s/^$header: //i" | tr -d '\r')
if [ -z "$value" ]; then
if [ "$expected" == "ABSENT" ]; then
return 0
else
print_error "Header '$header' is missing"
return 1
fi
else
if [ "$expected" == "ABSENT" ]; then
print_error "Header '$header' should be absent but found: $value"
return 1
elif [ "$expected" == "ANY" ]; then
return 0
elif [[ "$value" == *"$expected"* ]]; then
return 0
else
print_error "Header '$header' expected to contain '$expected' but got '$value'"
return 1
fi
fi
}
# Test functionality by creating and retrieving a document
test_functionality() {
print_info "Testing document creation and retrieval..."
# Try multiple times with backoff
for attempt in 1 2 3; do
# Create a document
local create_response=$(curl -s -X POST http://$HOST:$PORT/documents -d "Security Test Document")
echo "Create response: $create_response"
# Extract the key using a more reliable method
local key=$(echo $create_response | sed -n 's/.*"key":"\([^"]*\)".*/\1/p')
if [ -n "$key" ]; then
print_info "Created document with key: $key"
# Retrieve the document
local get_response=$(curl -s http://$HOST:$PORT/raw/$key)
if [ "$get_response" == "Security Test Document" ]; then
print_success "Document creation and retrieval successful"
return 0
else
print_error "Document retrieval failed - expected 'Security Test Document' but got '$get_response'"
fi
else
print_error "Failed to extract key from response: $create_response"
fi
# If we reach here, something failed - wait and retry
sleep_time=$((attempt * 2))
print_info "Attempt $attempt failed, waiting ${sleep_time}s before retry..."
sleep $sleep_time
done
print_error "Failed to create or retrieve document after 3 attempts"
return 1
}
# Run a single test
run_test() {
local test_name="$1"
local env_vars="$2"
local headers_to_check="$3"
print_header "Running test: $test_name"
# Kill any existing server and start a new one with the specified env
kill_server
if ! start_server "$env_vars"; then
print_error "Could not start server for test '$test_name'"
return 1
fi
# Get headers - retry a few times if needed
local response=""
for attempt in 1 2 3; do
response=$(curl -I -s http://$HOST:$PORT/)
if [[ "$response" == *"HTTP/1."* ]]; then
break
fi
sleep 2
done
if [[ "$response" != *"HTTP/1."* ]]; then
print_error "Could not get response from server"
return 1
fi
# Check each header
local failed=0
# Parse the headers to check and their expected values
local IFS=','
read -ra HEADER_CHECKS <<< "$headers_to_check"
for check in "${HEADER_CHECKS[@]}"; do
local header=$(echo $check | cut -d: -f1)
local expected=$(echo $check | cut -d: -f2)
if ! check_header "$header" "$expected" "$response"; then
failed=1
else
print_success "Header '$header' check passed"
fi
done
# Test functionality
if ! test_functionality; then
failed=1
fi
if [ $failed -eq 0 ]; then
print_success "Test '$test_name' passed"
return 0
else
print_error "Test '$test_name' failed"
return 1
fi
}
# Run tests
run_tests() {
print_header "🔒 Hastebin Security Headers Test Suite 🔒"
# Parse command line arguments
local test_filter=""
if [[ "$1" == --test=* ]]; then
test_filter="${1#--test=}"
fi
local passed=0
local failed=0
# Run selected tests
# Filter by name if specified
if [[ -z "$test_filter" || "$test_filter" == *"basic"* ]]; then
if run_test "Basic Security Headers" "NODE_ENV=production" "content-security-policy:ANY,x-content-type-options:nosniff,x-frame-options:DENY,x-xss-protection:1; mode=block,referrer-policy:strict-origin-when-cross-origin,permissions-policy:ANY"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"csp"* ]]; then
if run_test "Content Security Policy" "NODE_ENV=production HASTEBIN_ENABLE_CSP=true" "content-security-policy:script-src"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"noCsp"* ]]; then
if run_test "Disabled CSP" "NODE_ENV=production HASTEBIN_ENABLE_CSP=false" "content-security-policy:ABSENT,x-content-type-options:nosniff,x-frame-options:DENY"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"cors"* ]]; then
if run_test "Cross-Origin Isolation" "NODE_ENV=production HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true" "cross-origin-embedder-policy:require-corp,cross-origin-resource-policy:same-origin,cross-origin-opener-policy:same-origin"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"hsts"* ]]; then
if run_test "HTTP Strict Transport Security" "NODE_ENV=production HASTEBIN_ENABLE_HSTS=true" "strict-transport-security:max-age"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"devMode"* ]]; then
if run_test "Development Mode" "NODE_ENV=development" "content-security-policy:ANY,x-content-type-options:nosniff"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"devBypass"* ]]; then
if run_test "Development Mode with CSP Bypass" "NODE_ENV=development HASTEBIN_BYPASS_CSP_IN_DEV=true" "content-security-policy:unsafe-inline"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
if [[ -z "$test_filter" || "$test_filter" == *"combined"* ]]; then
if run_test "Combined Security Settings" "NODE_ENV=production HASTEBIN_ENABLE_CSP=false HASTEBIN_ENABLE_CROSS_ORIGIN_ISOLATION=true HASTEBIN_ENABLE_HSTS=true" "content-security-policy:ABSENT,x-content-type-options:nosniff,x-frame-options:DENY,cross-origin-embedder-policy:require-corp,strict-transport-security:max-age"; then
passed=$((passed+1))
else
failed=$((failed+1))
fi
fi
# Cleanup any remaining server process
kill_server
# Print summary
print_header "📊 Test Results:"
print_success "$passed tests passed"
if [ $failed -gt 0 ]; then
print_error "$failed tests failed"
return 1
fi
return 0
}
# Show help if requested
if [ $# -gt 0 ] && [ "$1" == "--help" ]; then
echo "Usage: $0 [--test=test1,test2,...]"
echo "Available tests: basic, csp, noCsp, cors, hsts, devMode, devBypass, combined"
exit 0
fi
# Run tests with any arguments passed
run_tests "$@"
result=$?
# Exit with status
exit $result