-
Notifications
You must be signed in to change notification settings - Fork 0
Security Implementation
- Introduction
- Authentication
- Authorization
- Data Protection
- Rate Limiting
- Error Handling
- Security Headers
- Best Practices
AgentID implements a comprehensive security model based on Ed25519 cryptographic signatures, challenge-response mechanisms, and defense-in-depth practices. This document details the security architecture and implementation.
AgentID uses Ed25519 digital signatures for all authentication:
- Registration: Agents must sign a challenge message with their Ed25519 private key
- Verification: PKI challenge-response uses Ed25519 signatures
- Flagging: Flag submissions require Ed25519 signatures
The Bags authentication flow:
- Initialize: Request challenge from Bags API
- Sign: Client signs challenge with private key
- Verify: Server verifies signature using tweetnacl
- Complete: Submit to Bags callback for API key
// Signature verification example
const nacl = require('tweetnacl');
const bs58 = require('bs58');
function verifySignature(message, signature, pubkey) {
const messageBytes = bs58.decode(message);
const signatureBytes = bs58.decode(signature);
const pubkeyBytes = bs58.decode(pubkey);
return nacl.sign.detached.verify(messageBytes, signatureBytes, pubkeyBytes);
}Prevents spoofing through time-bound challenges:
- Server generates UUID nonce and challenge string
- Challenge stored with expiration timestamp
- Client signs challenge and returns signature
- Server verifies signature and marks challenge complete
- Single-use enforcement prevents replay attacks
Current implementation uses signature-based authorization:
- Anyone can read public agent data
- Only key holders can modify their agent records
- Flag submissions require reporter's signature
Agent capabilities are stored and verified:
- Stored as JSONB in PostgreSQL
- Validated during registration
- Used for discovery and filtering
All inputs are validated:
- Pubkey format (88 characters, base58)
- Signature format (base58)
- Required field presence
- Data type validation
Parameterized queries throughout:
// Safe - uses parameterized query
const result = await query('SELECT * FROM agents WHERE pubkey = $1', [pubkey]);
// Unsafe - never do this
const result = await query(`SELECT * FROM agents WHERE pubkey = '${pubkey}'`);Output encoding for HTML/XML:
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}Express-rate-limit middleware protects all endpoints:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP'
});
app.use('/api/', limiter);Stricter limits for authentication endpoints:
- Registration: 10 requests per 15 minutes
- Challenge issuance: 20 requests per 15 minutes
Security-conscious error handling:
- Generic error messages in production
- Detailed logging server-side
- No stack traces leaked to clients
- Proper HTTP status codes
// Error handler middleware
function errorHandler(err, req, res, next) {
console.error(err); // Log full error
const status = err.status || 500;
const message = process.env.NODE_ENV === 'production'
? 'Internal server error'
: err.message;
res.status(status).json({ error: message });
}Helmet.js provides security headers:
const helmet = require('helmet');
app.use(helmet());This enables:
- Content Security Policy
- X-DNS-Prefetch-Control
- X-Frame-Options
- Strict-Transport-Security
- X-Download-Options
- X-Content-Type-Options
- X-Permitted-Cross-Domain-Policies
- Referrer-Policy
- Never commit secrets to version control
- Use environment variables
- Rotate API keys regularly
- Use secrets management in production
Always use HTTPS in production:
- TLS 1.2 or higher
- Valid certificates
- HSTS enabled
Monitor for security events:
- Failed authentication attempts
- Rate limit violations
- Unusual traffic patterns
- Error spikes
Keep dependencies updated:
npm audit
npm updateRestrict CORS in production:
const cors = require('cors');
app.use(cors({
origin: process.env.CORS_ORIGIN,
credentials: true
}));