Security performance
20. Security & Performance
Security Best Practices
File Upload Validation
Whitelist file extensions:
settings:
file_extensions: 'png gif jpg jpeg webp' # Images only
# Documents: 'pdf doc docx xls xlsx ppt pptx'
# NEVER: svg php js exe sh
Limit file size:
settings:
max_filesize: '10 MB'
max_resolution: '3840x3840'
Validate image dimensions:
settings:
min_resolution: '100x100'
max_resolution: '3840x3840'
Access Control
Never bypass media access checks:
// WRONG: Direct file URL
$url = $media->field_media_image->entity->getFileUri();
// CORRECT: Access-controlled URL
$url = $media->field_media_image->entity->createFileUrl();
Check permissions before showing widgets:
if (\Drupal::currentUser()->hasPermission('create image media')) {
// Show upload widget
}
Filter unpublished media in public queries:
$query->condition('status', 1);
Use private files for restricted content:
settings:
uri_scheme: private
oEmbed Security
Validate oEmbed providers:
source_configuration:
providers:
- YouTube
- Vimeo
# Don't allow arbitrary URLs
Set iframe_domain for oEmbed isolation:
# media.settings.yml
iframe_domain: 'https://media.example.com'
Content Security Policy
Configure CSP headers for media:
// settings.php or .htaccess
$config['media']['csp'] = [
'frame-src' => ['https://www.youtube.com', 'https://player.vimeo.com'],
'img-src' => ['https://i.ytimg.com', 'https://i.vimeocdn.com'],
];
Performance Optimization
Image Delivery
Always use responsive images:
content:
field_media_image:
type: responsive_image
settings:
responsive_image_style: hero
Enable lazy loading:
settings:
image_loading:
attribute: lazy
Use WebP format:
# In image style config:
effects:
convert:
id: image_convert
data:
extension: webp
<picture> with JPEG fallback for old browsers
Queue remote thumbnails:
queue_thumbnail_downloads: true
CDN Integration
Use CDN for media files: - Drupal CDN module: https://www.drupal.org/project/cdn - Flysystem S3: https://www.drupal.org/project/flysystem_s3 - Impact: 40-60% faster image delivery, offloads app server
Set appropriate cache max-age:
// settings.php — configure page cache lifetime
$config['system.performance']['css']['preprocess'] = TRUE;
$config['system.performance']['js']['preprocess'] = TRUE;
// Image derivatives are cached at the web server level via .htaccess rules
// For CDN: set Cache-Control headers via CDN configuration, not Drupal config
Caching
Enable entity view caching:
# In view mode config:
cache: true
BigPipe (enabled by default in Drupal 10+): - Works automatically for authenticated users — no display config needed - Streams page content progressively, improving perceived performance for media-heavy pages
Cache remote API responses:
// For custom media sources
$cache_backend->set($cid, $data, $expire_time);
Database Optimization
Index media reference fields:
# Drupal handles this automatically for entity_reference
# Verify with: drush sqlq "SHOW INDEX FROM node__field_hero_image"
Limit cardinality on unlimited fields: - Why: Unbounded galleries cause memory issues, slow rendering - Threshold: Cap at 50-100 images per gallery
File System
Organize uploads by date:
settings:
file_directory: '[date:custom:Y]-[date:custom:m]'
Use public:// for public media: - Why: private:// requires Drupal bootstrap for every file request (slow) - Impact: 10x faster file delivery with public:// + CDN
Monitoring
Key metrics to monitor: - Average image file size: target < 500 KB for heroes, < 150 KB for cards - Lazy loading effectiveness: measure LCP improvement - CDN cache hit rate: target > 85% - Media entity cache hit rate: target > 90% - Image derivative generation time: target < 2s for largest size
Performance testing:
# Measure page weight
drush pm:enable webprofiler
# Analyze delivered image sizes
# Test image derivative generation
time drush image:flush --all
drush image:derive thumbnail public://2026-02/test.jpg
# Measure Media Library load time
drush webprofiler:analyze --url=/admin/content/media
See Also
- Media File System
- Best Practices & Patterns
- Reference: https://www.drupal.org/docs/security/securing-file-uploads-and-directories
- Reference: https://web.dev/articles/fast (general web performance)