NFC/RFID Security System
RFGuard is a vendor-agnostic, passive NFC brute-force and anomaly detection engine. It ingests NFC reader event streams and log sources, normalizes them into a unified schema, and detects brute-force and anomalous reader behavior in real time.
- Hardware-agnostic, vendor-independent
- Passive monitoring only (no reader interference)
- Real-time sliding window detection (1s/10s/60s)
- Log ingestion: syslog, file tail, JSON/CSV/plain text parsing
- REST ingestion endpoint
- TCP JSON stream ingestion (newline-delimited)
- Optional Kafka adapter
- Structured JSON alerts
- Access-control policy checks (whitelist/blacklist)
- Partial hot-reload (detection + access control)
- Optional SQLite/PostgreSQL persistence
Input adapters → Normalization → Sliding windows per reader → Pattern recognition & rules → Alerts/metrics storage + API
go version # requires Go 1.25+
go build -o rfguard ./cmd/rfguard
go build -o loggen ./cmd/loggen
./rfguard -config config/example.yamlcurl -X POST http://localhost:8080/events \
-H 'Content-Type: application/json' \
-d '{"timestamp":"2026-02-23T12:34:56Z","reader":"reader01","card":"04AABBCC","status":"denied","error":"AUTH_FAIL"}'Update config/example.yaml:
ingest:
file_tail:
enabled: true
files:
- "./nfc.log"Enable TCP stream in config/example.yaml:
ingest:
tcp_stream:
enabled: true
addr: ":9000"nc localhost 9000 <<'EOF'
{"timestamp":"2026-02-23T12:34:56Z","reader":"reader01","card":"04AABBCC","status":"denied"}
EOFGET /statusGET /metrics/{reader_id}GET /metricsGET /alertsGET /config/access_controlPOST /config/access_controlPOST /admin/clearPOST /admin/restartGET /ui/GET /ui/access.htmlGET /ui/alerts.html
See docs/api.md for details.
All thresholds are configurable via YAML/JSON and support hot reload. See config/example.yaml for a full example.
Access-control rules are passive. When enabled, RFGuard will emit alerts for blacklisted UIDs and for non‑whitelisted UIDs if whitelist_only is set.
Access-control changes made from the UI are applied immediately and persisted back to the active config file.
RFGuard normalizes all inputs into:
NormalizedEvent {
timestamp (UTC)
reader_id (string)
uid (string, nullable)
result (success/failure)
error_code (optional)
}
Computed for 1s / 10s / 60s windows:
- Attempts per second (APS):
attempts / window_duration - Failure ratio (FR):
failures / attempts - UID diversity score (UDS):
unique_uids / attempts - Timing variance (TV): variance of inter‑arrival
Δtbetween events
-
Excessive Attempt Rate
Trigger whenAPS > aps_threshold. -
Failure Spike
Trigger whenFR > failure_ratio_thresholdandattempts >= min_attempts. -
UID Spraying / Enumeration
Trigger whenUDS > uid_diversity_thresholdandAPS > aps_elevated_threshold. -
Machine‑Like Timing
Trigger whenTV < timing_variance_thresholdandAPS > aps_elevated_threshold. -
Composite Attack Score
AttackScore = w1 * APS + w2 * FR + w3 * UDS + w4 * (1 / (TV + epsilon))Trigger when:
AttackScore > attack_score_thresholdattempts >= min_attemptsAPS > aps_elevated_threshold
-
Repeated Auth Failure (per UID)
Trigger when the same UID on the same reader produces two or more consecutive events with:result = failureanderror_codepresent (e.g.,AUTH_FAIL)
-
Access Control Policies
- Blacklisted UID: alert when UID is in
access_control.blacklistor per‑reader blacklist. - Whitelist Only: alert when UID is not in whitelist while
whitelist_only: true.
- Blacklisted UID: alert when UID is in
- Supports JSON, CSV, and plain text logs (including syslog‑style timestamps).
- Timestamp parsing: RFC3339,
YYYY‑MM‑DD HH:MM:SS, syslog (Jan 02 15:04:05), and numeric UNIX seconds/milliseconds. - Result inference uses explicit
result/statusfields or anyerror_codeas failure.
- Out‑of‑order timestamps: clamped within
max_clock_skew/max_future_skew. - Duplicate events: suppressed within
dedupe_window. - Missing UID: UID‑dependent rules (spray, access control) safely skip.
go build -o loggen ./cmd/loggen
./loggen -format json -pattern mixed -rate 50 -followloggen appends to ./nfc.log by default, which matches config/example.yaml for live tailing.
Start RFGuard and open the console:
http://localhost:8081/ui/
The UI shows live status, metrics, and alerts. Access control is available at:
http://localhost:8081/ui/access.html
Alerts detail view:
http://localhost:8081/ui/alerts.html
Admin controls are available on both the dashboard and Access Control page to clear metrics, clear alerts, or restart the engine state.
go test ./...docker build -t rfguard .
docker run --rm -p 8080:8080 -p 8081:8081 -v $(pwd)/config:/config rfguard -config /config/example.yaml- Out-of-order timestamps are clamped within configured skew thresholds before windowing.
- Duplicate events are suppressed within
detection.dedupe_window. - Log parsing supports JSON/CSV/plain text and common syslog timestamp formats.