Web Application Firewall for SPIP. Blocks malicious requests and bans repeat offenders.
Installation
SPIP WAF is installed like any other SPIP plugin. It requires the PHP-extension APCU enabled.
Most servers have APCU enabled by default. The plugin will refuse to install if APCU is not found. So you can try installing, and if it fails, check if you can find instructions on how to enable/install php-apcu for your hosting provider.
Background
SPIP is a secure CMS with a strong track record in terms of security and stability. At the same time, webmasters see an increased flood of malicious server attacks. This plugin will block malicious requests and help protect sites from malicous traffic.
How it works
- Rules check every request for suspicious patterns (SQL injection, path traversal, CMS probes, etc.)
- Each violation is blocked and logged.
- After several violations (
_WAF_STRIKE_THRESHOLD), the IP gets banned. - Banned visitors see an unblock form (useful for false positives).
- If they keep triggering rules after unblocking, they get banned again.
- After too many bans (
_WAF_BLOCK_THRESHOLD), the IP is permanently hard-blocked. In this case, users (bots) see a plain 403 error.
Flow: Blocked → Banned → Hard-blocked
Full docs: https://contrib.spip.net/WAF (coming soon)
Locked out?
If you got hard-blocked (e.g. after testing with malicious payloads), whitelist your IP via mes_options.php.
Find your IP at https://iplocation.net (looks like 203.0.113.42).
Tip: If you can’t access the site at all, switch to a different network (e.g. phone hotspot), log into /ecrire from there, and add your IP in the WAF config form. Then switch back.
To whitelist via code, add this to config/mes_options.php (create the file if needed):
define('_WAF_WHITELIST', '203.0.113.42');
Multiple IPs, one per line:
define('_WAF_WHITELIST',
'203.0.113.42
198.51.100.7
198.51.100.8'
);
Once saved, the WAF lets these IPs through.
Custom rules
The plugin exposes a waf_custom_rules pipeline. Define your rule function in mes_options.php and hook it into the pipeline.
Block a specific GET parameter:
function waf_custom_rule__block_foo_bar($ctx) {
if (isset($ctx['get']['foo']) && $ctx['get']['foo'] === 'bar') {
waf_handle_violation('CUSTOM_RULE', 'foo=bar', $ctx['client_ip']);
}
}
$GLOBALS['spip_pipeline']['waf_custom_rules'] = '|waf_custom_rule__block_foo_bar';
Block e.g. ?page=spipdf (when the SPIPDF plugin is not installed):
function waf_custom_rule__block_spipdf($ctx) {
if (isset($ctx['get']['page']) && $ctx['get']['page'] === 'spipdf') {
waf_handle_violation('CUSTOM_RULE', 'blocked_param=page, value=spipdf', $ctx['client_ip']);
}
}
$GLOBALS['spip_pipeline']['waf_custom_rules'] .= '|waf_custom_rule__block_spipdf';
Disabling rules
The waf_handle_violation pipeline lets you ignore specific violations. Return true to skip the violation.
Example: allow <script> tags when editing articles in the back-office:
function waf_override__allow_script_in_articles($ctx) {
$args = $ctx['args'];
if (
isset($args['get']['exec']) && $args['get']['exec'] === 'article_edit'
&& $args['reason'] === 'PATTERN_MATCH'
&& (
$args['pattern'] == '/<script/i'
|| $args['pattern'] == '/<\/script>/i'
)
) {
return true;
}
return false;
}
$GLOBALS['spip_pipeline']['waf_handle_violation'] = '|waf_override__allow_script_in_articles';
Profiling
Add to config/mes_options.php:
define('_WAF_PROFILE', microtime(true));
define('_LOG_FILTRE_GRAVITE', _LOG_INFO);
The second line is required if _LOG_FILTRE_GRAVITE is not defined, in order to set the proper log leve. Otherwise, no log output is written.
Each request logs one line to tmp/log/waf.log:
WAF_PROFILE PASS total:3.42ms fn:1.18ms
WAF_PROFILE VIOLATION total:5.01ms fn:2.73ms
- total — time from the
define()to the WAF exit (includes SPIP bootstrap) - fn — time inside
waf()only - Outcomes:
PASS,WHITELISTED,NO_IP,BLACKLISTED,BLOCKLISTED,HARDBLOCKED,BANNED,UNBLOCK_REDIRECT,VIOLATION
Remove both lines when done.
CLI stats
Stats for a given outcome (replace PASS with any outcome) for MIN, AVERAG; MAX:
For basic min, average, max stats:
grep 'WAF_PROFILE PASS ' tmp/log/waf.log | grep -oP 'fn:\K[0-9.]+' | awk '{s+=$1;n++;if(!min||$1<min)min=$1;if($1>max)max=$1} END{printf "n=%d min=%.2fms avg=%.2fms max=%.2fms\n",n,min,s/n,max}'
For Percentiles (p50/p95/p99): (This bash code is run in the the root directory of the SPIP install).
#go to root directory of SPIP install:
cd /var/www/html
It loops over the possible outcomes and lists the stats.
#Output percentiles per outcome:
for outcome in PASS WHITELISTED NO_IP BLACKLISTED BLOCKLISTED HARDBLOCKED BANNED UNBLOCK_REDIRECT VIOLATION; do
echo ""
echo "--- $outcome ---"
grep "WAF_PROFILE $outcome " tmp/log/waf.log \
| grep -oP 'fn:\K[0-9.]+' \
| sort -n \
| awk '{a[NR]=$1} END{
printf "n=%d p50=%.2fms p95=%.2fms p99=%.2fms\n",
NR,
a[int(NR*0.50)+1],
a[int(NR*0.95)+1],
a[int(NR*0.99)+1]
}'
done
Overview of all outcome types in the log:
grep -oP 'WAF_PROFILE \K\S+' tmp/log/waf.log | sort | uniq -c | sort -rn


No discussion
Add a comment
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Follow the comments:
|
