Protecting Your Site with kusanagi waf (ModSecurity/NAXSI) 

福田拓朗

KUSANAGI comes with a built-in Web Application Firewall (WAF) feature. 
In this article, we’ll walk you through how to use this feature, as well as how to investigate potential causes when errors occur. 

Benefits of Introducing a WAF

WAF stands for Web Application Firewall, and it serves as a protective layer for web applications such as WordPress. 
It helps prevent malicious access attempts that exploit known vulnerabilities—like SQL injection or directory traversal—before they reach the application layer (e.g., PHP). 

By blocking suspicious requests at the web server level, WAF reduces the risk of damage from unpatched vulnerabilities. 

We’ve briefly touched on this topic before in our article “Preparing for attacks with WAF”, but this time we’ll take a deeper dive into its setup and troubleshooting. 

How to Enable WAF in KUSANAGI

KUSANAGI includes a built-in WAF feature out of the box. 
It uses NAXSI for nginx and ModSecurity for Apache. 
Note, however, that WAF is not enabled by default, so you’ll need to activate it manually. 

You can enable it with a single command: 

kusanagi waf on

During the first execution, KUSANAGI will automatically install any necessary packages. 
If the setup is successful, you should see the following messages at the end: 

restart completed.
waf completed.

How to Analyze Errors with NAXSI on nginx 

Once you’ve enabled WAF, you may occasionally encounter errors such as 403 Forbidden when accessing your site. In this section, we’ll explain how to analyze and resolve such issues. 

Note: KUSANAGI includes NAXSI rules optimized for WordPress by default, so the example error below won’t normally occur. For demonstration purposes, these default rules have been disabled. 

Step 1: Check the nginx Error Log

NAXSI WAFによる403画面

If you see a 403 Forbidden page, the first step is to check the nginx error log for the corresponding profile. 

  • For regular access errors: 
    /home/kusanagi/(profile_name)/log/nginx/error.log 
  • For HTTPS-related errors: 
    /home/kusanagi/(profile_name)/log/nginx/ssl_error.log 

Here’s an example of an actual log entry: 

2023/07/21 08:36:23 [error] 7432#7432: *1 NAXSI_FMT: ip=192.0.2.1&server=example.com.internal&uri=/wp-login.php&vers=1.3&total_processed=1&total_blocked=1&config=block&cscore0=$XSS&score0=16&zone0=HEADERS&id0=1315&var_name0=cookie, client: 50.5.35.41, server: example.com.internal, request: "GET /wp-login.php?action=logout&_wpnonce=facec0ed55 HTTP/1.1", host: "example.com.internal", referrer: "http://example.com.internal/" 

Look for id0 in the log — in this case, it shows 1315. This indicates the rule ID that triggered the block. If multiple rules were triggered, you’d see id1, id2, and so on. 

Step 2: Look Up the Rule ID

To understand what rule 1315 refers to, open the base rules file: 

/etc/opt/kusanagi/nginx/naxsi.d/naxsi_core.rules.conf 

Search for rule ID 1315. You might find something like this: 

MainRule "rx:%[23]."  "msg:double encoding" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1315;

This rule flags content with double encoding as a potential XSS threat and increases the risk score accordingly. 

Step 3: Whitelist the Rule for the Specific Context 

Next, let’s craft an exception rule (whitelist) to prevent this from being triggered in safe cases. 

From the log entry: 

  • zone0=HEADERS tells us the issue occurred in the HTTP headers. 
  • var_name0=cookie indicates the suspicious data was in the Cookie header. 

To bypass this rule only in that context, add the following line: 

BasicRule wl:1315 "mz:$HEADERS_VAR:cookie";
  • wl means whitelist 
  • 1315 is the rule ID to ignore 
  • mz:$HEADERS_VAR:cookie limits the exception to the Cookie field in headers 

Step 4: Apply the Rule and Restart nginx

Place the whitelist rule into the following file: 

/etc/opt/kusanagi/nginx/naxsi.d/wordpress/user.conf 

Then restart nginx: 

kusanagi nginx 

After restarting, confirm that the issue is resolved. 

Repeat this process whenever false positives occur. 
By refining your rules over time, you can improve both security precision and site usability

How to Analyze Errors with ModSecurity on Apache

While KUSANAGI uses nginx as its default web server, many production environments run on Apache

In this section, we’ll cover how to investigate and respond to errors when using ModSecurity with Apache. 

For this demonstration, we used a specially crafted test script to send requests and intentionally trigger a block screen. 

When ModSecurity detects a suspicious or malformed request, the server responds with a block page and denies access. 

ModSecurity WAFによる403画面

Step 1: Review Apache Error Logs

When a request is blocked, the reason is logged in: 

/home/kusanagi/(profile_name)/log/httpd/error.log 

If the request was made via HTTPS, check: 

ssl_error.log 

These logs often contain a large volume of information. Start by checking the timestamp near the beginning of the line, such as: 

[Fri Jul 21 08:36:23.102987 2023] 
This tells you exactly when the event occurred (in this case, July 21, 2023 at 08:36:23 AM). 
Then, look for lines that mention rule IDs like: 
[id "920220"], [id "920270"], [id "949110"], [id "980130"] 

These indicate which ModSecurity rules were triggered. 

Example Error Log

Here’s a sample log entry (with some parts masked): 

[Fri Jul 21 08:36:23.103004 2023] [security2:error] [pid *****:tid ***************] [client 192.0.2.1:*****] [client 192.0.2.1] ModSecurity: Access denied with code 403 (phase 2). Operator GE matched 5 at TX:anomaly_score. [file "/etc/opt/kusanagi/httpd/modsecurity.d/activated_rules/REQUEST-949-BLOCKING-EVALUATION.conf"] [line "153"] [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.4"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-generic"] [hostname "example.com.internal"] [uri "/"] [unique_id "***************************"] 

This warning means the request included a null character (invalid input) in the query string. 

Such errors are typically triggered by malformed or suspicious inputs. While these may not cause issues with thread-safe software, non-thread-safe software could be vulnerable. Use caution when deciding to whitelist such requests. 

Step 2: Creating an Exception (Whitelist)

In this case, the requests were intentionally crafted and confirmed to be safe, so we’ll create a whitelist rule. 

You may also need the request path, query string, or referrer. These appear toward the end of the log line as: 

  • uri “/path” 
  • data “…” (contains the matched string) 

Now identify which rule IDs to exclude. Ideally, only exclude the minimal necessary rules to avoid weakening your WAF protection. 

For example, let’s say we determined that these two IDs can be safely ignored: 

  • 949110: Inbound anomaly score exceeded 
  • 980130: (not shown in full here, but assumed safe based on context) 

Here’s a sample log for 949110: 

[Fri Jul 21 08:36:23.103004 2023] [security2:error] ... [id "949110"] [msg "Inbound Anomaly Score Exceeded (Total Score: 10)"] ... 

Step 3: Add a Conditional Exception Rule

Two more rule IDs remain (e.g., 920220, 920270). We’ll add a conditional rule that disables them only when the query string or referrer matches a specific pattern, like test_query_string. 

Append the following block to: 

/etc/opt/kusanagi/httpd/modsecurity.d/kusanagi_activated_rules/wordpress/user.conf 

apache 

 <If "%{QUERY_STRING} =~ /.*test_query_string=.*/ || %{HTTP_REFERER} =~ /.*test_query_string=.*/"> 

    SecRuleRemoveById 920220 

    SecRuleRemoveById 920270 

</If> 

This rule tells ModSecurity to remove the specified rules only under tightly defined conditions, reducing the risk of over-whitelisting. 

Step 4: Restart and Verify 

After saving the file, restart Apache using: 

kusanagi httpd 

Then verify that the site loads correctly and the design remains intact. 

By repeating this process and reviewing each blocked request, you can fine-tune your WAF configuration for both security and usability. 

5. Disabling WAF as a last resort 

If you’ve investigated the error using the above methods and still cannot resolve the issue—and only if absolutely necessary—you may disable the WAF entirely using the following command: 

kusanagi waf off 

6. Conclusion

By leveraging the built-in WAF in KUSANAGI, you can operate a more secure website with minimal effort. 

While false positives can occur, they are generally easy to investigate and correct once you get the hang of it. 

We recommend evaluating the trade-off between security and convenience, and considering WAF as a practical solution to harden your web application. 

References

https://code.google.com/archive/p/naxsi/wikis/BasicRule.wiki

https://kusanagi.tokyo/kusanagi9/document/commands/

<< Achieve Ultra-Fast CMS Performance with kusanagi fcache Introducing the “Theme Accelerator” in the KUSANAGI Plugin >>

関連記事

Webサイト運用の課題解決事例100選 プレゼント

Webサイト運用の課題を弊社プロダクトで解決したお客様にインタビュー取材を行い、100の事例を108ページに及ぶ事例集としてまとめました。

・100事例のWebサイト運用の課題と解決手法、解決後の直接、間接的効果がわかる

・情報通信、 IT、金融、メディア、官公庁、学校などの業種ごとに事例を確認できる

・特集では1社の事例を3ページに渡り背景からシステム構成まで詳解