HomeDocs

Security & Best Practices

NexloLabs Verification was designed with security first. This page explains the built-in protections and what you should do on your side.

Built-in protections

Signed tokens (HMAC)

Verification tokens are signed with an HMAC-SHA256 secret that only the API server knows. A token cannot be forged, modified or re-signed by a client. Each token carries:

  • the site ID it was issued for (TOKEN_SITE_MISMATCH otherwise)
  • an expiry timestamp (TOKEN_EXPIRED after 120 s)
  • a unique nonce for replay detection

Replay protection

Redeeming a token atomically marks its hash as used in Redis (token:used:<sha256>). A second attempt with the same token fails with TOKEN_REPLAYED — this blocks session-replay attacks on form submissions.

Secret verification

The verification endpoint requires your site secret, which never leaves your backend. Without the secret, nobody can check tokens — including the site owner's own visitors.

Domain whitelist

When a challenge is created, the API validates the Host/Origin against the site's registered domains. example.com does not accept tokens from evil-example.com (suffix attacks are prevented with exact subdomain matching). Requests from unregistered hostnames fail with DOMAIN_NOT_ALLOWED before any challenge is created.

Rate limiting

Every public endpoint is rate limited per IP (and per secret for verify). Excessive requests receive 429 RATE_LIMITED, which slows down brute-force and automated traffic.

Challenge integrity

  • Challenges are single-use, expire quickly and fail after 3 wrong attempts.
  • Answers for image_select are derived deterministically from a per-challenge seed and validated server-side — the correct answer is never stored in plaintext.
  • Puzzle answers are validated with a positional tolerance, and the behavioral snapshot is scored together with the answer.

Session security

  • Passwords hashed with bcrypt.
  • TOTP secrets for 2FA are stored AES-256-GCM-sealed.
  • Refresh tokens are single-use with rotation; access tokens are short-lived.
  • CSRF protection for all state-changing dashboard endpoints.

No personal data

The widget collects behavioral signals (timing, interaction counts, entropy) but no identifying data: no cookies, no fingerprinting, no IPs stored per challenge beyond the standard verification log.

Best practices on your side

  1. Never expose the site secret. Only your backend may call verify. Frontend code containing nlx_secret_ is a leak.
  2. Set a threshold. Accept score >= 0.5 for normal forms; use >= 0.7 for high-value actions like password changes or payments.
  3. Always verify server-side. The widget only produces tokens; trusting a token without verification defeats the purpose.
  4. Handle 429s gracefully. Show a friendly "too many attempts" message and retry after a few seconds.
  5. Re-check on repeat actions. A token is single-use — require a fresh token for each submission, e.g. per checkout step.
  6. Keep the widget up to date by loading it from the hosted URL, so you automatically receive improvements.
  7. Rotate secrets when a team member leaves or a secret might have leaked (Dashboard → Sites → Rotate secret).
  8. Monitor your statistics. A sudden drop in pass rate or a spike in failed attempts often indicates an attack.
  9. Use API keys with minimal scopes for integrations (statistics:read only, if that is all you need).
  10. Set up monitoring for GET /api/health — it reports database and Redis status.

Threat model summary

AttackDefense
Token forgeryHMAC signature
Token replayOne-time redemption, Redis
Form spam with headless botsBehavioral scoring + score threshold
Cross-site key abuseDomain whitelist + hostname validation
Brute force / scrapingRate limits per IP and per secret
Answer extractionSeeded, server-validated answers; 3 attempts max
Session hijackingShort-lived access tokens, rotating refresh, CSRF