MediaWiki Security — Hardening, .htaccess, CSP, XSS Prevention, and CAPTCHA
In this tutorial, you will learn about MediaWiki Security. We cover key concepts, practical examples, and best practices to help you master this topic.
Security hardening in MediaWiki protects your wiki against common web threats through multiple layers — server-level .htaccess restrictions, Content Security Policy headers, built-in XSS and CSRF protections, CAPTCHA configuration, input validation, and secure authentication practices, the same defense-in-depth approach Wikipedia uses to protect one of the world's most targeted websites.
What You'll Learn
- Server-level security with .htaccess
- Content Security Policy configuration
- Understanding XSS and CSRF prevention
- Configuring CAPTCHA
- Securing file uploads
- Protecting user accounts
- Security hardening checklist
Why It Matters
A wiki is a target. It stores valuable content, user data, and runs on a public-facing web server. Attackers target wikis for spam, malware distribution, data theft, and defacement. MediaWiki has strong built-in security, but it must be properly configured. A single misconfiguration — like allowing uploaded HTML files or disabling CSRF tokens — can compromise your entire installation.
Real-World Use
A DodaTech wiki implements defense in depth. The .htaccess file blocks direct access to configuration files. Content Security Policy prevents injected scripts from executing. CAPTCHA stops automated spam registrations. File uploads are restricted to safe types with MIME verification. User passwords require 12+ characters. The wiki has never been successfully attacked.
Learning Path
flowchart RL A["38: Performance Tuning"] --> B["39: Upgrading MediaWiki"] B --> C["40: Security"] C:::current classDef current fill#38bdf8,color#0f172a,stroke-width:2px
Server-Level Security with .htaccess
Protect sensitive files and directories at the web server level.
Protect LocalSettings.php
Create or edit .htaccess in the MediaWiki root:
# Block access to sensitive files
<FilesMatch "^(LocalSettings\.php|\.htaccess|\.git)">
Require all denied
</FilesMatch>
# Block access to configuration directory
<DirectoryMatch "^\.|\/cache\/|\/logs\/">
Require all denied
</DirectoryMatch>
Protect the includes Directory
# Block direct access to PHP includes
<Directory "/var/www/mediawiki/includes">
Require all denied
</Directory>
Protect the maintenance Directory
# Block public access to maintenance scripts
<Directory "/var/www/mediawiki/maintenance">
Require all denied
</Directory>
Secure Image Uploads
# Prevent execution of PHP files in uploads
<Directory "/var/www/mediawiki/images">
php_flag engine off
<FilesMatch "\.(php|php5|phtml|shtml|cgi)$">
Require all denied
</FilesMatch>
</Directory>
Content Security Policy (CSP)
CSP prevents cross-site scripting (XSS) by controlling which resources the browser can load.
Basic CSP Configuration
// In LocalSettings.php
$wgCSPHeader = [
'default-src' => [
"'self'",
],
'script-src' => [
"'self'",
"'unsafe-inline'", // Required for some wiki features
],
'style-src' => [
"'self'",
"'unsafe-inline'", // Required for user CSS
],
'img-src' => [
"'self'",
"data:",
"https://upload.wikimedia.org",
],
'connect-src' => [
"'self'",
"https://api.dodatech.com",
],
];
Testing CSP
Start with report-only mode to test without blocking:
$wgCSPReportOnlyHeader = true;
$wgCSPHeader = [
'default-src' => "'self'",
'report-uri' => 'https://your-report-endpoint.com/csp',
];
Check CSP reports for blocked resources and adjust the policy.
CSP Best Practices
- Start strict and loosen as needed
- Avoid
'unsafe-inline'for scripts if possible - Use nonces or hashes for inline scripts
- Keep the policy as restrictive as your extensions allow
- Test in report-only mode before enforcing
XSS Prevention
Cross-Site Scripting (XSS) allows attackers to inject malicious scripts into pages.
Built-in XSS Protection
MediaWiki has strong built-in XSS protection:
- HTML sanitization: User-generated HTML is sanitized on output
- Escaping: All user input is escaped by default
- Edit filters: The AbuseFilter extension can block suspicious edits
- No raw HTML by default: Users cannot inject raw HTML without specific permissions
Configuring HTML Whitelist
// Allow specific HTML tags (restrictive is safer)
$wgRawHtml = false; // Disable raw HTML entirely
// If raw HTML is needed, use a whitelist
$wgRawHtmlMimeTypes = [ 'text/html' ];
XSS Risks to Avoid
❌ Allowing raw HTML for all users
❌ Using $wgAllowExternalImages without restrictions
❌ Disabling $wgMiserMode (which controls expensive operations)
❌ Installing untested extensions
❌ Granting editinterface to untrusted users
CSRF Prevention
Cross-Site Request Forgery (CSRF) tricks authenticated users into performing actions without their consent.
Built-in CSRF Protection
MediaWiki uses CSRF tokens for every write operation:
// CSRF tokens are enabled by default
$wgEnableWriteAPI = true; // API requires tokens
$wgCSRFTokenDuration = 3600; // Token valid for 1 hour
How CSRF Tokens Work
- User loads a page with an edit form
- MediaWiki generates a unique token tied to the user's session
- The token is embedded in the form as a hidden field
- When the form is submitted, MediaWiki validates the token
- If the token is missing or invalid, the request is rejected
CSRF Best Practices
- Keep
$wgEnableWriteAPIset totrue - Use
api.phpwith tokens for all write operations - Never use GET requests for write operations
- Keep session timeout reasonable (not too long)
CAPTCHA Configuration
CAPTCHA prevents automated spam and abuse by requiring human interaction.
Install ConfirmEdit
cd /opt/lampp/htdocs/mediawiki/extensions
git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/ConfirmEdit.git
cd ConfirmEdit
git checkout REL1_42
Enable CAPTCHA
wfLoadExtension( 'ConfirmEdit' );
// Choose a CAPTCHA module
$wgCaptchaClass = 'Captcha\SimpleCaptcha\SimpleCaptcha';
// Triggers: when to show CAPTCHA
$wgCaptchaTriggers['edit'] = true; // On every edit
$wgCaptchaTriggers['create'] = true; // On page creation
$wgCaptchaTriggers['addurl'] = true; // When adding external links
$wgCaptchaTriggers['createaccount'] = true; // On account registration
$wgCaptchaTriggers['badlogin'] = true; // After failed login attempts
CAPTCHA Modules
// Simple CAPTCHA (math question) — no external dependencies
$wgCaptchaClass = 'Captcha\SimpleCaptcha\SimpleCaptcha';
// ReCAPTCHA (Google)
wfLoadExtension( 'ConfirmEdit/ReCaptchaNoCaptcha' );
$wgCaptchaClass = 'ReCaptchaNoCaptcha';
$wgReCaptchaSiteKey = 'your-site-key';
$wgReCaptchaSecretKey = 'your-secret-key';
// Questy CAPTCHA (custom questions)
wfLoadExtension( 'ConfirmEdit/QuestyCaptcha' );
$wgCaptchaClass = 'QuestyCaptcha';
$wgCaptchaQuestions = [
'What color is the sky?' => 'blue',
'What is 2 + 2?' => '4',
];
CAPTCHA Best Practices
- Always enable for account registration
- Enable for anonymous edits (if allowed)
- Consider disabling for trusted user groups
- Use QuestyCaptcha if you cannot use external services
File Upload Security
Restrict File Types
// Only allow safe file types
$wgFileExtensions = [ 'png', 'gif', 'jpg', 'jpeg', 'svg', 'pdf', 'webp' ];
// Strict checking
$wgCheckFileExtensions = true;
$wgStrictFileExtensions = true;
// MIME type verification
$wgVerifyMimeType = true;
Disable Dangerous File Types
// Explicitly forbid dangerous types
$wgFileBlacklist = [
'html', 'htm', 'php', 'php5', 'phtml', 'exe', 'bat',
'cmd', 'com', 'dll', 'js', 'vbs', 'asp', 'aspx', 'jsp',
];
SVG Security
// SVGs can contain JavaScript — sanitize them
$wgSVGMetadataCutoff = 262144;
$wgAllowTitlesInSVG = false;
// Disable SVG upload if not needed
// Just remove 'svg' from $wgFileExtensions
User Account Security
Password Policy
// Enforce strong passwords
$wgPasswordPolicy['policies']['default'] = [
'MinimalPasswordLength' => 10,
'MinimumPasswordLengthToLogin' => 1,
'MaximalPasswordLength' => 4096,
'PasswordCannotMatchUsername' => true,
'PasswordCannotMatchBlacklist' => true,
];
// More aggressive for administrators
$wgPasswordPolicy['policies']['sysop'] = [
'MinimalPasswordLength' => 14,
'MinimumPasswordLengthToLogin' => 10,
];
Account Creation Control
// Require email confirmation to edit
$wgEmailConfirmToEdit = true;
// Disable anonymous account creation
$wgGroupPermissions['*']['createaccount'] = false;
$wgGroupPermissions['user']['createaccount'] = true;
// Require admin approval for account creation
$wgConfirmAccountRequest = true;
Security Headers
Add security headers in your web server configuration:
# Apache
Header always set X-Frame-Options "DENY"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "same-origin"
Header always set X-XSS-Protection "1; mode=block"
# Nginx
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "same-origin" always;
Security Hardening Checklist
Server Level:
☐ Block direct access to LocalSettings.php
☐ Protect includes/, maintenance/, cache/ directories
☐ Disable directory listing
☐ Use HTTPS (not HTTP)
☐ Keep PHP, MySQL, and web server updated
MediaWiki Configuration:
☐ Restrict file upload types
☐ Enable MIME verification
☐ Configure CAPTCHA (at minimum for registration)
☐ Enforce strong passwords
☐ Require email confirmation for editing
☐ Enable CSP headers
☐ Keep CSRF protection enabled
User Management:
☐ Review user groups regularly
☐ Remove inactive administrator accounts
☐ Use principle of least privilege
☐ Monitor failed login attempts
Extensions:
☐ Keep extensions updated
☐ Remove unused extensions
☐ Vet extensions before installation
☐ Check extension security advisories
Monitoring:
☐ Review logs weekly
☐ Monitor for suspicious edits
☐ Set up intrusion detection alerts
☐ Review firewall logs
Backup:
☐ Regular backups (verified)
☐ Offsite backup copy
☐ Test restore procedure
What You Learned
- .htaccess protects sensitive files at the server level
- CSP headers prevent XSS Attacks
- MediaWiki has built-in XSS and CSRF protection
- CAPTCHA stops automated abuse
- File uploads require strict type and MIME checking
- Strong password policies protect user accounts
- Security headers add browser-level protection
- Regular monitoring and updates are essential
Common Mistakes
| Mistake | Why It Happens | How to Fix |
|---|---|---|
| Leaving LocalSettings.php world-readable | Default file permissions not changed | Set permissions: chmod 600 LocalSettings.php. It should only be readable by the web server user. |
| Allowing raw HTML for all users | $wgRawHtml = true | Disable raw HTML: $wgRawHtml = false. If needed, restrict to trusted groups only. |
| Not updating MediaWiki for months | Security patches missed | Subscribe to MediaWiki security announcements. Apply security updates within 48 hours. |
| Installing extensions without checking | Untrusted code on the server | Only install extensions from the official MediaWiki extension registry. Check reviews and maintenance status. |
| Weak admin password | Easy to guess or brute-force | Enforce minimum 14-character passwords for administrators. Use a password manager. Enable two-factor authentication. |
Practice Questions
- What is Content Security Policy and how does it prevent XSS attacks?
- How does the CAPTCHA system prevent automated spam, and what triggers should you enable?
- What file types should you allow for uploads, and which should you explicitly block?
- Challenge: Perform a security audit of your wiki. Review LocalSettings.php for security-related settings. Check .htaccess for directory protection. Verify CSP headers are enabled. Test CAPTCHA by simulating a registration. Review file upload permissions. Check password policy configuration. Review user groups and remove unused administrators. Create a "Security Hardening" page documenting all security measures in place. List any vulnerabilities found and their remediation steps. Finally, create a regular security review schedule.
FAQ
Mini Project
Goal: Perform a complete security audit and hardening of your wiki.
- Review and secure LocalSettings.php permissions (chmod 600)
- Create or update .htaccess to protect sensitive directories
- Configure CSP headers (start in report-only mode)
- Install and configure ConfirmEdit with appropriate triggers
- Review and restrict file upload types
- Enforce strong password policy (12+ chars, no username match)
- Enable email confirmation for editing
- Review all user groups and remove inactive admins
- Enable HTTPS (if not already)
- Set up security monitoring (log review, backup verification)
- Create a "Security Posture" page documenting all hardening measures
- Schedule quarterly security reviews
What's Next
Congratulations — you have completed the full MediaWiki tutorial series. You now have the skills to install, configure, maintain, secure, and scale a MediaWiki wiki for any purpose.
Review the full course on the MediaWiki Tutorials homepage or start building your production wiki using the skills you have learned.
For additional help, explore extensions at the MediaWiki Extension Registry or join the MediaWiki community at mediawiki.org.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro