Your IP : 216.73.216.95


Current Path : /usr/share/modsecurity-crs.bk/rules/
Upload File :
Current File : //usr/share/modsecurity-crs.bk/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf

# ------------------------------------------------------------------------
# OWASP ModSecurity Core Rule Set ver.3.0.2
# Copyright (c) 2006-2016 Trustwave and contributors. All rights reserved.
#
# The OWASP ModSecurity Core Rule Set is distributed under
# Apache Software License (ASL) version 2
# Please see the enclosed LICENSE file for full details.
# ------------------------------------------------------------------------

#
# Some protocol violations are common in application layer attacks.
# Validating HTTP requests eliminates a large number of application layer attacks.
#
# The purpose of this rules file is to enforce HTTP RFC requirements that state how
# the client is supposed to interact with the server.
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html



#
# -= Paranoia Level 0 (empty) =- (apply unconditionally)
#


SecRule TX:PARANOIA_LEVEL "@lt 1" "phase:1,id:920011,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
SecRule TX:PARANOIA_LEVEL "@lt 1" "phase:2,id:920012,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
#
# -= Paranoia Level 1 (default) =- (apply only when tx.paranoia_level is sufficiently high: 1 or higher)
#

#
# Validate request line against the format specified in the HTTP RFC
#
# -=[ Rule Logic ]=-
#
# Uses rule negation against the regex for positive security.  The regex specifies the proper
# construction of URI request lines such as:
#
# 	"http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
#
# It also outlines proper construction for CONNECT, OPTIONS and GET requests.
#
# -=[ References ]=-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.1
# http://capec.mitre.org/data/definitions/272.html
#
SecRule REQUEST_LINE "!^(?i:(?:[a-z]{3,10}\s+(?:\w{3,7}?://[\w\-\./]*(?::\d+)?)?/[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?|connect (?:\d{1,3}\.){3}\d{1,3}\.?(?::\d+)?|options \*)\s+[\w\./]+|get /[^?#]*(?:\?[^#\s]*)?(?:#[\S]*)?)$"\
  "msg:'Invalid HTTP Request Line',\
  severity:'WARNING',\
  id:920100,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'2',\
  maturity:'9',\
  accuracy:'9',\
  logdata:'%{request_line}',\
  phase:request,\
  block,\
  t:none,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\
  tag:'CAPEC-272',\
  setvar:'tx.msg=%{rule.msg}',\
  setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'"


#
# Identify multipart/form-data name evasion attempts
#
# There are possible impedance mismatches between how
# ModSecurity interprets multipart file names and how
# a destination app server such as PHP might parse the
# Content-Disposition data:
#
#       filename-parm := "filename" "=" value
#
# -=[ Rule Logic ]=-
# These rules check for the existence of the ' " ; = meta-characters in
# either the file or file name variables.
# HTML entities may lead to false positives, why they are allowed on PL1.
# Negative look behind assertions allow frequently used entities &_;
#
# -=[ Targets, characters and html entities ]=-
#
# 920120: PL1 : FILES_NAMES, FILES
#         ['\";=] but allowed:
#         &[aAoOuUyY]uml); &[aAeEiIoOuU]circ; &[eEiIoOuUyY]acute;
#         &[aAeEiIoOuU]grave; &[cC]cedil; &[aAnNoO]tilde; & '
#
# 920121: PL2 : FILES_NAMES, FILES
#         ['\";=] : ' " ; = meta-characters
#
# -=[ References ]=-
# https://www.owasp.org/index.php/ModSecurity_CRS_RuleID-960000
# http://www.ietf.org/rfc/rfc2183.txt
#
SecRule FILES_NAMES|FILES "(?<!&(?:[aAoOuUyY]uml)|&(?:[aAeEiIoOuU]circ)|&(?:[eEiIoOuUyY]acute)|&(?:[aAeEiIoOuU]grave)|&(?:[cC]cedil)|&(?:[aAnNoO]tilde)|&(?:amp)|&(?:apos));|['\"=]" \
  "msg:'Attempted multipart/form-data bypass',\
  severity:'CRITICAL',\
  id:920120,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'9',\
  accuracy:'7',\
  logdata:'%{matched_var}',\
  phase:request,\
  block,\
  t:none,t:urlDecodeUni,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\
  tag:'CAPEC-272',\
  setvar:'tx.msg=%{rule.msg}',\
  setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'"


#
# Verify that we've correctly processed the request body.
#
# As a rule of thumb, when failing to process a request body
# you should reject the request (when deployed in blocking mode)
# or log a high-severity alert (when deployed in detection-only mode).
#
# -=[ Rule Logic ]=-
# Checks for the existence of the REQBODY_ERROR variable that is created
# by the request body processor if it encounters errors.
#
# -=[ References ]=-
# https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#REQBODY_ERROR
#
SecRule REQBODY_ERROR "!@eq 0" \
  "msg:'Failed to parse request body.',\
  severity:'CRITICAL',\
  id:920130,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'9',\
  accuracy:'9',\
  logdata:'%{REQBODY_ERROR_MSG}',\
  phase:request,\
  block,\
  t:none,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\
  tag:'CAPEC-272',\
  setvar:'tx.msg=%{rule.msg}',\
  setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'"


#
# Strict Multipart Parsing Checks
#
# -=[ Rule Logic ]=-
# By default be strict with what we accept in the multipart/form-data
# request body. If the rule below proves to be too strict for your
# environment consider changing it to detection-only. You are encouraged
# _not_ to remove it altogether.
#
# -=[ References ]=-
# https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#MULTIPART_STRICT_ERROR
#
SecRule MULTIPART_STRICT_ERROR "!@eq 0" \
  "msg:'Multipart request body failed strict validation:\
    PE %{REQBODY_PROCESSOR_ERROR},\
    BQ %{MULTIPART_BOUNDARY_QUOTED},\
    BW %{MULTIPART_BOUNDARY_WHITESPACE},\
    DB %{MULTIPART_DATA_BEFORE},\
    DA %{MULTIPART_DATA_AFTER},\
    HF %{MULTIPART_HEADER_FOLDING},\
    LF %{MULTIPART_LF_LINE},\
    SM %{MULTIPART_SEMICOLON_MISSING},\
    IQ %{MULTIPART_INVALID_QUOTING},\
    IH %{MULTIPART_INVALID_HEADER_FOLDING},\
    FLE %{MULTIPART_FILE_LIMIT_EXCEEDED}',\
  severity:'CRITICAL',\
  id:920140,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'8',\
  accuracy:'7',\
  phase:request,\
  block,\
  t:none,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\
  tag:'CAPEC-272',\
  setvar:'tx.msg=%{rule.msg}',\
  setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'"


#
# Accept only digits in content length
#
# -=[ Rule Logic ]=-
# This rule uses ModSecurity's rule negation against the regex meaning if the Content-Length header
# is NOT all digits, then it will match.
#
# -=[ References ]=-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
#
SecRule REQUEST_HEADERS:Content-Length "!^\d+$" \
  "msg:'Content-Length HTTP header is not numeric.',\
  severity:'CRITICAL',\
  id:920160,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'9',\
  accuracy:'9',\
  phase:1,\
  block,\
  logdata:'%{matched_var}',\
  t:none,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
  tag:'CAPEC-272',\
  setvar:'tx.msg=%{rule.msg}',\
  setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}'"


#
# Do not accept GET or HEAD requests with bodies
# HTTP standard allows GET requests to have a body but this
# feature is not used in real life. Attackers could try to force
# a request body on an unsuspecting web applications.
#
# -=[ Rule Logic ]=-
# This is a chained rule that first checks the Request Method.  If it is a
# GET or HEAD method, then it checks for the existence of a Content-Length
# header.  If the header exists and its payload is either not a 0 digit or not
# empty, then it will match.
#
# -=[ References ]=-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3
#
SecRule REQUEST_METHOD "^(?:GET|HEAD)$" \
  "msg:'GET or HEAD Request with Body Content.',\
  severity:'CRITICAL',\
  id:920170,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'9',\
  accuracy:'9',\
  phase:request,\
  block,\
  logdata:'%{matched_var}',\
  t:none,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
  tag:'CAPEC-272',\
  chain"
	SecRule REQUEST_HEADERS:Content-Length "!^0?$"\
	  "t:none,\
	  setvar:'tx.msg=%{rule.msg}',\
	  setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
	  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}'"


#
# Require Content-Length to be provided with every POST request.
#
# -=[ Rule Logic ]=-
# This chained rule checks if the request method is POST, if so, it checks that a Content-Length
# header is also present.
#
# -=[ References ]=-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.5
#
SecRule REQUEST_METHOD "^POST$" \
  "msg:'POST request missing Content-Length Header.',\
  severity:'WARNING',\
  id:920180,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'9',\
  accuracy:'9',\
  phase:request,\
  block,\
  logdata:'%{matched_var}',\
  t:none,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
  tag:'CAPEC-272',\
  chain"
        SecRule &REQUEST_HEADERS:Content-Length "@eq 0" \
          "t:none,\
          setvar:'tx.msg=%{rule.msg}',\
          setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
          setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}'"


#
# Range Header Checks
#
# 1. Range Header exists and begins with 0 - normal browsers don't do this.
# Automated programs and bots often do not obey the HTTP RFC
#
# -=[ Rule Logic ]=-
# This rule inspects the Range request header to see if it starts with 0.
#
# -=[ References ]=-
# http://www.bad-behavior.ioerror.us/documentation/how-it-works/
#
# 2. Per RFC 2616 -
#    "If the last-byte-pos value is present, it MUST be greater than or equal to the first-byte-pos in that byte-range-spec,
#    or the byte- range-spec is syntactically invalid."
# -=[ Rule Logic ]=-
# This rule compares the first and second byte ranges and flags when the first value is greater than the second.
#
# -=[ References ]=-
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
# http://seclists.org/fulldisclosure/2011/Aug/175
#
SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "(\d+)\-(\d+)\," \
  "capture,\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'Range: Invalid Last Byte Value.',\
   logdata:'%{matched_var}',\
   severity:'WARNING',\
   id:920190,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
   chain"
        SecRule TX:2 "!@ge %{tx.1}" \
		"setvar:'tx.msg=%{rule.msg}',\
		setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
		setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}"


#
# Broken/Malicous clients often have duplicate or conflicting headers
# Automated programs and bots often do not obey the HTTP RFC
#
# -=[ Rule Logic ]=-
# This rule inspects the Connection header and looks for duplicates of the
# keep-alive and close options.
#
# -=[ References ]=-
# http://www.bad-behavior.ioerror.us/documentation/how-it-works/
#
SecRule REQUEST_HEADERS:Connection "\b(keep-alive|close),\s?(keep-alive|close)\b" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'Multiple/Conflicting Connection Header Data Found.',\
   logdata:'%{matched_var}',\
   id:920210,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
   severity:'WARNING',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}"

#
# Check URL encodings
#
# -=[ Rule Logic ]=-
# There are two different chained rules.  We need to separate them as we are inspecting two
# different variables - REQUEST_URI and REQUEST_BODY.  For REQUEST_BODY, we only want to
# run the @validateUrlEncoding operator if the content-type is application/x-www-form-urlencoding.
#
# -=[ References ]=-
# http://www.ietf.org/rfc/rfc1738.txt
#
SecRule REQUEST_URI "\%((?!$|\W)|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'URL Encoding Abuse Attack Attempt',\
   id:920220,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   severity:'WARNING',\
   chain"
     SecRule REQUEST_URI "@validateUrlEncoding" \
       "setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"

SecRule REQUEST_HEADERS:Content-Type "^(application\/x-www-form-urlencoded|text\/xml)(?:;(?:\s?charset\s?=\s?[\w\d\-]{1,18})?)??$" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'URL Encoding Abuse Attack Attempt',\
   id:920240,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   severity:'WARNING',\
   chain"
     SecRule REQUEST_BODY|XML:/* "\%((?!$|\W)|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" "chain"
       SecRule REQUEST_BODY|XML:/* "@validateUrlEncoding" \
         "setvar:'tx.msg=%{rule.msg}',\
          setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
          setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


#
# Check UTF enconding
# We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise
# it will result in false positives.
#
# -=[ Rule Logic ]=-
# This chained rule first checks to see if the admin has set the TX:CRS_VALIDATE_UTF8_ENCODING
# variable in the crs-setup.conf file.
#
SecRule TX:CRS_VALIDATE_UTF8_ENCODING "@eq 1" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'UTF8 Encoding Abuse Attack Attempt',\
   id:920250,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   severity:'WARNING',\
   chain"
     SecRule REQUEST_FILENAME|ARGS|ARGS_NAMES "@validateUtf8Encoding" \
       "setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


#
# Disallow use of full-width unicode as decoding evasions my be possible.
#
# -=[ Rule Logic ]=-
# This rule looks for full-width encoding by looking for %u followed by 2 'f'
# characters and then 2 hex characters. It is a vulnerability that affected
# IIS circa 2007.
# The rule will trigger on %uXXXX formatted chars that are full or half
# width, as explained above. This %uXXXX format is passed as a raw parameter
# and is (seemingly only) accepted by IIS (5.0, 6.0, 7.0, and 8.0). Other
# webservers will only process unicode chars presented as hex UTF-8 bytes.
#
# -=[ References ]=-
# http://www.kb.cert.org/vuls/id/739224
# https://www.checkpoint.com/defense/advisories/public/2007/cpai-2007-201.html
# https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/719
#
SecRule REQUEST_URI|REQUEST_BODY "\%u[fF]{2}[0-9a-fA-F]{2}" \
  "msg:'Unicode Full/Half Width Abuse Attack Attempt',\
   id:920260,\
   severity:'WARNING',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   phase:request,\
   t:none,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-iis',\
   tag:'platform-windows',\
   tag:'attack-protocol',\
   block,\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


#
# Restrict type of characters sent
#
# This is a rule with multiple stricter siblings that grows more
# restrictive in higher paranoia levels.
#
# -=[ Rule Logic ]=-
# This rule uses the @validateByteRange operator to restrict the request
# payloads.
#
# -=[ Targets and ASCII Ranges ]=-
#
# 920270: PL1 : REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
# 	  ASCII 1-255 : Full ASCII range without null character
#
# 920271: PL2 : REQUEST_URI, REQUEST_HEADERS, ARGS and ARGS_NAMES
#         ASCII 9,10,13,32-126,128-255 : Full visible ASCII range, tab, newline
#
# 920272: PL3 : REQUEST_URI, REQUEST_HEADERS, ARGS, ARGS_NAMES and REQUEST_BODY
#         ASCII 32-36,38-126 : Visible lower ASCII range without percent symbol
#
# 920273: PL4 : ARGS, ARGS_NAMES and REQUEST_BODY
#         ASCII 38,44-46,48-58,61,65-90,95,97-122
#               A-Z a-z 0-9 = - _ . , : &
#
# 920274: PL4 : REQUEST_HEADERS without User-Agent, Referer and Cookie
#         ASCII 32,34,38,42-59,61,65-90,95,97-122
#               A-Z a-z 0-9 = - _ . , : & " * + / SPACE
#
# REQUEST_URI and REQUEST_HEADERS User-Agent, Referer and Cookie are very hard
# to restrict beyond the limits in 920272.
#
# 920274 generally has few positives. However, it would detect rare attacks
# on Accept request headers and friends.

SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 1-255" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   block,\
   msg:'Invalid character in request (null character)',\
   id:920270,\
   severity:'CRITICAL',\
   t:none,t:urlDecodeUni,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.error_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


#
# Do not accept requests without common headers.
# All normal web browsers include Host, User-Agent and Accept headers.
# Implies either an attacker or a legitimate automation client.
#

#
# Missing/Empty Host Header
#
# -=[ Rule Logic ]=-
# These rules will first check to see if a Host header is present.
# The second check is to see if a Host header exists but is empty.
#
SecRule &REQUEST_HEADERS:Host "@eq 0" \
  "msg:'Request Missing a Host Header',\
   severity:'WARNING',\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   t:none,\
   pass,\
   id:920280,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_HOST',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var},\
   skipAfter:END_HOST_CHECK"


SecRule REQUEST_HEADERS:Host "^$" \
  "msg:'Empty Host Header',\
   severity:'WARNING',\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   t:none,\
   pass,\
   id:920290,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_HOST',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"

SecMarker END_HOST_CHECK


#
# Empty Accept Header
#
# -=[ Rule Logic ]=-
# This rule checks if an Accept header exists, but has an empty value.
# This is only allowed in combination with the OPTIONS method.
# Additionally, there are some clients sending empty Accept headers.
# They are covered in another chained rule checking the User-Agent.
# This technique demands a separate rule to detect an empty
# Accept header if there is no user agent. This is checked via
# the separate rule 920311.
#
# Exclude some common broken clients sending empty Accept header:
# "Business/6.6.1.2 CFNetwork/758.5.3 Darwin/15.6.0" (CRS issue #515)
# "Entreprise/6.5.0.177 CFNetwork/758.4.3 Darwin/15.5.0" (CRS issue #366)
#
# -=[ References ]=-
# https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/366
#

SecRule REQUEST_HEADERS:Accept "^$" \
  "msg:'Request Has an Empty Accept Header',\
   chain,\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'8',\
   t:none,\
   pass,\
   severity:'NOTICE',\
   id:920310,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT'"
     SecRule REQUEST_METHOD "!^OPTIONS$" \
       "chain"
          SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android Business Enterprise Entreprise" \
            "t:none,\
            setvar:'tx.msg=%{rule.msg}',\
            setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
            setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"

#
# This rule is a sibling of rule 920310.
#
SecRule REQUEST_HEADERS:Accept "^$" \
  "msg:'Request Has an Empty Accept Header',\
   chain,\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'8',\
   t:none,\
   pass,\
   severity:'NOTICE',\
   id:920311,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT'"
     SecRule REQUEST_METHOD "!^OPTIONS$" \
       "chain"
          SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \
            "t:none,\
            setvar:'tx.msg=%{rule.msg}',\
            setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
            setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"


#
# Empty User-Agent Header
#
# -=[ Rule Logic ]=-
# This rules will check to see if the User-Agent header is empty.
#
# Note that there is a second rule, 920320, which will check for
# the existence of the User-Agent header.
#

SecRule REQUEST_HEADERS:User-Agent "^$" \
  "msg:'Empty User Agent Header',\
   severity:'NOTICE',\
   phase:request,\
   t:none,\
   pass,\
   id:920330,\
   rev:'1',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EMPTY_HEADER_UA',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"

#
# Missing Content-Type Header with Request Body
#
# -=[ Rule Logic]=-
# This rule will first check to see if the value of the Content-Length header is
# non-equal to 0. The chained rule is then checking the existence of the
# Content-Type header. The RFCs do not state there must be a
# Content-Type header. However, a request missing a Content-Header is a
# strong indication of a non-compliant browser.
#
# -=[ References ]=-
# http://httpwg.org/specs/rfc7231.html#header.content-type

SecRule REQUEST_HEADERS:Content-Length "!^0$" \
  "msg:'Request Containing Content, but Missing Content-Type header',\
   chain,\
   phase:request,\
   rev:'3',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   t:none,\
   block,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   id:920340,\
   severity:'NOTICE'"
     SecRule &REQUEST_HEADERS:Content-Type "@eq 0" \
       "t:none,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"

# Check that the host header is not an IP address
# This is not an HTTP RFC violation but it is indicative of automated client access.
# Many web-based worms propagate by scanning IP address blocks.
#
# -=[ Rule Logic ]=-
# This rule triggers if the Host header contains all digits (and possible port)
#
# -=[ References ]=-
# http://technet.microsoft.com/en-us/magazine/2005.01.hackerbasher.aspx
#

SecRule REQUEST_HEADERS:Host "^[\d.:]+$" \
  "msg:'Host header is a numeric IP address',\
   phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   t:none,\
   block,\
   logdata:'%{matched_var}',\
   severity:'WARNING',\
   id:920350,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/IP_HOST',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/POLICY/IP_HOST-%{matched_var_name}=%{matched_var}"


# In most cases, you should expect a certain volume of each a request on your
# website. For example, a request with 400 arguments, can be suspicious.
# This file creates limitations on the request.
#
# TODO Look at the rules in this file, and define the sizes you'd like to enforce.
#      Note that most of the rules are commented out by default.
#      Uncomment the rules you need
#


#
# Maximum number of arguments in request limited
#
SecRule &TX:MAX_NUM_ARGS "@eq 1" \
  "chain,\
   phase:request,\
   t:none,\
   block,\
   msg:'Too many arguments in request',\
   id:920380,\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/SIZE_LIMIT'"
     SecRule &ARGS "@gt %{tx.max_num_args}" \
       "t:none,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"

## -- Arguments limits --
#
# Limit argument name length
#
SecRule &TX:ARG_NAME_LENGTH "@eq 1" \
  "chain,\
   phase:request,\
   t:none,\
   block,\
   msg:'Argument name too long',\
   id:920360,\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/SIZE_LIMIT'"
     SecRule ARGS_NAMES "@gt %{tx.arg_name_length}" \
       "t:none,\
        t:length,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"

#
# Limit argument value length
#
SecRule &TX:ARG_LENGTH "@eq 1" \
  "chain,\
   phase:request,\
   t:none,\
   block,\
   msg:'Argument value too long',\
   id:920370,\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/SIZE_LIMIT'"
     SecRule ARGS "@gt %{tx.arg_length}" \
       "t:none,\
        t:length,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"

#
# Limit arguments total length
#
SecRule &TX:TOTAL_ARG_LENGTH "@eq 1" \
  "chain,\
   phase:request,\
   t:none,\
   block,\
   msg:'Total arguments size exceeded',\
   id:920390,\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/SIZE_LIMIT'"
     SecRule ARGS_COMBINED_SIZE "@gt %{tx.total_arg_length}" \
       "t:none,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"


#
# -- File upload limits --
#
# Individual file size is limited
SecRule &TX:MAX_FILE_SIZE "@eq 1" \
  "chain,\
   phase:request,\
   t:none,\
   block,\
   msg:'Uploaded file size too large',\
   id:920400,\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/SIZE_LIMIT'"
     SecRule REQUEST_HEADERS:Content-Type "@beginsWith multipart/form-data" \
       "chain"
         SecRule REQUEST_HEADERS:Content-Length "@gt %{tx.max_file_size}" \
           "t:none,\
            setvar:'tx.msg=%{rule.msg}',\
            setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
            setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"

#
# Combined file size is limited
#
SecRule &TX:COMBINED_FILE_SIZES "@eq 1" \
  "chain,\
   phase:request,\
   t:none,\
   block,\
   msg:'Total uploaded files size too large',\
   id:920410,\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/SIZE_LIMIT'"
     SecRule FILES_COMBINED_SIZE "@gt %{tx.combined_file_sizes}" \
       "t:none,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/SIZE_LIMIT-%{matched_var_name}=%{matched_var}"



#
# Restrict which content-types we accept.
#
SecRule REQUEST_METHOD "!^(?:GET|HEAD|PROPFIND|OPTIONS)$" \
  "phase:request,\
   chain,\
   t:none,\
   block,\
   msg:'Request content type is not allowed by policy',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:920420,\
   severity:'CRITICAL',\
   logdata:'%{matched_var}',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/ENCODING_NOT_ALLOWED',\
   tag:'WASCTC/WASC-20',\
   tag:'OWASP_TOP_10/A1',\
   tag:'OWASP_AppSensor/EE2',\
   tag:'PCI/12.1'"
     SecRule REQUEST_HEADERS:Content-Type "^([^;\s]+)" \
       "chain,\
        capture"
          SecRule TX:0 "!^%{tx.allowed_request_content_type}$" \
            "t:none,\
             ctl:forceRequestBodyVariable=On,\
             setvar:'tx.msg=%{rule.msg}',\
             setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
             setvar:tx.%{rule.id}-OWASP_CRS/POLICY/CONTENT_TYPE_NOT_ALLOWED-%{matched_var_name}=%{matched_var}"

#
# Restrict protocol versions.
#
SecRule REQUEST_PROTOCOL "!@within %{tx.allowed_http_versions}" \
  "phase:request,\
   t:none,\
   block,\
   msg:'HTTP protocol version is not allowed by policy',\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:920430,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/PROTOCOL_NOT_ALLOWED',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A6',\
   tag:'PCI/6.5.10',\
   logdata:'%{matched_var}',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/POLICY/PROTOCOL_NOT_ALLOWED-%{matched_var_name}=%{matched_var}"

#
# Restrict file extension
#
SecRule REQUEST_BASENAME "\.(.*)$" \
  "chain,\
   capture,\
   phase:request,\
   t:none,t:urlDecodeUni,t:lowercase,\
   block,\
   msg:'URL file extension is restricted by policy',\
   severity:'CRITICAL',\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:920440,\
   logdata:'%{TX.0}',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/EXT_RESTRICTED',\
   tag:'WASCTC/WASC-15',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',logdata:'%{TX.0}',\
   setvar:tx.extension=.%{tx.1}/"
     SecRule TX:EXTENSION "@within %{tx.restricted_extensions}" \
       "t:none,\
        setvar:'tx.msg=%{rule.msg}',\
        setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
        setvar:tx.%{rule.id}-OWASP_CRS/POLICY/EXT_RESTRICTED-%{matched_var_name}=%{matched_var}"

#
# Restricted HTTP headers
#
# -=[ Rule Logic ]=-
# The use of certain headers is restricted. They are listed in the variable
# TX.restricted_headers.
#
# The headers are transformed into lowercase before the match.  In order to
# make sure that only complete header names are matching, the names in
# TX.restricted_headers are wrapped in slashes. This guarantees that the
# header Range (-> /range/) is not matching the restricted header
# /content-range/ for example.
#
# This is a chained rule, where the first rule fills a set of variables of the
# form TX.header_name_<HEADER_NAME>. The second rule is then executed for all
# variables of the form TX.header_name_<HEADER_NAME>.
#
# As a consequence of the construction of the rule, the alert message and the
# alert data will not display the original header name Content-Range, but
# /content-range/ instead.
#
#
# -=[ References ]=-
# https://access.redhat.com/security/vulnerabilities/httpoxy (Header Proxy)
#
SecRule REQUEST_HEADERS_NAMES "@rx ^(.*)$" \
  "msg:'HTTP header is restricted by policy (%{MATCHED_VAR})',\
   severity:'CRITICAL',\
   phase:request,\
   t:none,\
   block,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   id:920450,\
   capture,\
   logdata:' Restricted header detected: %{matched_var}',\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/POLICY/HEADER_RESTRICTED',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/12.1',\
   tag:'WASCTC/WASC-15',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/12.1',\
   t:lowercase,\
   setvar:'tx.header_name_%{tx.0}=/%{tx.0}/',\
   chain"
     SecRule TX:/^HEADER_NAME_/ "@within %{tx.restricted_headers}" \
   	"setvar:'tx.msg=%{rule.msg}',\
   	 setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   	 setvar:'tx.%{rule.id}-OWASP_CRS/POLICY/HEADERS_RESTRICTED-%{matched_var_name}=%{matched_var}'"


SecRule TX:PARANOIA_LEVEL "@lt 2" "phase:1,id:920013,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
SecRule TX:PARANOIA_LEVEL "@lt 2" "phase:2,id:920014,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
#
# -= Paranoia Level 2 =- (apply only when tx.paranoia_level is sufficiently high: 2 or higher)
#

#
# -=[ Rule Logic ]=-
#
# Check the number of range fields in the Range request header.
#
# An excessive number of Range request headers can be used to DoS a server.
# The original CVE proposed an arbitrary upper limit of 5 range fields.
#
# Several clients are known to request PDF fields with up to 34 range
# fields. Therefore the standard rule does not cover PDF files. This is
# performed in two separate (stricter) siblings of this rule.
#
# 920200: PL2: Limit of 5 range header fields for all filenames outside of PDFs
# 920201: PL2: Limit of 34 range header fields for PDFs
# 920202: PL4: Limit of 5 range header fields for PDFs
#
# -=[ References ]=-
# https://httpd.apache.org/security/CVE-2011-3192.txt

SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "^bytes=((\d+)?\-(\d+)?\s*,?\s*){6}" \
  "phase:request,\
   capture,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'Range: Too many fields (6 or more)',\
   logdata:'%{matched_var}',\
   severity:'WARNING',\
   id:920200,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
   tag:'paranoia-level/2',\
   chain"
   SecRule REQUEST_BASENAME "!@endsWith .pdf" \
   	"setvar:'tx.msg=%{rule.msg}',\
	 setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
	 setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}"

#
# This is a sibling of rule 920200
#

SecRule REQUEST_BASENAME "@endsWith .pdf" \
  "phase:request,\
   capture,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'Range: Too many fields for pdf request (35 or more)',\
   logdata:'%{matched_var}',\
   severity:'WARNING',\
   id:920201,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
   tag:'paranoia-level/2',\
   chain"
   SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "^bytes=((\d+)?\-(\d+)?\s*,?\s*){35}" \
   	   "setvar:'tx.msg=%{rule.msg}',\
	   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
	   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}"


SecRule ARGS "\%((?!$|\W)|[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'Multiple URL Encoding Detected',\
   id:920230,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   tag:'paranoia-level/2',\
   severity:'WARNING',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


#
# Missing Accept Header
#
# -=[ Rule Logic ]=-
# This rule generates a notice if the Accept header is missing.
#
SecRule &REQUEST_HEADERS:Accept "@eq 0" \
  "msg:'Request Missing an Accept Header',\
   chain,\
   phase:request,\
   rev:'3',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'8',\
   t:none,\
   pass,\
   severity:'NOTICE',\
   id:920300,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_ACCEPT',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',\
   tag:'paranoia-level/2'"
     SecRule REQUEST_METHOD "!^OPTIONS$" \
       "chain"
	  SecRule REQUEST_HEADERS:User-Agent "!@pm AppleWebKit Android" \
	    "t:none,\
            setvar:'tx.msg=%{rule.msg}',\
            setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
            setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"

#
# PL2: This is a stricter sibling of 920270.
#
SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "@validateByteRange 9,10,13,32-126,128-255" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   block,\
   msg:'Invalid character in request (non printable characters)',\
   id:920271,\
   severity:'CRITICAL',\
   t:none,t:urlDecodeUni,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   tag:'paranoia-level/2',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


#
# Missing User-Agent Header
#
# -=[ Rule Logic ]=-
# This rules will check to see if there is a User-Agent header or not.
#

SecRule &REQUEST_HEADERS:User-Agent "@eq 0" \
  "msg:'Missing User Agent Header',\
   severity:'NOTICE',\
   phase:request,\
   rev:'1',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   t:none,\
   pass,\
   id:920320,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER_UA',\
   tag:'WASCTC/WASC-21',\
   tag:'OWASP_TOP_10/A7',\
   tag:'PCI/6.5.10',\
   tag:'paranoia-level/2',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.notice_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/MISSING_HEADER-%{matched_var_name}=%{matched_var}"


#
# PL2: This is a stricter sibling of 920120.
#
SecRule FILES_NAMES|FILES "['\";=]" \
  "msg:'Attempted multipart/form-data bypass',\
  severity:'CRITICAL',\
  id:920121,\
  ver:'OWASP_CRS/3.0.0',\
  rev:'1',\
  maturity:'9',\
  accuracy:'7',\
  logdata:'%{matched_var}',\
  phase:request,\
  block,\
  t:none,t:urlDecodeUni,\
  tag:'application-multi',\
  tag:'language-multi',\
  tag:'platform-multi',\
  tag:'attack-protocol',\
  tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ',\
  tag:'CAPEC-272',\
  tag:'paranoia-level/2',\
  setvar:'tx.msg=%{rule.msg}',\
  setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
  setvar:'tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_REQ-%{matched_var_name}=%{matched_var}'"


SecRule TX:PARANOIA_LEVEL "@lt 3" "phase:1,id:920015,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
SecRule TX:PARANOIA_LEVEL "@lt 3" "phase:2,id:920016,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
#
# -= Paranoia Level 3 =- (apply only when tx.paranoia_level is sufficiently high: 3 or higher)
#

#
# PL 3: This is a stricter sibling of 920270. Ascii range: Printable characters in the low range
#
SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 32-36,38-126" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   block,\
   msg:'Invalid character in request (outside of printable chars below ascii 127)',\
   id:920272,\
   severity:'CRITICAL',\
   t:none,t:urlDecodeUni,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   tag:'paranoia-level/3',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"



SecRule TX:PARANOIA_LEVEL "@lt 4" "phase:1,id:920017,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
SecRule TX:PARANOIA_LEVEL "@lt 4" "phase:2,id:920018,nolog,pass,skipAfter:END-REQUEST-920-PROTOCOL-ENFORCEMENT"
#
# -= Paranoia Level 4 =- (apply only when tx.paranoia_level is sufficiently high: 4 or higher)
#

#
# This is a stricter sibling of rule 920200
#

SecRule REQUEST_BASENAME "@endsWith .pdf" \
  "phase:request,\
   capture,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'6',\
   accuracy:'8',\
   t:none,\
   block,\
   msg:'Range: Too many fields for pdf request (6 or more)',\
   logdata:'%{matched_var}',\
   severity:'WARNING',\
   id:920202,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ',\
   tag:'paranoia-level/4',\
   chain"
   SecRule REQUEST_HEADERS:Range|REQUEST_HEADERS:Request-Range "^bytes=((\d+)?\-(\d+)?\s*,?\s*){6}" \
   	   "setvar:'tx.msg=%{rule.msg}',\
	   setvar:tx.anomaly_score=+%{tx.warning_anomaly_score},\
	   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/INVALID_HREQ-%{matched_var_name}=%{matched_var}"


#
# This is a stricter sibling of 920270.
#
SecRule ARGS|ARGS_NAMES|REQUEST_BODY "@validateByteRange 38,44-46,48-58,61,65-90,95,97-122" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   block,\
   msg:'Invalid character in request (outside of very strict set)',\
   id:920273,\
   severity:'CRITICAL',\
   t:none,t:urlDecodeUni,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   tag:'paranoia-level/4',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"

#
# This is a stricter sibling of 920270.
#
SecRule REQUEST_HEADERS|!REQUEST_HEADERS:User-Agent|!REQUEST_HEADERS:Referer|!REQUEST_HEADERS:Cookie "@validateByteRange 32,34,38,42-59,61,65-90,95,97-122" \
  "phase:request,\
   rev:'2',\
   ver:'OWASP_CRS/3.0.0',\
   maturity:'9',\
   accuracy:'9',\
   block,\
   msg:'Invalid character in request headers (outside of very strict set)',\
   id:920274,\
   severity:'CRITICAL',\
   t:none,t:urlDecodeUni,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'OWASP_CRS/PROTOCOL_VIOLATION/EVASION',\
   tag:'paranoia-level/4',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/PROTOCOL_VIOLATION/EVASION-%{matched_var_name}=%{matched_var}"


# -=[ Abnormal Character Escapes ]=-
#
# [ Rule Logic ]
# Consider the following payload: arg=cat+/e\tc/pa\ssw\d
# Here, \s and \d were only used to obfuscate the string passwd and a lot of
# parsers will silently ignore the non-necessary escapes. The case with \t is
# a bit different though, as \t is a natural escape for the TAB character,
# so we will avoid this (and \n, \r, etc.).
#
# This rule aims to detect non-necessary, abnormal esacpes. You could say it is
# a nice # way to forbid the backslash character where it is not needed.
#
# This is a new rule at paranoia level 4. We expect quite a few false positives
# for this rule and we will later evaluate if the rule makes any sense at all.
# The rule is redundant with 920273 and 920274 in PL4. But if the rule proofs
# to be useful and false positives remain at a reasonable level, then it might
# be shifted to PL3 in a future release, where it would be the only rule
# covering the backslash escape.
#
# The rule construct is overly complex due to the fact that matching the
# backslash character with \b did not work. \Q\\\E does match the backslash
# character though. This is thus the base of the rule. We forbid the backslash
# when followed by a list of basic ascii characters - unless the backslash
# is preceded by another backslash character, which is being checked via a
# negative look-behind construct. If that is the case, the backslash character
# is allowed.
#
SecRule REQUEST_URI|REQUEST_HEADERS|ARGS|ARGS_NAMES "(?<!\Q\\\E)\Q\\\E[cdeghijklmpqwxyz123456789]" \
  "phase:request,\
   id:920460,\
   rev:'1',\
   accuracy:'1',\
   maturity:'1',\
   ver:'OWASP_CRS/3.0.0',\
   block,\
   log,\
   severity:'CRITICAL',\
   capture,\
   tag:'application-multi',\
   tag:'language-multi',\
   tag:'platform-multi',\
   tag:'attack-protocol',\
   tag:'paranoia-level/4',\
   t:none,t:urlDecodeUni,t:htmlEntityDecode,t:lowercase,\
   ctl:auditLogParts=+E,\
   logdata:'Matched Data: %{TX.0} found within %{MATCHED_VAR_NAME}: %{MATCHED_VAR}',\
   setvar:'tx.msg=%{rule.msg}',\
   setvar:'tx.http_violation_score=+%{tx.critical_anomaly_score}',\
   setvar:tx.anomaly_score=+%{tx.critical_anomaly_score},\
   setvar:tx.%{rule.id}-OWASP_CRS/WEB_ATTACK/ABNORMAL-ESCAPE-%{matched_var_name}=%{matched_var}"


#
# -= Paranoia Levels Finished =-
#
SecMarker "END-REQUEST-920-PROTOCOL-ENFORCEMENT"