Cybersecurity-Projects/PROJECTS/beginner/canary-token-generator/README.md

155 lines
12 KiB
Markdown

```yaml
██████╗ █████╗ ███╗ ██╗ █████╗ ██████╗ ██╗ ██╗
██╔════╝██╔══██╗████╗ ██║██╔══██╗██╔══██╗╚██╗ ██╔╝
██║ ███████║██╔██╗ ██║███████║██████╔╝ ╚████╔╝
██║ ██╔══██║██║╚██╗██║██╔══██║██╔══██╗ ╚██╔╝
╚██████╗██║ ██║██║ ╚████║██║ ██║██║ ██║ ██║
╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝
```
[![Cybersecurity Projects](https://img.shields.io/badge/Cybersecurity--Projects-Project%20%2332-red?style=flat&logo=github)](https://github.com/CarterPerez-dev/Cybersecurity-Projects/tree/main/PROJECTS/beginner/canary-token-generator)
[![Go](https://img.shields.io/badge/Go-1.25+-00ADD8?style=flat&logo=go&logoColor=white)](https://go.dev)
[![React](https://img.shields.io/badge/React-19-61DAFB?style=flat&logo=react&logoColor=black)](https://react.dev)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-18-4169E1?style=flat&logo=postgresql&logoColor=white)](https://www.postgresql.org)
[![Redis](https://img.shields.io/badge/Redis-7-DC382D?style=flat&logo=redis&logoColor=white)](https://redis.io)
[![License: AGPLv3](https://img.shields.io/badge/License-AGPL_v3-purple.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Docker](https://img.shields.io/badge/Docker-ready-2496ED?style=flat&logo=docker)](https://www.docker.com)
[![MITRE Engage](https://img.shields.io/badge/MITRE-Engage-red?style=flat)](https://engage.mitre.org/)
[![Live Demo](https://img.shields.io/badge/Live-iglowinthedark.com-green?style=flat&logo=googlechrome)](https://iglowinthedark.com/)
> Self-hosted honeytoken generator. Mints seven kinds of tripwire artifacts — invisible web bugs, booby-trapped PDF/DOCX files, fake `.env` and kubeconfig credentials, and a real MySQL wire-protocol decoy — then alerts you on Telegram or a webhook the moment an attacker touches one.
*This is a quick overview — security theory, architecture, and full walkthroughs are in the [learn modules](#learn).*
## What It Does
- Seven token types, each disguised as something an attacker would actually try to use: `webbug`, `slowredirect`, `pdf`, `docx`, `envfile`, `kubeconfig`, and a real `mysql` listener that speaks the MySQL v10 handshake
- Per-token Telegram or webhook alerts the instant a token fires (HMAC-signed for webhooks)
- Async notification worker pool with per-channel timeouts and dedup gating (15-minute Redis silence window per `{token, source_ip}` so a curious attacker reloading the page doesn't spam you)
- GeoIP enrichment via MaxMind GeoLite2 (country, region, city, ASN, ASN org) attached to every event
- Browser fingerprint capture for `slowredirect` tokens via a 3-second JS-collection interstitial before the redirect resolves
- Public manage URL (UUID-gated) so you can share a single link with a teammate to view triggers without exposing operator credentials
- Operator-only admin API (constant-time bearer comparison) for global stats, token listing, and force-disable
- Cloudflare Turnstile on token creation, dual-window rate limiting (per-minute + per-hour) keyed by browser fingerprint
- Optional Cloudflare Tunnel overlay — expose the service publicly without opening a port or maintaining a TLS cert
- Defense-grade observability: OpenTelemetry traces, slog structured logs, `/healthz` liveness, graceful shutdown with load-balancer drain delay
## Quick Start
```bash
just init # generates .env, .env.development, randomised ports, operator token
just dev-up # launches nginx + Vite HMR + Go (Air hot-reload) + Postgres + Redis + Jaeger
```
Open the URL printed by `just init` (typically `http://localhost:22784`). Mint a token, watch the manage page, then trigger it from another tab and refresh.
or the live demo at [iglowinthedark.com](https://iglowinthedark.com/)
> [!TIP]
> This project uses [`just`](https://github.com/casey/just) as a command runner. Type `just` to see every available recipe grouped by area.
>
> Install: `curl -sSf https://just.systems/install.sh | bash -s -- --to ~/.local/bin`
## Token Types
| Type | Artifact | Trigger Mechanism | Where You'd Plant It |
|------|----------|-------------------|----------------------|
| `webbug` | URL to a 1x1 JPEG | Any HTTP GET on the URL | HTML emails, internal wikis, "do-not-touch" docs |
| `slowredirect` | URL with a delayed redirect | Click-through; runs fingerprint JS before redirecting to a real destination | Phishing-bait links in honeyfile chat threads, fake admin panel URLs |
| `pdf` | Patched PDF | Acrobat opens, fires `/AA /O /URI` page-open action | `payroll-q3.pdf` on a shared drive, `vpn-creds.pdf` on a workstation |
| `docx` | Patched Word doc | Word/LibreOffice loads the footer, which contains a remote URI | `customer-list.docx`, `passwords.docx` in `Documents/` |
| `envfile` | Plain-text `.env` | Attacker `curl`s the fake `INTERNAL_METRICS_ENDPOINT` baked into the file | Repository roots, `~/.config/`, container `/app/` directories |
| `kubeconfig` | YAML kubeconfig | Attacker runs `kubectl --kubeconfig=stolen.yaml ...` and our server logs the bearer token | `~/.kube/config`, ops engineer laptops, CI runner home dirs |
| `mysql` | `mysql://...` connection string | Attacker connects with `mysql` CLI; our TCP listener replies with a real MySQL v10 handshake and an `Access denied` packet | `.env` files, `database.yml`, internal wiki snippets |
The `envfile` generator is the densest of the bunch. It picks recipes from `aws.go`, `db.go`, `github.go`, and `stripe.go`, shuffles the resulting sections, and buries a single canary line (`INTERNAL_METRICS_ENDPOINT=https://your-host/c/{tokenID}`) among plausible production config. The attacker harvesting the file gets a fistful of fake secrets to chase *and* trips the wire as soon as one of those secrets is touched.
## HTTP API
Token creation, manage view, and admin are mounted under `/api/`. Trigger routes live at the root so artifacts can carry short URLs.
| Method | Path | Auth | Purpose |
|--------|------|------|---------|
| `POST` | `/api/tokens` | Turnstile + rate limit | Mint a new token (`type`, `memo`, `alert_channel`, channel config, type-specific metadata) |
| `GET` | `/api/tokens/types` | Public | List available token types and their metadata schemas |
| `GET` | `/api/m/{manageId}` | Manage UUID | Token details + paginated event feed + dedup silence counter |
| `DELETE` | `/api/m/{manageId}` | Manage UUID | Soft-disable the token (events stop, history retained) |
| `GET` | `/api/admin/stats` | Bearer | Tokens count, events count, breakdowns by type and alert channel |
| `GET` | `/api/admin/tokens` | Bearer | All tokens (offset paginated) |
| `POST` | `/api/admin/tokens/{id}/disable` | Bearer | Force-disable any token |
| `GET` | `/healthz` | Public | Liveness + readiness probe (used by Docker healthchecks) |
| `GET` | `/c/{tokenID}` | Public | **Trigger route.** Records event, fires notification, returns artifact body (pixel, GIF, HTML interstitial, etc.) |
| `POST` | `/c/{tokenID}/fingerprint` | Public | Receives JSON fingerprint payload from the `slowredirect` interstitial |
| `*` | `/k/{tokenID}[/*]` | Public | Kubeconfig trigger — matches `kubectl`'s wildcard API paths |
The MySQL listener does not run on HTTP. It's a separate TCP server bound to a configurable address; an attacker using the connection string from the artifact will speak the MySQL wire protocol with our `protocol.go` handshake builder before getting denied.
## Stack
**Backend:** Go 1.25, chi router, pgx + sqlx, goose migrations, koanf config, slog, validator/v10, OpenTelemetry, pdfcpu, MaxMind GeoLite2, miniredis (tests), testcontainers (integration)
**Frontend:** React 19, TypeScript, Vite, TanStack Query, Zod, Axios, Biome, Stylelint
**Storage:** PostgreSQL 18 (`tokens`, `events` tables; INET + JSONB columns), Redis 7 (dedup gate + rate-limit token buckets)
**Infra:** Docker Compose (dev: nginx + Vite HMR + Air + Postgres + Redis + Jaeger; prod: nginx + Go binary + Postgres + Redis), optional `cloudflared` overlay
## Project Layout
```
canary-token-generator/
├── backend/
│ ├── cmd/canary/ main.go — wiring, signal handling, MySQL listener spawn, retention loop
│ └── internal/
│ ├── token/ Service, repository, handler, generator interface
│ │ └── generators/
│ │ ├── webbug/ Embedded JPEG pixel
│ │ ├── pixel/ Shared 1x1 GIF helper used by every "visited" response
│ │ ├── pdf/ Byte-exact PDF placeholder substitution (76-byte URL window)
│ │ ├── docx/ ZIP-aware footer rewrite
│ │ ├── envfile/ Recipe shuffler + canary line injection
│ │ │ └── recipes/ aws.go, db.go, github.go, stripe.go
│ │ ├── kubeconfig/ text/template renderer + wildcard /k/ handler
│ │ ├── mysql/ protocol.go (handshake + auth + err packets), server.go (TCP), handler.go
│ │ └── slowredirect/ HTML interstitial + fingerprint POST handler
│ ├── event/ Event entity, service (geo enrich → insert → dedup → notify), repository
│ ├── notify/ Worker pool, queue, status writer
│ │ ├── webhook/ HMAC-signed POSTs with exponential backoff
│ │ └── telegram/ Bot API client
│ ├── middleware/ request_id, logging, recovery, realip, fingerprint, ratelimit, turnstile, operator_bearer, headers
│ ├── geoip/ MaxMind MMDB lookup wrapper (nop when no DB present)
│ ├── turnstile/ Cloudflare Turnstile siteverify
│ ├── admin/ Stats, listing, force-disable
│ ├── core/ DB pool, Redis client, migrations, telemetry, errors, validation, response envelopes
│ ├── health/ /healthz handler with readiness/shutdown flags
│ └── server/ chi router shell with graceful shutdown + drain delay
├── frontend/
│ └── src/
│ ├── pages/landing/ Token creation form (type-aware metadata, Turnstile widget, artifact reveal)
│ └── pages/manage/ Token detail + event table (cursor paginated, GeoIP cells, dedup silence)
├── infra/
│ ├── nginx/ prod.nginx, dev.nginx (Vite proxy)
│ └── docker/ Dockerfiles for prod binary, Air hot-reload, Vite HMR
├── compose.yml Production stack
├── dev.compose.yml Dev stack with Jaeger
├── cloudflared.compose.yml Tunnel overlay
├── justfile Recipes grouped by frontend / backend / lint / compose / tunnel / dev / util
└── learn/ You are here
```
## Learn
This project includes step-by-step learning materials covering deception theory, token mechanics, system design, and a code walkthrough.
| Module | Topic |
|--------|-------|
| [00 - Overview](learn/00-OVERVIEW.md) | Prerequisites, quick start, project structure |
| [01 - Concepts](learn/01-CONCEPTS.md) | Honeytokens, deception defense, Thinkst Canary, MITRE Engage, real breaches |
| [02 - Architecture](learn/02-ARCHITECTURE.md) | System design, request lifecycle, schema, dedup gate, notification pipeline |
| [03 - Implementation](learn/03-IMPLEMENTATION.md) | Code walkthrough: generators, trigger handler, event service, MySQL protocol |
| [04 - Challenges](learn/04-CHALLENGES.md) | Extension ideas — new token types, alert channels, evasion-resistance |
## License
AGPL 3.0