# Security Headers Audit — security-headers-audit

Audit HSTS, CSP, X-Frame-Options, and COOP/COEP for any URL to quickly spot weaknesses and apply simple fix snippets. Static HTTP checks (HEAD/GET) with optional redirects; no JavaScript crawling. Optional AI can draft a basic CSP.

## Features
- URL input with validation; choose method (HEAD/GET), follow redirects, timeout control
- Static HTTP fetch; redirect chain capture; no JS crawling
- Grades and scores with per-header status: ok, missing, weak
- Fix snippets for common issues (e.g., HSTS, CSP, X-Frame-Options, COOP/COEP)
- History of scans (stored in MySQL) with run metadata
- Export results as CSV or JSON
- Built-in rate limiting (8 requests/minute by default), freemium quotas
- Secure by default: CSP headers, CSRF tokens, prepared statements, output escaping
- Optional AI: draft a basic CSP and improvement tips (based on observed domains)
- Dark UI, blue accent, card layout

## Requirements
- PHP 8.2+ with extensions: curl, json, mbstring, pdo_mysql, openssl
- MySQL 8.x
- Outbound HTTP(S) connectivity from the server
- Optional: OpenAI API key (for AI CSP drafting)

## Quick start
1) Database
- Create a database (utf8mb4) and the two tables.

```sql
CREATE TABLE runs (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  url VARCHAR(2048) NOT NULL,
  method ENUM('HEAD','GET') NOT NULL DEFAULT 'HEAD',
  follow_redirects TINYINT(1) NOT NULL DEFAULT 1,
  ai_csp_draft TINYINT(1) NOT NULL DEFAULT 0,
  timeout_sec TINYINT UNSIGNED NOT NULL DEFAULT 10,
  score TINYINT UNSIGNED NULL,
  grade VARCHAR(2) NULL,
  headers JSON NOT NULL,
  issues JSON NOT NULL,
  fixes JSON NOT NULL,
  redirect_chain JSON NOT NULL,
  ip VARCHAR(45) NULL,
  user_agent VARCHAR(255) NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE rate_limits (
  ip VARCHAR(45) NOT NULL,
  bucket_start TIMESTAMP NOT NULL,
  count INT UNSIGNED NOT NULL DEFAULT 0,
  PRIMARY KEY (ip, bucket_start)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

2) Environment variables
- Provide DB credentials and app secrets. If you plan to use AI, set your OpenAI key.

Example .env:
```ini
APP_ENV=production
APP_BASE_URL=https://yourdomain.example
APP_SECRET=change_me_to_a_random_32+_char_string

APP_DB_HOST=127.0.0.1
APP_DB_PORT=3306
APP_DB_NAME=security_headers_audit
APP_DB_USER=sha_user
APP_DB_PASS=strongpassword

RATE_LIMIT_PER_MINUTE=8
DEFAULT_TIMEOUT_SEC=10
HTTP_MAX_REDIRECTS=5

# Optional AI
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o-mini
OPENAI_TEMPERATURE=0.2
OPENAI_BASE_URL=
```

3) Deploy
- Place the single PHP file (index.php) on an HTTPS-enabled virtual host (Apache or Nginx + PHP-FPM).
- Ensure environment variables are loaded (server config or .env loader).
- Verify the app can connect to MySQL.
- Open the app, submit a URL, and confirm a run appears in the runs table.

## Configuration
Environment variables

| Variable | Required | Default | Purpose |
|---|---|---:|---|
| APP_ENV | No | production | App mode (development/production). |
| APP_BASE_URL | No |  | Absolute base URL, used in links and CSRF origin checks. |
| APP_SECRET | Yes |  | Random secret used for CSRF token HMAC. |
| APP_DB_HOST | Yes |  | Database host. |
| APP_DB_PORT | No | 3306 | Database port. |
| APP_DB_NAME | Yes |  | Database name. |
| APP_DB_USER | Yes |  | Database user. |
| APP_DB_PASS | Yes |  | Database password. |
| RATE_LIMIT_PER_MINUTE | No | 8 | Global per-IP request limit. |
| DEFAULT_TIMEOUT_SEC | No | 10 | Default HTTP timeout when not specified by user. |
| HTTP_MAX_REDIRECTS | No | 5 | Maximum redirects to follow. |
| OPENAI_API_KEY | No |  | Enables AI features when set. |
| OPENAI_MODEL | No | gpt-4o-mini | Model used for CSP drafting tips. |
| OPENAI_TEMPERATURE | No | 0.2 | AI temperature for deterministic output. |
| OPENAI_BASE_URL | No |  | Alternate API base URL (optional proxy). |

Notes:
- Only http/https URLs are accepted. Input is validated against ^https?:// and max length 2048.
- If OPENAI_API_KEY is not provided, AI features are hidden and the app uses static CSP templates.

## How it works
- Inputs: url (required), method (HEAD/GET), follow_redirects (bool), timeout_sec (2–30), ai_csp_draft (bool).
- The app fetches headers, optionally follows redirects, and records the redirect chain.
- It evaluates the presence/strength of: Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy. It may also surface helpful related headers like Referrer-Policy and X-Content-Type-Options.
- Outputs include: numeric score, letter grade, per-header status (ok/missing/weak), list of issues, fix snippets, and the redirect chain.

## Exports
- In-app: Use the Export CSV or Export JSON buttons on a run’s result view.
- Programmatic: Append export parameters to the results URL (e.g., format=csv or format=json). The response includes run metadata, header findings, issues, fixes, and redirect chain.

## Security measures
- Content Security Policy: App pages send a strict CSP (default-src 'self'; no remote scripts; per-request nonce for any inline needs).
- CSRF protection: HMAC-based token tied to session and origin; validated on POST.
- Prepared statements: All DB queries use PDO with prepared statements; no string interpolation.
- Output escaping: All UI output is HTML-escaped; JSON outputs set correct content type.
- Rate limiting: IP-based sliding window (default 8/min) enforced via rate_limits table.
- Input validation: URL pattern/length checks; method whitelist; timeout bounds.
- SSRF guard: Only http/https schemes; blocks private/loopback/link-local/reserved IP ranges after DNS resolution; caps redirects and total fetch time.
- Secure cookies: SameSite=Strict, HttpOnly, Secure in production.
- HTTPS recommended: Optionally include Strict-Transport-Security on the app itself.

## Optional AI behavior and fallback mode
- When AI CSP Draft is enabled and OPENAI_API_KEY is set, the app sends a minimal context (target hostname, observed header values, and any observed external domains from headers/redirects) to generate a baseline CSP and tips.
- Fallback mode: If the AI key is missing, disabled, or an API error occurs, the app shows a static, conservative CSP template and human-written tips. All core auditing remains fully functional.

## Monetization (freemium)
- Free quota: 10 scans per period; Pro quota: 100 scans per period.
- Quota checks run alongside the per-minute rate limit. Configure plan/quotas in your hosting environment or app settings.

## Acceptance checklist
- [ ] Title includes app name and slug
- [ ] One-page summary: problem → outcome
- [ ] Features list covers inputs, history, exports, rate limit, security, AI
- [ ] Requirements: PHP 8.2+, MySQL 8
- [ ] Quick start: DB schema, env vars, deploy steps
- [ ] Config table includes APP_DB_* and OPENAI_* variables
- [ ] Security: CSP, CSRF, prepared statements, output escaping, rate limits, SSRF guard
- [ ] Exports described for CSV/JSON
- [ ] Optional AI behavior and fallback documented
- [ ] License present

## License
MIT (c) Your Name Here