# ------------------------------------------------------------------------
# OWASP ModSecurity Core Rule Set ver.3.3.9
# Copyright (c) 2006-2020 Trustwave and contributors. All rights reserved.
# Copyright (c) 2021-2026 Core Rule Set project. 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.
#
# ------------------------------------------------------------------------

# These exclusions remedy false positives in a default NextCloud install.
# They will likely work with OwnCloud too, but you may have to modify them.
# The exclusions are only active if crs_exclusions_nextcloud=1 is set.
# See rule 900130 in crs-setup.conf.example for instructions.
#
# To relax upload restrictions for only the php files that need it,
# you put something like this in crs-setup.conf:
#
# SecRule REQUEST_FILENAME "@rx /(?:remote.php|index.php)/" \
#   "id:9003330,\
#   phase:1,\
#   t:none,\
#   nolog,\
#   pass,\
#   tx.restricted_extensions='.bak/ .config/ .conf/'"
#
# Large uploads can be modified with SecRequestBodyLimit. Or they
# can be more controlled by using the following:
#
# SecRule REQUEST_URI "@endsWith /index.php/apps/files/ajax/upload.php" \
#    "id:9003610,\
#    phase:1,\
#    t:none,\
#    nolog,\
#    ctl:requestBodyLimit=1073741824"
#
# ---------------------


SecRule &TX:crs_exclusions_nextcloud|TX:crs_exclusions_nextcloud "@eq 0" \
    "id:9003000,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    skipAfter:END-NEXTCLOUD"

SecRule &TX:crs_exclusions_nextcloud|TX:crs_exclusions_nextcloud "@eq 0" \
    "id:9003001,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    skipAfter:END-NEXTCLOUD"


#
# [ File Manager ]
#
#
# The web interface uploads files, and interacts with the user.

SecRule REQUEST_FILENAME "@contains /remote.php/webdav" \
    "id:9003100,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveByTag=attack-injection-php,\
    ctl:ruleRemoveById=941000-942999,\
    ctl:ruleRemoveById=951000-951999,\
    ctl:ruleRemoveById=953100-953130,\
    ctl:ruleRemoveById=920420,\
    ctl:ruleRemoveById=920440,\
    ver:'OWASP_CRS/3.3.9'"

# Skip PUT parsing for invalid encoding / protocol violations in binary files.

SecRule REQUEST_METHOD "@streq PUT" \
    "id:9003105,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    chain"
    SecRule REQUEST_FILENAME "@contains /remote.php/webdav" \
        "t:none,\
        ctl:ruleRemoveById=920000-920999,\
        ctl:ruleRemoveById=932000-932999,\
        ctl:ruleRemoveById=921150,\
        ctl:ruleRemoveById=930110,\
        ctl:ruleRemoveById=930120"

# Allow the data type 'text/vcard'

SecRule REQUEST_FILENAME "@contains /remote.php/dav/files/" \
    "id:9003110,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'tx.allowed_request_content_type=%{tx.allowed_request_content_type} |text/vcard|'"

# Allow the data type 'application/octet-stream'

SecRule REQUEST_METHOD "@rx ^(?:PUT|MOVE)$" \
    "id:9003115,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    chain"
    SecRule REQUEST_FILENAME "@rx /remote\.php/dav/(?:files|uploads)/" \
        "setvar:'tx.allowed_request_content_type=%{tx.allowed_request_content_type} |application/octet-stream|'"

# Allow data types like video/mp4

SecRule REQUEST_METHOD "@streq PUT" \
    "id:9003116,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    chain"
    SecRule REQUEST_FILENAME "@rx (?:/public\.php/webdav/|/remote\.php/dav/uploads/)" \
        "ctl:ruleRemoveById=920340,\
        ctl:ruleRemoveById=920420"


# Allow characters like /../ in files.
# Allow all kind of filetypes.
# Allow source code.

SecRule REQUEST_FILENAME "@contains /remote.php/dav/files/" \
    "id:9003120,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveById=930100-930110,\
    ctl:ruleRemoveById=951000-951999,\
    ctl:ruleRemoveById=953100-953130,\
    ctl:ruleRemoveById=920440,\
    ver:'OWASP_CRS/3.3.9'"

# Allow REPORT requests without Content-Type header (at least the iOS app does this)

SecRule REQUEST_METHOD "@streq REPORT" \
    "id:9003121,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    chain"
    SecRule REQUEST_FILENAME "@contains /remote.php/dav/files/" \
        "t:none,\
        ctl:ruleRemoveById=920340"


# [ Searchengine ]
#
# NexCloud uses a search field for filename or content queries.

SecRule REQUEST_FILENAME "@contains /index.php/core/search" \
    "id:9003125,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetByTag=attack-injection-php;ARGS:query,\
    ctl:ruleRemoveTargetById=941000-942999;ARGS:query,\
    ctl:ruleRemoveTargetById=932000-932999;ARGS:query,\
    ver:'OWASP_CRS/3.3.9'"


# [ DAV ]
#
# NextCloud uses DAV methods with index.php and remote.php to do many things
# The default ones in ModSecurity are: GET HEAD POST OPTIONS
#
# Looking through the code, and via testing, I found these:
#
# File manager: PUT DELETE MOVE PROPFIND PROPPATCH
# Calendars: REPORT
# Others in the code or js files: PATCH MKCOL MOVE TRACE
# Others that I added just in case, and they seem related:
#   CHECKOUT COPY LOCK MERGE MKACTIVITY UNLOCK.

SecRule REQUEST_FILENAME "@rx /(?:remote|index|public)\.php/" \
    "id:9003130,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'tx.allowed_methods=%{tx.allowed_methods} PUT PATCH CHECKOUT COPY DELETE LOCK MERGE MKACTIVITY MKCOL MOVE PROPFIND PROPPATCH UNLOCK REPORT TRACE jsonp'"


# We need to allow DAV methods for sharing files, and removing shares
# DELETE - when the share is removed
# PUT - when setting a password / expiration time

SecRule REQUEST_FILENAME "@rx /ocs/v[0-9]+\.php/apps/files_sharing/" \
    "id:9003140,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'tx.allowed_methods=%{tx.allowed_methods} PUT DELETE'"


# [ Preview and Thumbnails ]

SecRule REQUEST_FILENAME "@contains /index.php/core/preview.png" \
    "id:9003150,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetById=932150;ARGS:file,\
    ver:'OWASP_CRS/3.3.9'"

# Filepreview for trashbin

SecRule REQUEST_FILENAME "@contains /index.php/apps/files_trashbin/ajax/preview.php" \
    "id:9003155,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetById=932150;ARGS:file,\
    ctl:ruleRemoveTargetById=942190;ARGS:file,\
    ver:'OWASP_CRS/3.3.9'"

SecRule REQUEST_FILENAME "@rx /index\.php/(?:apps/gallery/thumbnails|logout$)" \
    "id:9003160,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetById=941120;ARGS:requesttoken,\
    ver:'OWASP_CRS/3.3.9'"


# [ Ownnote ]

SecRule REQUEST_FILENAME "@contains /index.php/apps/ownnote/" \
    "id:9003300,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveById=941150,\
    ver:'OWASP_CRS/3.3.9'"


# [ Text Editor ]
#
# This file can save anything, and it's name could be lots of things.

SecRule REQUEST_FILENAME "@contains /index.php/apps/files_texteditor/" \
    "id:9003310,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:filecontents,\
    ctl:ruleRemoveTargetById=921110-921160;ARGS:filecontents,\
    ctl:ruleRemoveTargetById=932150;ARGS:filename,\
    ctl:ruleRemoveTargetById=920370-920390;ARGS:filecontents,\
    ctl:ruleRemoveTargetById=920370-920390;ARGS_COMBINED_SIZE,\
    ver:'OWASP_CRS/3.3.9'"


# [ Address Book ]
#
# Allow the data type 'text/vcard'

SecRule REQUEST_FILENAME "@contains /remote.php/dav/addressbooks/" \
    "id:9003320,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'tx.allowed_request_content_type=%{tx.allowed_request_content_type} |text/vcard|'"

# Allow modifying contacts via the web interface
SecRule REQUEST_METHOD "@streq PUT" \
    "id:9003321,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    chain"
    SecRule REQUEST_FILENAME "@contains /remote.php/dav/addressbooks/" \
        "t:none,\
        ctl:ruleRemoveById=200002"


# [ Calendar ]
#
# Allow the data type 'text/calendar'

SecRule REQUEST_FILENAME "@contains /remote.php/dav/calendars/" \
    "id:9003330,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    setvar:'tx.allowed_request_content_type=%{tx.allowed_request_content_type} |text/calendar|'"

# Allow modifying calendar events via the web interface
SecRule REQUEST_METHOD "@streq PUT" \
    "id:9003331,\
    phase:1,\
    pass,\
    t:none,\
    nolog,\
    chain"
    SecRule REQUEST_FILENAME "@contains /remote.php/dav/calendars/" \
        "t:none,\
        ctl:ruleRemoveById=200002"


# [ Notes ]
#
# We want to allow a lot of things as the user is
# allowed to note on anything.

SecRule REQUEST_FILENAME "@contains /index.php/apps/notes/" \
    "id:9003340,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveByTag=attack-injection-php,\
    ver:'OWASP_CRS/3.3.9'"


# [ Bookmarks ]
#
# Allow urls in data.

SecRule REQUEST_FILENAME "@contains /index.php/apps/bookmarks/" \
    "id:9003350,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveById=931130,\
    ver:'OWASP_CRS/3.3.9'"


#
# [ Login forms ]
#

# This removes checks on the 'password' and related fields:

# User login password.

SecRule REQUEST_FILENAME "@contains /index.php/login" \
    "id:9003400,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetById=941100;ARGS:requesttoken,\
    ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:password,\
    ver:'OWASP_CRS/3.3.9'"

# Reset password.

SecRule REQUEST_FILENAME "@endsWith /index.php/login" \
    "id:9003410,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ver:'OWASP_CRS/3.3.9',\
    chain"
    SecRule ARGS:action "@streq resetpass" \
        "t:none,\
        chain"
        SecRule &ARGS:action "@eq 1" \
            "t:none,\
            ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:pass1,\
            ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:pass1-text,\
            ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:pass2"

# Change Password and Setting up a new user/password

SecRule REQUEST_FILENAME "@endsWith /index.php/settings/users" \
    "id:9003500,\
    phase:2,\
    pass,\
    t:none,\
    nolog,\
    ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:newuserpassword,\
    ctl:ruleRemoveTargetByTag=OWASP_CRS;ARGS:password,\
    ver:'OWASP_CRS/3.3.9'"


SecMarker "END-NEXTCLOUD-ADMIN"

SecMarker "END-NEXTCLOUD"
