IskWaf - Web Application Firewall for MODX 3

Author: Ivan Sergeevich K. (ivan@iskwaf.com)
Website in Russian: iskwaf.ru
Website in English: iskwaf.com

IskWaf is a component for MODX Revolution 3.x, representing a simple yet flexible Web Application Firewall (WAF). It is designed to provide basic protection for your site against some common threats, unwanted bots, and suspicious activity by applying a set of customizable rules. The component also includes detailed logging, a reporting system, the ability to determine IP geolocation, and optional WAF check modes to optimize performance.

Key Features

  • Multi-layered Security Rules:
    • IP Address/CIDR (with priority for exact IP match over subnet).
    • Country (with exceptions for trusted bots).
    • User-Agent (types: contains, exact match, regular expression).
    • Referrer (types: contains, exact match, regular expression).
    • Request URI (types: contains, exact match, regular expression, starts with; with or without query string matching).
  • Intelligent Rule Automation:
    • Automatic creation of allow rules for subnets of trusted bots (Google, Yandex, etc.).
    • Automatic creation of block rules for subnets of unwanted hosters/proxies.
    • Rules are generated based on Autonomous System (ASN) data via CRON.
  • Realtime checks (no waiting for CRON):
    • Country resolved directly from the local IP2Location database at request time (iskwaf_country_check_mode = realtime).
    • Instant block/allow by ASN and company name (iskwaf_enable_realtime_asn_rules), without waiting for CRON.
  • Country whitelist: allow traffic only from listed countries, blocking all others (iskwaf_allowed_countries); takes precedence over the blacklist.
  • Search bot verification: hybrid ASN + DNS (rDNS/fDNS) method. Verified Google/Yandex/Bing/Apple/DuckDuckGo bots bypass country and ASN blocking.
  • CSV export/import of rules: export and import rules (IP, User-Agent, Referrer, Request URI) right from the interface; import via the standard MODX file manager, with per-row validation.
  • Request inspection (SQL injection protection): checks GET/POST/Cookie values (and optionally the request body) against configurable attack signatures, with "log only" and "block" modes.
  • Flexible Rule Actions: Block (403), CAPTCHA, Allow.
  • Local CAPTCHA: Numeric, with a "first/last 3 digits" task from a 6-digit image, session-based.
  • Optional WAF Check Modes:
    • Check on every request (standard behavior).
    • Check once per session (reduces load for already verified users).
  • Logging System: Detailed WAF trigger logs, configurable modes (`full`, `triggered`, `off`), automatic old log cleanup. Logs also reflect if WAF rules were skipped due to the "once per session" mode.
  • IP Address Analysis: Determination of country, region, city, ASN, and ISP for IP addresses from logs using local IP2Location LITE databases (via CRON).
  • Daily Reports: Aggregated statistics on WAF events, rule types, search engine bot hits, top-N offenders (in JSON), including geolocation data.
  • Management Interface (CMP): Tabs for logs (displaying country/city), each rule type, and reports; create, edit, enable/disable, delete rules.

Installation

  1. Upload the component package via the "Installer" (Extras -> Installer) in the MODX manager.
  2. Find the "IskWaf" package and click "Install".
  3. Follow the on-screen instructions.

Configuration

After installing the component, you need to configure a few system settings, a page for CAPTCHA, and prepare the environment for GeoIP databases.

1. System Settings

Find them in "System" (cog icon) -> "System Settings", selecting the iskwaf namespace.

Key Description Possible Values/Action
iskwaf_iskwaf_captcha_resource_id MODX Resource ID for displaying the CAPTCHA page. Create a new MODX resource (e.g., with alias captcha-verify), ensure it is not cacheable. In the "Resource Content" field, place the snippet call [[!IskWafCaptcha]]. Specify the ID of this resource here.
iskwaf_iskwaf_option_log WAF Logging Mode.
  • full: (Default) All requests are logged (triggered rules + normal visits, including those where rules were skipped due to session check).
  • triggered: Only requests that trigger a rule are logged. May optionally log when rules are skipped due to session check (see plugin code).
  • off: Logging is disabled (but rules continue to operate).
iskwaf_waf_check_mode WAF Rule Check Mode.
  • on_every_request: (Default) WAF rules are checked on every request.
  • once_per_session: WAF rules are checked for a user only once per session. If the check is passed, subsequent requests in the same session do not undergo full WAF checking (but visits may be logged according to the iskwaf_iskwaf_option_log setting).
iskwaf_iskwaf_log_retention_days Number of days to retain records in the iskwaf_logs log. Old records are deleted by a CRON script. Number (e.g., 7, 30). Default in script: 7.
iskwaf_ip2location_download_token Your personal token for downloading databases from the IP2Location website. Obtain the token after registering at lite.ip2location.com and enter it here.
iskwaf_ip_analysis_limit_per_run Maximum number of new/outdated IPs to analyze per single run of the analyze_ip2location_details.php CRON script. Number. Default in script: 500.
iskwaf_ip_analysis_update_interval Frequency in days for updating information for an IP already existing in the details table. Number. Default in script: 30.
Automatic Rule Management & Country Blocking
iskwaf_iskwaf_country_check_mode Country check mode
  • cached (default): country is taken from the details table populated by CRON. Fast, but new IPs are only blocked after the cron run.
  • realtime: country is resolved by querying the local IP2Location database at request time — blocking is instant; the result is written back to the table. Requires geoip_db/IP2LOCATION-LITE-DB11.BIN.
iskwaf_iskwaf_blocked_countries Blocked Countries (blacklist) Comma-separated two-letter country codes (ISO 3166-1 alpha-2). Traffic from these countries is blocked (except trusted bots). Example: CN,RU,KP. Ignored if a whitelist is set.
iskwaf_iskwaf_allowed_countries Allowed Countries (whitelist) If filled, only traffic from the listed countries is allowed; all others are blocked (trusted bots still pass). Takes precedence over the blacklist. Example: RU,BY,KZ. If an IP cannot be resolved to a country, it is not blocked (fail-open).
iskwaf_iskwaf_enable_dns_verification Search bot verification If "Yes", the WAF verifies Google/Yandex/Bing/Apple/DuckDuckGo bots. A verified bot bypasses all rules, including country blocking. Strongly recommended when country blocking is used.
iskwaf_iskwaf_bot_verification_method Bot verification method asn_dns (default) — fast local ASN check first, then DNS as a fallback; asn — ASN only (no external DNS; requires IP2LOCATION-LITE-ASN.BIN); dns — double DNS check only (rDNS+fDNS).
iskwaf_iskwaf_auto_allow_as_names Allowed Company Names (AS Name) Company names (ASN) that are allowed. Highest priority: checked in realtime and before country blocking — such companies are not blocked even if their country is blacklisted. Delimiter — |. Example: Google LLC|Cloudflare. Also used by CRON to auto-create /24 rules.
iskwaf_iskwaf_auto_allow_as_numbers Allowed AS Numbers (ASN) AS numbers that are allowed. Highest priority (as above). Delimiter — |. Example: AS15169|AS13238
iskwaf_iskwaf_auto_block_as_names Blocked Company Names (AS Name) Company names (ASN) to block. Delimiter — |. Example: DigitalOcean|OVH
iskwaf_iskwaf_auto_block_as_numbers Blocked AS Numbers (ASN) AS numbers to block. Delimiter — |. Example: AS14061|AS16276
iskwaf_iskwaf_enable_realtime_asn_rules Realtime ASN checks Controls instant ASN blocking at request time (without waiting for CRON). Allow lists always work regardless of this option. Requires geoip_db/IP2LOCATION-LITE-ASN.BIN.
iskwaf_iskwaf_csv_delimiter CSV delimiter (rules export) Column delimiter for exporting rules. Default ; (so Excel opens columns correctly). Allowed: ;, , or tab. On import the delimiter is auto-detected or chosen in the import dialog.

Request Inspection Settings (SQL injection protection)

A separate group of settings (the "Request inspection" area). The module is disabled by default.

KeyDescriptionPossible Values
iskwaf_iskwaf_payload_inspection_mode Request payload inspection mode. off (default) — disabled; log — only record hits to the log; block — block the request (403). Recommended to run log first to tune signatures.
iskwaf_iskwaf_payload_scan_sources Which inputs to inspect. Comma-separated from: get, post, cookie, body (raw body). Default: get,post,cookie.
iskwaf_iskwaf_payload_max_body Max body size to inspect (bytes). Number. Default 262144 (256 KB).
iskwaf_iskwaf_payload_signatures Signatures (regular expressions). One expression per line (lines starting with # are comments). Case-insensitive, pattern delimiter is ~. If empty, a built-in set for common SQL injections is used.

2. CAPTCHA Page

As mentioned above, create a MODX resource to display the CAPTCHA. It should be non-cacheable and contain the snippet call [[!IskWafCaptcha? &tpl=`your_form_chunk_name`]] (the `&tpl` parameter is optional, defaults to `iskWafCaptchaFormTpl`).

3. GeoIP Setup (IP2Location)

The IskWaf component uses IP2Location LITE databases to determine geolocation, ASN, and other information for IP addresses. The database files themselves are not included in the component installation package but are downloaded using a special CRON script.

  1. Get Token: Register at lite.ip2location.com and obtain your personal download token. Enter it into the iskwaf_ip2location_download_token system setting.
  2. IP2Location PHP Library:

    To work with IP2Location BIN database files, the appropriate PHP library is required. The IskWaf component uses PHP library files that should be placed in the core/components/iskwaf/lib/ip2location/src/ folder. You can download the "IP2Location PHP Module" (for BIN Data File) from the official IP2Location website and place the contents of its `src` folder in the specified path.

  3. Directories for Databases: Ensure that the following directories exist on the server and are writable by PHP (relative to core/components/iskwaf/):
    • tmp_db_download/ (for temporary files during download)
    • geoip_db/ (for storing unpacked BIN database files)
  4. Initial Database Download: After setting up the token and placing the PHP library, run the ip2location_download.php CRON script (see below) once manually from the server's command line for the initial download of the databases (IP2LOCATION-LITE-DB11.BIN and IP2LOCATION-LITE-ASN.BIN).

4. CRON Jobs

For automatic component operation, set up three CRON jobs:

Downloading/Updating GeoIP Databases (IP2Location):
  • Script: core/components/iskwaf/elements/cron/ip2location_download.php
  • Frequency: Recommended once a month (e.g., on the 1st of each month).
  • Example command: /usr/bin/php /path/to/your/site/core/components/iskwaf/elements/cron/ip2location_download.php
Analyzing IPs, populating GeoIP details, and auto-creating rules:
  • Script: core/components/iskwaf/elements/cron/analyze_ip2location_details.php
  • Frequency: Recommended every 5-15 minutes for timely rule creation.
  • Example command: /usr/bin/php /path/to/your/site/core/components/iskwaf/elements/cron/analyze_ip2location_details.php
Cleaning up old logs:
  • Script: core/components/iskwaf/elements/cron/clear_log.php
  • Frequency: Recommended once daily.
  • Example command: /usr/bin/php /path/to/your/site/core/components/iskwaf/elements/cron/clear_log.php
Generating Reports:
  • Script: core/components/iskwaf/elements/cron/reports_daily.php
  • Frequency: Recommended once daily.
  • Example command: /usr/bin/php /path/to/your/site/core/components/iskwaf/elements/cron/reports_daily.php

Ensure the paths to the PHP interpreter and scripts are correct for your server.

Usage (CMP)

Access the IskWaf management interface via the main MODX manager menu (usually in the "Extras" or "Applications" section).

  • "Logs" Tab: View all WAF log entries with search. "Country" and "City" columns are shown, plus an "Injection" column (marked "YES" for request-inspection hits).
  • Rule Tabs (IP, User-Agent, Referrer, Request URI): Manage rules, plus "Export CSV" and "Import CSV" buttons to export/import rules.
  • "Report" Tab: View daily summary reports.

Rule Types (Detailed)

IP Rules

Designed to block, allow, or show CAPTCHA based on the visitor's IP address or CIDR subnet.

  • Fields: IP/CIDR, Rule Type (action), Description, Active.
  • Priority Logic: An exact IP match takes precedence over a CIDR subnet. Among CIDR subnets containing the same IP, the narrower one (largest mask) takes precedence.
Pattern Examples for IP/CIDR:
  • Single IPv4: 192.168.1.100
  • IPv4 CIDR (subnet): 10.0.0.0/8
  • IPv6 CIDR: 2001:db8::/32

Country Blocking (black/white list)

This is not a separate rule type in the interface but a built-in WAF mechanism. Two list modes are supported:

  • Blacklist (iskwaf_iskwaf_blocked_countries): traffic from the listed countries is blocked.
  • Whitelist (iskwaf_iskwaf_allowed_countries): if set, only the listed countries are allowed and all others are blocked. The whitelist takes precedence over the blacklist (when a whitelist is set, the blacklist is ignored).
  • Country resolution mode: depends on iskwaf_iskwaf_country_check_modecached (from the details table populated by CRON) or realtime (direct IP2Location lookup at request time; new IPs are blocked instantly).
  • Exceptions: verified search bots and companies in the ASN allow lists pass even if the country is blocked (see below).
  • If the country cannot be resolved (not in the database), the IP is not blocked (fail-open) so that unidentified addresses are not cut off.
  • In the log, such a block records the reason, mode and source in the notes, e.g.: Reason: country not in whitelist. Mode: realtime (source: table).

User-Agent Rules

Allow applying actions based on the User-Agent string.

  • Fields: User-Agent Pattern, Pattern Type ('contains', 'exact', 'regex'), Rule Type (action), Description, Active.
Pattern Examples for User-Agent Pattern:
  • Type: contains, Pattern: AhrefsBot
  • Type: regex, Pattern: /^EvilCorp Crawler\/[0-9\.]+/i

Referrer Rules

Filter requests based on the HTTP Referrer.

  • Fields: Referrer Pattern, Pattern Type ('contains', 'exact', 'regex'), Rule Type (action), Description, Active.
Pattern Examples for Referrer Pattern:
  • Type: contains, Pattern: spam-site.com
  • Type: regex, Pattern: /^https?:\/\/([\w-]+\.)*spammerdomain\.com/i

Request URI Rules

Apply actions based on the requested URI.

  • Fields: URI Pattern, Pattern Type ('contains', 'exact', 'regex', 'starts_with'), Match Query String (yes/no), Rule Type (action), Description, Active.
Pattern Examples for URI Pattern:
  • Type: exact, Query String: no, Pattern: /wp-login.php
  • Type: starts_with, Query String: no, Pattern: /admin-backup/
  • Type: contains, Query String: yes, Pattern: eval(

Search Bot Verification

To prevent genuine search bots from being caught by blocking (by country, ASN, etc.), IskWaf verifies their authenticity. The check runs at the very beginning of request processing: if a bot is verified, it bypasses all rules.

  • Enable: the iskwaf_iskwaf_enable_dns_verification setting = "Yes".
  • Hybrid method (iskwaf_iskwaf_bot_verification_method):
    • asn_dns (default) — first a fast local ASN check against the IP2Location database (Googlebot=AS15169, YandexBot=AS13238, bingbot=AS8075, Applebot=AS714), then, if needed, a double DNS check (rDNS+fDNS) as a fallback;
    • asn — ASN only (no external DNS, faster);
    • dns — rDNS+fDNS only (as in previous versions).
  • Caching: a successful verification of an IP is cached for 24 hours.
  • Supported bots: Google, Yandex, Bing, Apple, DuckDuckGo (the latter — DNS only).

A spoofer with the "YandexBot" UA but not from Yandex's network will fail verification and fall under the regular rules.

ASN Rules & Priorities

Besides auto-creating /24 rules via CRON, IskWaf can make decisions by ASN/company name right at request time (requires geoip_db/IP2LOCATION-LITE-ASN.BIN).

  • Allow lists (iskwaf_iskwaf_auto_allow_as_names / ..._numbers) — highest priority: they always apply (regardless of the realtime-block option) and before country blocking. A trusted company is not blocked even if its country is blacklisted (or not in the whitelist).
  • Block lists (..._block_as_names / ..._numbers) — instant blocking is enabled by the iskwaf_iskwaf_enable_realtime_asn_rules option.
  • Priority: allow is checked first, then block.
  • In the log: Rule type: asn ... Match: allow by AS name. Mode: realtime (source: ip2location_db|table).

CSV Export & Import of Rules

Each rule tab (IP, User-Agent, Referrer, Request URI) has "Export CSV" and "Import CSV" buttons.

  • Export: exports all rules of the selected type to CSV (with a BOM for correct Cyrillic in Excel). The delimiter is set by iskwaf_iskwaf_csv_delimiter (default ;).
  • Import: the file is chosen via the standard MODX file manager (a new one can be uploaded too) and read on the server. The delimiter is auto-detected or chosen in the dialog.
  • Validation on import: each row is checked (IP/CIDR format, pattern type, regex compilability, rule type). Invalid rows are skipped with a line number and reason, valid ones are imported.
  • On-duplicate mode: "skip duplicates" or "update existing".
  • On completion a summary is shown: added / updated / skipped / errors.

Request Inspection (SQL injection protection)

An additional defence-in-depth layer: inspecting request inputs against attack signatures (primarily SQL injections). This is not a replacement for fixing vulnerable code, but a compensating control. Disabled by default.

  • What is inspected: GET, POST, Cookie values and (optionally) the raw request body — the iskwaf_iskwaf_payload_scan_sources setting.
  • Modes (iskwaf_iskwaf_payload_inspection_mode): off — disabled; log — log only; block — 403. Run log first, tune signatures, and only then switch to block.
  • Signatures (iskwaf_iskwaf_payload_signatures): one regex per line; empty → a built-in set for common SQLi (UNION SELECT, INFORMATION_SCHEMA, SLEEP(, BENCHMARK(, ORD(MID(, UPDATEXML(, etc.). Values are normalized (raw/urldecode) before matching.
  • Logging: hits are written to the main log (triggered_rule = payload); the "Logs" tab has an "Injection" column marked "YES", with the pattern, source and parameter in the notes.
  • Note: broad signatures cause false positives. For requests to component connectors (which may not fire OnHandleRequest) you can include the iskwaf-guard.php file.

CAPTCHA System

IskWaf uses a local numeric CAPTCHA. An image with 6 digits is generated, and the user is asked to enter either the first or last three digits. Completion is remembered in the session. Displayed via the [[!IskWafCaptcha]] snippet (supports &tpl).

Reporting System

Daily summaries in IskWafReportDaily include: total WAF events, blocks, CAPTCHAs, rule allowances, triggers by rule type, search engine bot hits, top N IPs and rules (JSON). Generated by a CRON script.

This product includes IP2Location LITE data available from https://lite.ip2location.com.

Important Notes

Please Note

  • Order of Rule Execution: Bot verification → Request inspection (SQLi) → IP Rules → ASN (allow/block) → Country Blocking → User-Agent → Referrer → Request URI. The first triggered rule determines the action.
  • Regular Expressions: Must include delimiters/flags (e.g., /badbot/i). Test thoroughly.
  • Visitor's IP Address: Uses $_SERVER['REMOTE_ADDR'] by default. Adapt for sites behind a proxy.
  • Performance: A large number of rules or full logging mode can impact performance.
  • False Positives: Possible. Review logs regularly.

Disclaimer

IskWaf is a tool for basic protection and is not a substitute for comprehensive enterprise security solutions or specialized WAF services. Use it at your own risk. It is always recommended to have up-to-date backups of your site.