Releases: vshn/capjs-server
Releases · vshn/capjs-server
v0.2.0
Replay Protection
Challenges can now only be redeemed once per server process, preventing attackers from replaying solved challenges to stockpile verification tokens.
New features
NonceStoreProtocol — pluggable interface for tracking used challenge noncesMemoryNonceStore— thread-safe in-memory default with automatic expiry (no new dependencies)nonce_storeparameter onCapServer— pass a custom store (e.g. Redis) for strict single-use across replicasCAP_NONCE_STOREDjango setting — configure nonce store via Django settings
How it works
After verifying a challenge token's signature, redeem() now checks whether the nonce has been seen before. If it has, the request is rejected. Nonces are tracked with TTLs matching the challenge expiry, so memory stays bounded.
For single-process deployments, this works out of the box. For multi-replica deployments (e.g. Kubernetes), a challenge can be redeemed at most once per replica. For strict single-use across replicas, plug in a shared store:
from capjs_server import CapServer
class RedisNonceStore:
def __init__(self, redis_client):
self.redis = redis_client
def mark_used(self, nonce: str, ttl_seconds: float) -> bool:
return self.redis.set(f"cap:nonce:{nonce}", 1, nx=True, ex=int(ttl_seconds) + 1)
cap = CapServer(secret_key="...", nonce_store=RedisNonceStore(redis_client))