Docs / Dos & Don'ts
Documentation

Dos & Don'ts

Security best practices and common mistakes to avoid in CWaptcha deployments.

✓ Do
  • Enable HTTPS in production

    Set RequireHttps: true in production. CWaptcha's HMAC provides field integrity, but the nonce and fieldSalt must be protected in transit by TLS. SubtleCrypto also requires a secure context (HTTPS or localhost).

  • Keep NonceTtlSeconds short

    Default is 300 seconds (5 minutes). Longer TTLs widen the window for token theft and replay. For high-security forms (password reset, payment), consider 60–120 seconds.

  • Use distributed nonce store on multi-node deployments

    Call .UseDistributedNonceStore() after AddCWaptcha() whenever your app runs behind a load balancer without sticky sessions. Without it, nonces on one node are invisible to others.

  • Store SecretKey outside source control

    Use dotnet user-secrets in development, environment variables in production. A committed SecretKey allows anyone who can read your repo to forge valid CAPTCHA tokens.

  • Protect POST handlers, not GET

    Only include the POST path in ProtectedPaths (e.g. "/Contact", not "/Contact/Post"). Middleware validates POST only. Protecting the GET blocks the page from loading.

  • Use CWaptcha as one layer among several

    Combine with rate limiting (ASP.NET Core Rate Limiting middleware), input validation, and server-side authentication. CWaptcha is bot protection, not a silver bullet.

✗ Don't
  • Don't apply both ProtectedPaths and [CWaptchaValidation] to the same route

    The middleware and the attribute both redeem the nonce. If both run on the same request, the middleware consumes the nonce and the attribute sees it as already used — the request always fails. Choose one mechanism per route.

  • Don't reuse a page's nonce across navigations

    Each page load issues a fresh nonce. Navigating back in the browser, then submitting, uses an already-redeemed token. This is by design — it prevents replay attacks.

  • Don't use MemoryNonceStore behind a load balancer without sticky sessions

    In-memory state is per-process. A request that lands on a different node than the one that issued the nonce will fail to find it. Use UseDistributedNonceStore() instead.

  • Don't load cwaptcha.js from a CDN or external host

    The script is embedded in the NuGet package and served from /cwaptcha/cwaptcha.js by the middleware. Hosting it externally breaks the HMAC field salt mechanism and defeats the self-hosted security model.

  • Don't skip HTTPS validation in production

    On HTTP, the fieldSalt is transmitted in plaintext and could be intercepted to forge a valid token. Always enforce HTTPS in production — either via RequireHttps: true or at the reverse-proxy / IIS level.