From 219211a88e9a3694890fe4b03d1bf0c3b62bb61c Mon Sep 17 00:00:00 2001 From: Anna Larch Date: Tue, 1 Sep 2026 18:35:00 +0200 Subject: [PATCH] docs(admin): document ICAP antivirus configuration The ICAP section was a single paragraph ending 'Additional documentation is work in progress'. Replaces it with the settings and their defaults, the choice between REQMOD and RESPMOD, the vendor-specific virus response header and its silent failure mode, verification via occ files_antivirus:test, how scanner verdicts are handled, transport security, and what data is sent to the scanning service. Adds a general 'How scanning works' section with the scan limits, since those apply to all scanner modes and not only to ICAP. Assisted-by: ClaudeCode:claude-opus-5-5 Signed-off-by: Anna Larch --- .../antivirus_configuration.rst | 303 +++++++++++++++++- 1 file changed, 300 insertions(+), 3 deletions(-) diff --git a/admin_manual/configuration_server/antivirus_configuration.rst b/admin_manual/configuration_server/antivirus_configuration.rst index de5675dbec1..121e92396d2 100644 --- a/admin_manual/configuration_server/antivirus_configuration.rst +++ b/admin_manual/configuration_server/antivirus_configuration.rst @@ -191,6 +191,58 @@ You may configure additional alert options in ``clamd.conf``, that should catch For reliable detection and blocking of encrypted files, consult available antivirus backends documentation. +How scanning works +------------------ + +The following applies to all scanner modes, including ICAP: + +* Uploads are scanned while they are being written. The app installs a storage + wrapper that observes every write, so the data is streamed to the scanner as + it arrives rather than after the file is complete. + +* When the verdict is "infected", the newly written file is deleted and the + upload is refused with the message *Virus is detected in the file. + Upload cannot be completed.* The trash bin is paused while the file is + deleted, so the infected file does not end up in the user's trash. An entry + is written to the log and to the user's activity stream. + +* Files that already existed, files that were accepted while the scanner was + unavailable, and files whose scan is older than ``av_rescan_days`` (default + ``28``) are handled by the background scanner, which scans in batches on the + cron schedule. For infected files found by the background scanner, the + action is controlled by ``av_infected_action``, which defaults to + ``only_log``. See `Manage the background scanner`_. + +* Some content is never sent to the scanner: end-to-end encrypted files and + their metadata, and anything under a directory listed in + ``av_blocklisted_directories``. + +Scan limits +~~~~~~~~~~~ + +Three settings bound how much of a file is sent to the scanner, and all three +change what the verdict is actually based on: + +``av_scan_first_bytes`` + Default ``-1``, meaning the whole file. With a positive value, only about + the first that many bytes of a file are sent, so the scanner returns a + verdict on a prefix of the file and malware later in the file is not seen. + +``av_stream_max_length`` + Default ``26214400`` (25 MiB). A file larger than this is not sent in a + single scan: the scan is finished and evaluated, and a new one is started + for the following bytes. Each segment is scanned on its own, and a + detection in any segment marks the file as infected. Detections that depend + on seeing a whole object, such as a large archive, can be missed when the + object spans a segment boundary, so raise this limit rather than lowering it + if your scanner and the PHP ``memory_limit`` allow for it. + +``av_max_file_size`` + Default ``-1``, meaning no limit. With a positive value, files larger than + this are excluded from background scanning entirely, and chunked WebDAV + uploads larger than this are not scanned at all. They are stored unscanned; + they are not partially scanned. + Manage the background scanner ----------------------------- @@ -231,12 +283,257 @@ Files marked as scanned will not be scanned for the next four weeks. Configuring ICAP on Nextcloud ----------------------------- -Nextcloud offers the integration of antivirus protection based on the ICAP protocol. -The settings are outlined here. -Additional documentation is work in progress. +Instead of talking to ClamAV directly, the Antivirus app for Files can hand +files to an external scanning service using ICAP, the Internet Content +Adaptation Protocol (`RFC 3507 `_). +In this mode Nextcloud does not run a scanner itself: it opens a TCP +connection to an ICAP server, streams the file to it and acts on the verdict +that comes back. + +Use ICAP mode when: + +* you already operate an enterprise scanning appliance or scanning service + that speaks ICAP, possibly shared with your mail gateway or proxy. The + administration settings ship presets for ClamAV / c-icap, Kaspersky and + FortiSandbox; +* you want to run ClamAV behind ``c-icap`` on a separate host, so that + scanning load and signature updates are kept away from the Nextcloud + servers; +* your scanner should also enforce a file type or file extension policy, which + ICAP mode understands in addition to malware verdicts (see + `How ICAP responses are interpreted`_). + +To enable it, select ``ICAP`` as the mode in the Antivirus Configuration panel +on your Admin page, or set it with ``occ``:: + + sudo -E -u www-data php occ config:app:set files_antivirus av_mode --value="icap" .. figure:: ../images/antivirus-icap.png +Settings +~~~~~~~~ + +The host and port are shared with the other network modes; all other settings +below are specific to ICAP mode. + +.. list-table:: + :header-rows: 1 + :widths: 30 20 50 + + * - Option + - Default + - Description + * - ``av_mode`` + - ``executable`` + - Set to ``icap`` to enable ICAP mode. + * - ``av_host`` + - (empty) + - Hostname or IP address of the ICAP server. Scanning fails if this is + not set. + * - ``av_port`` + - ``3310`` + - Port of the ICAP server. Note that this default is the ClamAV daemon + port, not the ICAP default port of 1344, so it almost always has to be + changed. + * - ``av_icap_request_service`` + - ``avscan`` + - The ICAP service to call, that is the path part of the request URI + ``icap:///``. ``c-icap`` with ClamAV uses ``avscan``; + other products use different names, for example ``req`` for Kaspersky + and ``respmod`` for FortiSandbox. + * - ``av_icap_mode`` + - ``reqmod`` + - Either ``reqmod`` or ``respmod``. See + `Choosing between REQMOD and RESPMOD`_. + * - ``av_icap_response_header`` + - ``X-Infection-Found`` + - The ICAP response header from which the threat name is read. This is + vendor specific; see `The virus response header`_. + * - ``av_icap_tls`` + - ``false`` + - Whether to wrap the ICAP connection in TLS. See + `Transport security`_. + * - ``av_icap_chunk_size`` + - ``1048576`` + - Number of bytes buffered in memory before they are sent to the ICAP + server. + * - ``av_icap_connect_timeout`` + - ``5`` + - Timeout in seconds for establishing the TCP or TLS connection to the + ICAP server. The read timeout on an established connection is fixed at + 600 seconds. + +All of these can be set with ``occ``, for example:: + + sudo -E -u www-data php occ config:app:set files_antivirus av_host --value="icap.example.com" + sudo -E -u www-data php occ config:app:set files_antivirus av_port --value="1344" + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_request_service --value="avscan" + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_mode --value="reqmod" + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_response_header --value="X-Infection-Found" + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_tls --value="true" + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_chunk_size --value="1048576" + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_connect_timeout --value="5" + +The Antivirus Configuration panel exposes the mode, host, port, service, +virus response header and TLS switch, plus a preset selector that fills in +service, header and mode for ClamAV / c-icap, Kaspersky and FortiSandbox. +The chunk size and the connection timeout can only be set with ``occ``. + +The settings shared with the other modes also apply in ICAP mode: the +streaming limits ``av_stream_max_length``, ``av_max_file_size`` and +``av_scan_first_bytes`` (see `Scan limits`_), and the +handling options ``av_block_unscannable``, ``av_block_unreachable`` and +``av_infected_action`` (see `How ICAP responses are interpreted`_). + +Choosing between REQMOD and RESPMOD +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the mode your ICAP service supports. If the vendor has no preference, use +``respmod``. + +The virus response header +~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the ICAP server reports an infection it names the threat in a response +header, and the name of that header differs per vendor. ``av_icap_response_header`` +must match exactly what your scanner sends: ``c-icap`` with ClamAV uses +``X-Infection-Found``, Kaspersky uses ``X-Virus-ID``, and other products use +other names. The value of that header becomes the threat name that is logged +and shown to the user. + +.. warning:: A wrong ``av_icap_response_header`` fails silently and in the + unsafe direction. If the configured header is not the one the scanner + sends, no threat name is ever found, the response is treated as clean, and + infected files are accepted without any error being logged. Always verify + the setting against a real detection instead of assuming that an + error-free upload means scanning works. + +Verifying the configuration +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use the built-in test command, which scans harmless content and two variants +of the EICAR test file through the configured backend:: + + sudo -E -u www-data php occ files_antivirus:test + +The command fails if the clean content is reported as infected, or if either +EICAR sample is reported as clean, which is exactly the failure mode of a +wrong virus response header. It reports files that could not be scanned or +were not scanned separately, so a run that reports pending or unscannable +results is not a confirmation that detection works. + +ICAP mode also supports debug output, which prints the generated ICAP request +headers and the raw ICAP response. This is the quickest way to see which +header a scanner actually returns:: + + sudo -E -u www-data php occ files_antivirus:test --debug + +Saving the settings in the Antivirus Configuration panel also runs a scan of +dummy content and reports the result, so a saved configuration that cannot +reach the ICAP server is reported immediately. + +How ICAP responses are interpreted +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ICAP mode distinguishes more outcomes than clean and infected: + +.. list-table:: + :header-rows: 1 + :widths: 40 15 45 + + * - Scanner reports + - Result + - Handling + * - The file is clean + - Clean + - The file is accepted. + * - A virus was found + - Infected + - The upload is rejected and the file is deleted, see + `How scanning works`_. + * - The file type or file extension is blocked + - Infected + - Treated exactly like a malware detection, so an ICAP scanner can also + enforce a file type policy for Nextcloud uploads. + * - The file cannot be scanned, for example a password-protected archive, + an archive nested too deeply, or a file that cannot be decoded + - Unscannable + - Accepted or rejected according to ``av_block_unscannable``. + * - The file was not checked + - Not checked + - Accepted or rejected according to ``av_block_unreachable``. + * - Any other response or error + - Error + - The scan fails with an error and the upload does not complete. + +Two settings decide what happens to a file the scanner did not clear: + +``av_block_unscannable`` + Default ``false``. Files the scanner reported as unscannable, such as + password-protected archives or archives nested more deeply than the scanner + will unpack, are **accepted** with the default setting. Set it to ``true`` + to reject them instead:: + + sudo -E -u www-data php occ config:app:set files_antivirus av_block_unscannable --value="true" + +``av_block_unreachable`` + Default ``true``. With the default setting, a file is rejected when the ICAP + server cannot be reached at all or the file couldn't be scanned, and the user is told + that the upload cannot be completed. Set it to ``false`` to accept uploads + while the scanner is unavailable; such files are not marked as scanned, so + the background scanner picks them up later. + +.. warning:: These two defaults mean that, out of the box, a file that could + not be checked because it is unscannable is treated as safe and stored, + while a file that could not be checked because the scanner was unreachable + is refused. Decide deliberately which behaviour you want before relying on + ICAP scanning as a control. + +Transport security +~~~~~~~~~~~~~~~~~~ + +By default, ``av_icap_tls`` is ``false`` and the ICAP connection is a plain +TCP connection. With TLS enabled:: + + sudo -E -u www-data php occ config:app:set files_antivirus av_icap_tls --value="true" + +the connection is established as ``tls://:`` with peer and +peer name verification enabled, validated against the CA bundle managed by +Nextcloud. A scanner presenting a self-signed or private-CA certificate +therefore needs that certificate imported into Nextcloud, in the same way as +for external storage. + +.. warning:: Unless ``av_icap_tls`` is enabled, the connection to the ICAP + server is unencrypted: the contents of every scanned file, the file path and + the uploader's IP address are sent in plaintext. Only leave TLS off when the connection stays on a network you + fully control, and never for a remote or cloud-hosted scanning service. + +What is sent to the scanning service +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For a data protection assessment, this is what leaves the Nextcloud server on +every ICAP scan: + +* **The file contents**, subject to the `Scan limits`_. + +* **The file path.** For a file in an account's own storage it has the form + ``//files/``, so the account's user ID is part of it. + +* **The uploader's IP address**, whenever the scan is triggered by a request. + Background scans send none. + +No account name, display name, email address, group membership, share +information, comment or tag is sent. Nothing is transmitted back into +Nextcloud from the scanner except the verdict, and the threat name is stored +and logged with the scan result. + +.. warning:: If your ICAP server is operated by a third party or hosted + outside your own infrastructure, then enabling ICAP mode means you are + transferring file contents, file paths including account user IDs, and + client IP addresses to that third party for every upload and every + background scan. Cover this in your processing records and contracts + before enabling it. + Disabling background scan task ------------------------------