Skip to content

Site Configuration

CaptchaService is multi-tenant. Each "site" has its own key, secret, optional IP allow-list, and optional difficulty map. Configure them in application.yml:

yaml
captcha:
  hmac-key: secret # HMAC key for signing challenges
  captcha-timeout-seconds: 300 # How long a CAPTCHA challenge is valid
  source-address-window-seconds: 3600 # How long a source address is stored
  sites:
    site1: # Site key for site1
      site-secret: "secret1" # Site secret for site1
      max-verifies-per-payload: 1 # How many times a payload can be verified
      whitelisted_source-addresses:
        - "192.0.2.0/24" # Whitelisted IP address range
    site2:
      site-secret: "secret2"
      whitelisted_source-addresses:
        - "192.0.2.0/24" # Whitelisted IP address range
      difficulty-map:
        - min-visits: 1 # From the first visit on...
          cost: 1000 # ...the difficulty is 1000
        - min-visits: 10 # From the 10th visit on...
          cost: 10000 # ...the difficulty is 10000

Fields

  • captcha.hmac-key — global HMAC key used to sign every challenge. Move this into your secret manager via the CAPTCHA_HMAC_KEY environment variable.
  • captcha.captcha-timeout-seconds — how long an issued challenge stays valid before it is rejected on verification.
  • captcha.source-address-window-seconds — observation window for adaptive difficulty.
  • captcha.sites.<key>.site-secret — per-site secret. Clients send siteKey + siteSecret on every request.
  • captcha.sites.<key>.max-verifies-per-payload — how many times a single solved payload can be verified before it is invalidated. Almost always 1.
  • captcha.sites.<key>.whitelisted_source-addresses — list of CIDR ranges. Clients from outside the list are rejected (when the field is present).
  • captcha.sites.<key>.difficulty-map — adaptive difficulty ladder. Each entry maps a number of recent visits (min-visits) to a difficulty level (cost). The service picks the highest matching entry per request, so heavy hitters get more expensive challenges.

Difficulty Map Example

Reading the example above for site2:

Recent visits in windowChallenge cost
1 to 91 000
10 or more10 000

Higher cost makes each solving step on the client more expensive (more hash iterations per try), so the proof of work takes longer on average. Tune per site based on observed bot traffic.

In ZMS / eAppointment

For the ZMS / eAppointment deployment, zmscitizenview holds the public site key and zmscitizenapi keeps the site secret. The whitelisted_source-addresses list and difficulty-map are tuned to the slot-discovery traffic profile of the public booking flow — see Project History for background.