Varnish WAF


ModSecurity is an open source project started in 2002, currently backed and maintained by SpiderLabs. The main tools in the ModSecurity toolbox are logging, parsing, buffering, and the rule engine. At the start of the application, ModSecurity will parse and classify a set of rules. For each request it will buffer the request and response headers/bodies, parse them against the rule set and finally log all relevant information. The version used for Varinsh WAF, as of writing this, is 3.0.2. To change the settings of ModSecurity edit /etc/varnish/modsec/modsecurity.conf.

Phases of a Request

ModSecurity goes through a specific order of operations, called phase. The phases determine the risk of a request, ensuring protection of a backend. Each phase will either block and finish the request by logging, or continue to the next phase. The phases are as follows:

  1. Request Headers
    • This phase will examine the connecting and host IP addresses, request URL, request protocol, HTTP version, and request headers. The goal of this phase is to is to determine early if the request body should even be buffered or if the request should be rejected right away.
  2. Request Body
    • This phase is guaranteed to have access to all of the request information. Ultimately this phase can parse the request body, or any other request information. Most of the application-oriented rules should go here. The following encoding types are supported: text/xml, multipart/form-data and application/x-www-form-urlencoded.
    • In order to access the Request Body, you must have SecRequestBodyAccess set to On.
    • The maximum size of the request body and the action of what should happen when that size is hit are set by SecRequestBodyLimit and SecRequestBodyLimitAction.
  3. Response Headers
    • This phase acts similarly to phase 1 but for the response. This phase will read the response headers, determine if there are reasons to block the request, and determine if the response body should be buffered.
  4. Response Body
    • This phase will have access to all of the response by this point. The response body will be parsed and it will decide if the request should continue to the user.
    • In order to access the Response Body, you must have SecResponseBodyAccess set to On.
    • The maximum size of the response body and the action of what should happen when that size is hit are set by SecResponsetBodyLimit and SecResponseBodyLimitAction.
    • The response body buffering can also be restricted by content type with SecResponseBodyMimeType.
  5. Logging
    • The final phase finishes up the request. This phase cannot block requests. Rules in this phase will determine how the logging should be done. Logging can be done in two places, the Debug log and the Audit log.


ModSecurity’s logging is generally verbose and resource expensive. It is suggested to use logging in the testing phase of an application but disable it once it reaches production. This is acceptable because Varnish contains a much more efficient logging system. On a disruptive action, Varnish will log information from ModSecurity about the request. There are two types of logs: debug and audit.

Debug Log

This is a verbose log on everything ModSecurity does for a request. This tool is best used testing, troubleshooting or for learning how ModSecurity interacts with an application. The path to the debug log is set with SecDebugLog. There are 7 levels of logging, (1-6, 9) that can be set with SecDebugLogLevel:

  1. No logging.
  2. Log errors (intercepted requests) only.
  3. Log warnings.
  4. Log notices.
  5. Log details of how transactions are handled.
  6. The same as above, but including information about each piece of information handled.
  7. Log everything, including very detailed debugging information.

Audit Log

This is a log to track the data of a HTTP request. This is less verbose than the debug log but still resource expensive. SecAuditEngine determines if the audit log should be used. It can be set to On, Off or RelevantOnly. SecAuditEngine defaults to false. RelevantOnly will log for specific response codes set by SecAuditLogRelevantStatus. This defaults to ^(?:5|4(?!04)). The audit log is broken down into 12 parts, A-K, and Z. All but two are optional. The parts are:

  • A: Audit log header (mandatory).
  • B: Request headers.
  • C: Request body (if SecRequestBodyAccess is set to on).
  • D: Reserved for intermediary response headers; not implemented yet.
  • E: Intermediary response body (if SecResponseBodyAccess is set to On).
  • F: Final response headers (excluding the Date and Server headers).
  • G: Reserved for the actual response body; not implemented yet.
  • H: Audit log trailer.
  • I: This part is a replacement for part C. It will log the same data as C in all cases except when multipart/form-data encoding in used.
  • J: This part contains information about the files uploaded using multipart/form-data encoding.
  • K: This part contains a full list of every rule that matched (one per line) in the order they were matched. The rules are fully qualified and will thus show inherited actions and default operators.
  • Z: Final boundary, signifies the end of the entry (mandatory).

State Diagram of the Phases of a Request