Skip to content

Security & compliance

This section describes QSign’s security model and the controls relevant to a technical or compliance review. It is informational, not a certification; map it to your own control framework and obtain independent legal advice on signature validity in your jurisdiction.

  • Web/app users: email + password (passwords hashed by Django’s auth framework). Sessions use JWT (HS256, signed with SECRET_KEY): a short-lived access token (~30 min) and a longer-lived refresh token. Refresh tokens are stored server-side and can be revoked (logout / force-logout).
  • Single sign-on (optional): Google and Microsoft/Entra OAuth.
  • Account lockout: failed logins decrement a per-user counter and lock the account after a threshold; unlock is a deliberate admin action (not automatic).
  • Idle handling: the web app enforces an inactivity timeout; access tokens expire independently, so an abandoned session cannot be used indefinitely.
  • Roles (RBAC): super_admin (platform operator — no signing workspace), admin/user (signing workspace), api_admin (owns API credentials, sees only the developer portal), reviewer. Sensitive operator endpoints require the super_admin claim.
  • API authentication: opaque API keys (qsk_live_/qsk_test_) sent as X-Api-Key; only the SHA-256 hash is stored, so a database compromise does not yield usable keys. Account-management API calls use the api_admin’s JWT.

QSign produces evidence appropriate to each method:

  • e-Signature: signer intent + consent are captured (see audit trail). On completion, a platform tamper seal (a CMS signature over the finalized PDF) is applied so any later byte-level modification is detectable.
  • Aadhaar eSign: identity is asserted by the government Aadhaar OTP flow via the NSDL/Protean gateway; the returned PKCS#7 signature is validated and embedded. This is an IT-Act-aligned electronic signature in India.
  • DSC: a PKI/X.509 digital signature (RSA), optionally with an RFC-3161 trusted timestamp, providing cryptographic non-repudiation. Certificate chains are validated.

Tamper seal cert: the platform seal is applied with the certificate you configure. For maximum third-party trust (e.g. green “valid” in Adobe Reader without manual trust), use an organization signing certificate from a recognized CA. A self-signed seal still provides full tamper-evidence but may show as “not trusted” in some readers.

QSign keeps two complementary kinds of records: the signing evidence trail (the legally-relevant proof of who signed what, when, and how) and operational/activity logs (who did what in the system). Coverage exists for both web-app users and API users, though the operational logging differs in breadth between the two.

Signing evidence trail — applies to ALL signers (web + API)

Section titled “Signing evidence trail — applies to ALL signers (web + API)”

This is the legally-important audit trail and is captured identically regardless of whether the document was created through the web app or the API:

  • ESIGN consent per signer: timestamp, IP address, and user-agent, recorded at the moment the signer consents to sign electronically.
  • Per-recipient signing record: signed / declined status, signing timestamp, decline reason, signer identity (name/email), signing method, IP address, and signing order.
  • Document finalization evidence: the finalized document hash, the seal timestamp, and the signature method (signed_hash / signed_at / signature_method) — the basis of the tamper-evident seal.
  • Method-specific audit logs: dedicated records for the platform notarization/tamper- seal step and for the Aadhaar (Protean) gateway exchange, retained for traceability.
  • Web-app users — event-based activity log: key user actions (e.g. authentication, account/profile and administrative changes) are written to an activity log with the acting user, module, action, free-text detail, IP address, and timestamp. This is targeted to significant actions, not a row per HTTP request.
  • API users — per-call audit log: every metered API call is logged with the calling account, endpoint, HTTP method, response status, IP address, and timestamp. This is comprehensive request-level auditing and also powers quota enforcement and abuse detection. Outbound webhook deliveries are separately logged (event, target URL, attempts, status code, success, response).
RecordWeb-app usersAPI users
Signing evidence (consent, IP, timestamps, method, doc hash)
Notarization / Aadhaar method audit logs
Activity log of user/account actions (with IP)✅ (event-based)n/a (API has no interactive sessions)
Per-request/per-call access log⚠️ Not in-app (see below)✅ Every call (APICallLog)
Webhook delivery logn/a

Gap & recommendation — web-app request-level access logging

Section titled “Gap & recommendation — web-app request-level access logging”

The application logs selected web-app user actions, not every HTTP request. If your audit/compliance posture requires a full request-level access trail for the web app (every request with method, path, status, IP, user), enable it at the edge: turn on nginx access logs (and the upstream LB/WAF logs) and forward them, together with the application activity/signing-evidence records, to your SIEM / centralized log store. This complements the in-app evidence trail with complete access logging. Set a retention period that matches your regulatory obligations.

All in-app records live in the database — back them up with the same rigor as documents (see 06-operations). Treat the signing-evidence records as the primary legal artifact; export/retain them per your e-signature evidentiary requirements.

  • Data in transit: TLS terminates at the reverse proxy; HTTP is redirected to HTTPS and HSTS is set (Strict-Transport-Security). All signer interactions are over HTTPS.
  • Data at rest: documents are stored on the document volume (or Azure Blob if configured). Enable disk/volume encryption (LUKS, encrypted EBS/SAN, or Azure SSE) on the host — QSign relies on the underlying storage for at-rest encryption. Database at-rest encryption is likewise a function of your MySQL/host configuration.
  • Secrets: all credentials are environment-supplied (no secrets in code). API keys and webhook secrets are stored hashed/secret and revealed only once. Restrict the env files (chmod 600) and use a secret manager where possible.
  • PII collected: signer name + email; IP/user-agent + consent timestamps; for Aadhaar, the identity assertion from the gateway. Define retention/erasure per your DPA/GDPR/IT-Act obligations; documents and audit records persist until you delete/anonymize them.
  • Upload safety: the optional ClamAV sidecar scans uploads before processing; infected or oversized files are rejected and flagged.
  • SSRF protection: any caller-supplied URL the server fetches/posts to (document doc_url, webhook_url) is validated — non-HTTP(S) schemes are rejected, and every resolved address is checked against private/loopback/link-local/metadata ranges. Redirects are followed manually and re-validated at each hop (defends DNS-rebinding).
  • Rate limiting: per-caller burst throttling on the API (Redis-backed, shared across workers) with X-RateLimit-* headers; fails open on a cache outage so legitimate traffic is never blocked.
  • HTTP security headers: HSTS, X-Content-Type-Options: nosniff, X-Frame-Options/clickjacking protection, Referrer-Policy, and a restrictive Permissions-Policy are applied to responses.
  • CORS: the backend only accepts cross-origin requests from configured origins (your frontend domain).
  • CSRF: Django CSRF protection on session-based endpoints; secure cookies in production.
  • Idempotency: the create-document API supports an Idempotency-Key to prevent duplicate side effects on retries.
  • Upload size limits and per-tenant document/storage caps are enforced.

Accounts/companies are isolated at the application layer via ownership scoping (every record is tied to its company/account; API responses are scoped to the calling account). For an on-prem single-tenant deployment this is straightforward; if you host multiple business units, keep that scoping in mind and consider separate deployments for hard isolation.

  • Publish only ports 443 (and 80 for ACME) externally; firewall everything else.
  • Never expose Solr, MySQL, Redis, or the esign service to untrusted networks.
  • Enable full-disk/volume encryption on the host and DB storage.
  • Use a CA-issued TLS certificate; keep TLS config current (modern ciphers, HSTS).
  • Set a strong, unique SECRET_KEY and BACKEND_LOGIN_PASSWORD_KEY; rotate on a schedule and on staff offboarding.
  • Use an organization signing certificate for the tamper seal if third-party trust matters.
  • Keep SENTRY_SEND_PII=false unless you have a justification and a DPA.
  • Restrict and audit access to the host, env files, and DB.
  • Enable edge access logging (nginx access logs + LB/WAF) and forward them, with the in-app activity/signing-evidence records, to your SIEM / central log store — this gives the web app full request-level auditing (the app logs selected actions, not every request). Set a retention period that meets your regulatory obligations.
  • Patch the host + base images regularly; apply QSign image updates from Quoqo.
  • Back up DB + documents + audit data; test restores (see 06-operations).
  • Time-sync the host (NTP) — signing/audit timestamps depend on it.
  • QSign supports electronic-signature workflows consistent with frameworks such as the US ESIGN Act / UETA and (for Aadhaar/DSC) India’s IT Act. Suitability for a given document, jurisdiction, and signature level is your determination — obtain legal advice.
  • The audit trail + tamper seal are designed to provide evidentiary support (who signed, when, from where, with consent, and that the document is unmodified since signing).
  • Data-residency, retention, and subject-access obligations are satisfied by running on-prem under your control plus your own retention/erasure procedures.