Security guidelines and best practices for VideoGen Messenger.
- Authentication & Authorization
- API Security
- Data Protection
- Infrastructure Security
- Content Moderation
- Incident Response
Best Practices:
- Use strong, random secrets (minimum 32 characters)
- Set appropriate expiration times (24 hours recommended)
- Rotate secrets periodically
- Store tokens securely on client side
Implementation:
// Generate token
const token = jwt.sign(
{ userId, email },
process.env.JWT_SECRET,
{
expiresIn: '24h',
issuer: 'videogen-messenger',
audience: 'videogen-api'
}
);
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
issuer: 'videogen-messenger',
audience: 'videogen-api'
});Security Checklist:
- JWT_SECRET is at least 32 characters
- Secrets are stored in AWS Secrets Manager
- Tokens include expiration
- Tokens are validated on every request
- Refresh token mechanism implemented
Generation:
const crypto = require('crypto');
function generateApiKey() {
return `vgm_${crypto.randomBytes(32).toString('hex')}`;
}Storage:
const bcrypt = require('bcrypt');
// Hash API key before storing
const hashedKey = await bcrypt.hash(apiKey, 10);
// Store hash in database, give user the plain key onceValidation:
// Compare provided key with stored hash
const isValid = await bcrypt.compare(providedKey, storedHash);Requirements:
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character
Hashing:
const bcrypt = require('bcrypt');
// Hash password (10 rounds)
const passwordHash = await bcrypt.hash(password, 10);
// Verify password
const isValid = await bcrypt.compare(password, passwordHash);Password Validation:
function validatePassword(password) {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(password);
return password.length >= minLength &&
hasUpperCase &&
hasLowerCase &&
hasNumbers &&
hasSpecial;
}Configuration:
// Per-user limits
const userLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
keyGenerator: (req) => req.user?.id || req.ip,
message: 'Too many requests, please try again later'
});
// Aggressive limiting for auth endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 5 attempts per 15 minutes
skipSuccessfulRequests: true
});Protection Against:
- Brute force attacks
- DDoS attacks
- API abuse
- Credential stuffing
Joi Schema Example:
const generationSchema = Joi.object({
prompt: Joi.string().min(3).max(500).required(),
quality: Joi.string().valid('sd', 'hd', '4k').required(),
duration: Joi.number().min(1).max(30).required(),
style: Joi.string().optional()
});
// Validate
const { error, value } = generationSchema.validate(req.body);
if (error) {
return res.status(400).json({ error: error.details[0].message });
}Always Validate:
- Request body
- Query parameters
- Path parameters
- Headers
- File uploads
Use Parameterized Queries:
// BAD - Vulnerable to SQL injection
const query = `SELECT * FROM users WHERE email = '${email}'`;
// GOOD - Parameterized query
const query = 'SELECT * FROM users WHERE email = $1';
const result = await db.query(query, [email]);Content Security Policy:
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'"],
fontSrc: ["'self'"],
objectSrc: ["'none'"],
mediaSrc: ["'self'", 'https://cdn.yourdomain.com'],
frameSrc: ["'none'"]
}
}));Sanitize User Input:
const sanitize = require('sanitize-html');
const clean = sanitize(userInput, {
allowedTags: [],
allowedAttributes: {}
});const corsOptions = {
origin: function (origin, callback) {
const whitelist = [
'https://yourdomain.com',
'https://app.yourdomain.com'
];
if (process.env.NODE_ENV === 'development') {
whitelist.push('http://localhost:3000');
}
if (!origin || whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));Database:
- Enable RDS encryption
- Use AWS KMS for key management
- Encrypt backups
# Enable encryption on RDS
aws rds modify-db-instance \
--db-instance-identifier videogen-db \
--storage-encrypted \
--kms-key-id arn:aws:kms:region:account:key/key-idS3:
- Server-side encryption (SSE-S3 or SSE-KMS)
- Bucket policies enforce encryption
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::videogen-videos-prod/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "AES256"
}
}
}
]
}TLS 1.3:
- All API endpoints use HTTPS
- Database connections use SSL
- Redis connections use TLS
- No plain HTTP in production
Certificate Management:
# Use AWS Certificate Manager
aws acm request-certificate \
--domain-name api.yourdomain.com \
--subject-alternative-names *.yourdomain.com \
--validation-method DNSAWS Secrets Manager:
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
async function getSecret(secretName) {
const data = await secretsManager.getSecretValue({
SecretId: secretName
}).promise();
return JSON.parse(data.SecretString);
}
// Usage
const dbCreds = await getSecret('videogen/database');
const apiKeys = await getSecret('videogen/api-keys');Never:
- Commit secrets to Git
- Log secrets
- Include secrets in error messages
- Store secrets in plain text
GDPR Compliance:
- User consent for data collection
- Right to be forgotten implementation
- Data portability
- Data minimization
Data Deletion:
async function deleteUserData(userId) {
// Delete user record
await db.query('DELETE FROM users WHERE id = $1', [userId]);
// Delete videos
await db.query('DELETE FROM videos WHERE user_id = $1', [userId]);
// Delete from S3
const videos = await s3.listObjects({
Bucket: 'videogen-videos',
Prefix: `${userId}/`
}).promise();
for (const obj of videos.Contents) {
await s3.deleteObject({
Bucket: 'videogen-videos',
Key: obj.Key
}).promise();
}
// Remove from search index
await elasticsearch.deleteByQuery({
index: 'videos',
body: {
query: { term: { user_id: userId } }
}
});
}VPC Configuration:
- Private subnets for databases
- Public subnets for load balancers only
- NAT Gateway for outbound traffic
- Network ACLs
Security Groups:
# API Server Security Group
# Inbound: Port 3000 from ALB only
# Outbound: All traffic
# Database Security Group
# Inbound: Port 5432 from API servers only
# Outbound: None
# Redis Security Group
# Inbound: Port 6379 from API servers only
# Outbound: NonePrinciple of Least Privilege:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::videogen-videos-prod/*"
},
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:*:*:secret:videogen/*"
}
]
}Docker Best Practices:
- Use official base images
- Run as non-root user
- Scan images for vulnerabilities
- Keep images updated
FROM node:18-alpine
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
# Set working directory
WORKDIR /app
# Copy files
COPY --chown=nodejs:nodejs . .
# Install dependencies
RUN npm ci --production
# Switch to non-root user
USER nodejs
# Start application
CMD ["node", "api/server.js"]Security Monitoring:
- Failed login attempts
- Unusual API patterns
- Privilege escalation attempts
- Data export activities
CloudWatch Alarms:
# Alert on high 4xx errors
aws cloudwatch put-metric-alarm \
--alarm-name high-4xx-errors \
--alarm-description "Alert on high 4xx error rate" \
--metric-name 4XXError \
--namespace AWS/ApplicationELB \
--statistic Sum \
--period 300 \
--threshold 100 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1Unsafe Keywords:
const UNSAFE_KEYWORDS = [
'violence', 'explicit', 'nsfw', 'gore',
'weapon', 'drug', 'hate', 'terrorism'
];
function checkContentSafety(prompt) {
const lowerPrompt = prompt.toLowerCase();
for (const keyword of UNSAFE_KEYWORDS) {
if (lowerPrompt.includes(keyword)) {
throw new Error('Prompt contains potentially unsafe content');
}
}
}const { ContentSafetyClient } = require('@azure/ai-content-safety');
async function moderateContent(text) {
const client = new ContentSafetyClient(
process.env.AZURE_CONTENT_SAFETY_ENDPOINT,
process.env.AZURE_CONTENT_SAFETY_KEY
);
const result = await client.analyzeText({
text: text,
categories: ['Hate', 'Sexual', 'Violence', 'SelfHarm']
});
// Check severity levels
for (const category of result.categories) {
if (category.severity >= 4) { // High severity
throw new Error(`Content flagged for ${category.category}`);
}
}
}AWS Rekognition:
const rekognition = new AWS.Rekognition();
async function moderateVideo(videoUrl) {
const result = await rekognition.startContentModeration({
Video: {
S3Object: {
Bucket: 'videogen-videos',
Name: 'video.mp4'
}
}
}).promise();
// Poll for results
// Block videos with inappropriate content
}- Detection: Monitor for security events
- Containment: Isolate affected systems
- Eradication: Remove threat
- Recovery: Restore normal operations
- Lessons Learned: Post-incident review
Immediate Actions:
- Identify scope of breach
- Contain the breach
- Preserve evidence
- Notify security team
Communication:
- Internal stakeholders
- Affected users (within 72 hours for GDPR)
- Regulatory bodies if required
- Law enforcement if necessary
Post-Incident:
- Root cause analysis
- Update security measures
- Document lessons learned
- Update response plan
- All dependencies up to date
- No secrets in code
- Input validation on all endpoints
- Error messages don't leak sensitive info
- Secure defaults everywhere
- HTTPS only (TLS 1.3)
- Security headers configured
- Rate limiting enabled
- CORS properly configured
- Secrets in Secrets Manager
- IAM roles follow least privilege
- Security groups properly configured
- Encryption at rest enabled
- Encryption in transit enabled
- Monitoring and alerting active
- Regular security audits
- Dependency scanning automated
- Penetration testing scheduled
- Incident response plan tested
- Team security training current
- Backup and recovery tested
Recommended Tools:
- OWASP ZAP: Web application security scanner
- Snyk: Dependency vulnerability scanning
- npm audit: Built-in npm security auditing
- AWS Inspector: Infrastructure assessment
- AWS GuardDuty: Threat detection
- Trivy: Container image scanning
Regular Audits:
# Check for vulnerable dependencies
npm audit
# Fix vulnerabilities
npm audit fix
# Container scanning
trivy image videogen-backend:latest
# Infrastructure scanning
aws inspector create-assessment-targetIf you discover a security vulnerability:
- DO NOT open a public issue
- Email: [email protected]
- Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
We will acknowledge within 24 hours and provide updates every 48 hours.