Security

Multi-layered security for DNS-based data distribution

Security Layers

ResolveDB implements defense-in-depth with four distinct security layers:

+--------------------------------------------------------------+
|  Layer 4: Query Privacy (DoH/DoT)                            |
|  -> Encrypts DNS queries in transit                          |
+--------------------------------------------------------------+
|  Layer 3: Payload Encryption (AES-256-GCM, X25519)           |
|  -> Encrypts sensitive data within responses                 |
+--------------------------------------------------------------+
|  Layer 2: Content Integrity (SHA-256, Ed25519)               |
|  -> Verifies data hasn't been tampered with                  |
+--------------------------------------------------------------+
|  Layer 1: DNSSEC Foundation                                  |
|  -> Authenticates DNS infrastructure                         |
+--------------------------------------------------------------+

Layer 1: DNSSEC Foundation

DNSSEC provides cryptographic authentication for DNS responses, preventing cache poisoning and man-in-the-middle attacks.

Features

  • ECDSA P-256 KSK - Key Signing Key with wide resolver compatibility
  • Ed25519 ZSK - Zone Signing Key with modern cryptography
  • Automatic Zone Signing - All records signed with RRSIG at startup
  • DS Record Support - Easy registrar integration

Implementation Status

DNSSEC signing is implemented and ready. To enable:

  1. DS record must be added at the domain registrar
  2. Enable via DNSSEC_ENABLED=true environment variable
  3. Provide key paths for persistent keys

Verifying DNSSEC (when enabled)

# Check DNSSEC validation using dig
dig +dnssec resolvedb.net DNSKEY

# Look for DNSKEY and RRSIG records in response
# The "ad" flag indicates Authenticated Data
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 3, AUTHORITY: 0

Layer 2: Content Integrity

Beyond DNSSEC, ResolveDB supports application-level integrity verification.

SHA-256 Hash Verification

# Response with integrity hash (first 16+ chars of SHA-256)
v=rdb1;s=ok;t=data;h=a7f3c2e8b9d1f456;d={"config":"value"}
// Client verification
async function verifyIntegrity(response) {
  const data = response.d;
  const expectedHash = response.h;  // SHA-256 hash (first 16+ chars)

  const encoder = new TextEncoder();
  const dataBuffer = encoder.encode(data);
  const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
  const actualHash = Array.from(new Uint8Array(hashBuffer))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('')
    .substring(0, expectedHash.length);  // Compare same length

  return actualHash === expectedHash;
}

Ed25519 Signatures

For higher assurance, responses can be signed with Ed25519.

# Signed response format
v=rdb1;s=ok;t=data;sig=<base64-signature>;pk=<base64-pubkey>;d=<data>

Replay Protection

Authenticated requests require timestamp and nonce to prevent replay attacks:

get.auth-<jwt>.ts-1703865600.nonce-a1b2c3d4.resource.namespace.v1.resolvedb.net
RequirementValue
Timestamp tolerance5 seconds
Nonce format8+ alphanumeric characters
Nonce uniquenessCryptographically random, unique per request

Servers reject requests with:

  • Timestamp more than 5 seconds from server time
  • Duplicate (nonce, timestamp) pairs -> returns E016 (replay detected)

Layer 3: Encryption

For sensitive data, ResolveDB supports end-to-end payload encryption.

Symmetric Encryption (AES-256-GCM)

# Encrypted response format
v=rdb1;s=ok;t=data;e=encrypted;d=<base64-nonce+ciphertext>

Structure:

  • First 12 bytes: Random nonce (IV)
  • Remaining bytes: AES-256-GCM ciphertext + auth tag

Asymmetric Key Exchange (X25519)

For establishing shared secrets with ephemeral keys (Perfect Forward Secrecy):

# Query for encrypted data
get.auth-<jwt>.secret.tenant.v1.resolvedb.net

# Response with server ephemeral public key + encrypted data
v=rdb1;s=ok;t=encrypted;e=aes256gcm;k=<server-ephemeral-pubkey>;d=<encrypted-payload>

The k field contains the server's ephemeral X25519 public key (Base64, 32 bytes). Use HKDF-SHA256 to derive the AES-256-GCM key from the shared secret.

JWT Authentication

ResolveDB uses JWT tokens for authenticating requests to protected resources.

Query Format

get.auth-<jwt-token>.resource.namespace.v1.resolvedb.net

JWT Token Structure

{
  "header": {
    "alg": "EdDSA",
    "typ": "JWT"
  },
  "payload": {
    "sub": "user-123",
    "iss": "resolvedb.io",
    "aud": "resolvedb.io",
    "tenant": "acme-corp",
    "exp": 1703869200,
    "iat": 1703865600,
    "nbf": 1703865600,
    "jti": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "scopes": ["read", "write"]
  }
}

Required Claims: sub, iss, aud, exp, iat, nbf, jti, tenant, scopes

Algorithm Requirements

AlgorithmStatusNotes
EdDSA (Ed25519)RequiredPrimary signing algorithm
ES256AllowedECDSA P-256 (legacy)
RS256AllowedRSA 2048+ (legacy)
noneForbiddenNo signature - always reject
HS256/384/512ForbiddenSymmetric key confusion risk

Tokens with forbidden algorithms return E008 (token invalid).

Token Hash References

JWT tokens often exceed the 63-character DNS label limit. Use hash references:

get.auth-h-a1b2c3d4e5f6g7h8i9j0k1l2.resource.namespace.v1.resolvedb.net

Register tokens via the API to receive hash references. See UQRP Protocol for details.

Token Validation

  1. Signature Verification - Ed25519 with constant-time comparison
  2. Expiration Check - Token exp validated against server time
  3. Scope Validation - Operation checked against token scopes
  4. Tenant Isolation - Token tenant must match query namespace

Cache Exclusion

Authenticated queries are never cached:

fn is_authenticated_query(query: &DNSQuery) -> bool {
    query.question.qname.contains(".auth-")
}

// In cache.put(): skip caching for auth queries

Layer 4: Query Privacy

For sensitive queries, use encrypted DNS transports.

Transport Requirements

Query TypeTransportEnforcement
auth-* prefixDoH/DoT requiredReturns E014 if plaintext
user.* namespaceDoH/DoT requiredReturns E014 if plaintext
public.* namespaceDoH/DoT recommendedWarning logged, query processed
system.* namespacePlaintext allowedHealth checks over UDP

DNS-over-HTTPS (DoH)

Endpoint: https://doh.resolvedb.net/dns-query

curl -H "accept: application/dns-json" \
  "https://doh.resolvedb.net/dns-query?name=get.weather.public.v1.resolvedb.net&type=TXT"

DNS-over-TLS (DoT)

Endpoint: dot.resolvedb.net:853

kdig -d @dot.resolvedb.net +tls-ca +tls-hostname=dot.resolvedb.net \
  get.weather.public.v1.resolvedb.net TXT

Best Practices

  1. Always Enable DNSSEC Validation - Check for AD flag in responses
  2. Use Short-Lived JWT Tokens - 15-60 minute expiration
  3. Encrypt Sensitive Payloads - Use AES-256-GCM for defense-in-depth
  4. Use DoH/DoT for Authenticated Queries - Protect tokens in transit
  5. Verify Content Signatures - Don't rely solely on transport security
  6. Rotate Keys Regularly - JWT signing keys quarterly, encryption keys annually

Next Steps