Server: Access forbidden: CSRF check failed on logout

Created on 9 Sep 2019  ·  117Comments  ·  Source: nextcloud/server

Steps to reproduce

  1. Install Lighttpd and PHP.
  2. Download Nextcloud server ZIP.
  3. Log in Nextcloud, and when you log out, in the most cases you get the next error:

Access forbidden
CSRF check failed

Screenshot at 2019-09-09 15-18-28

Expected behaviour

Log out succesfully.

Actual behaviour

When I try logout, I get the telled error. Then, if I refresh the website the session is still active.

In Network Firefox explorer (from F12) the logout request get a 412 status code:

Screenshot at 2019-09-09 15-27-30

This error is with Lighttpd web service, with Nginx works fine.

Server configuration

Operating system:
Debian / Raspbian
Web server:
Lighttpd
Database:
MariaDB
PHP version:
PHP 7.3
Nextcloud version: (see Nextcloud admin page)
16.0.4
Updated from an older Nextcloud/ownCloud or fresh install:
Fresh install
Where did you install Nextcloud from:
https://download.nextcloud.com/server/releases/nextcloud-16.0.4.zip

1. to develop bug papercut security

Most helpful comment

Problem is not yet solved, additional logs and stack trace provided above. Issue, although Lighttpd not officially supported, is security-relevant, e.g. on public clients:

  • User logs out, receives error but might not recheck/ignore
  • Next user can access same Nextcloud session without login

All 117 comments

Anything in the logs?

Anything in the logs?

Nothing in Nextcloud logs with debug 0 level.
Nothing in PHP logs.
In Lighttpd:

192.168.1.8 192.168.1.29 - [09/Sep/2019:15:08:08 +0100] "GET /nextcloud/index.php/logout?requesttoken=FfsiGZcBHPF%2BqSnsIhrlZNOXbAr%2F682WV718xe7WqfI%3D%3AfI1VL8ZUKLY4hlqKbG2OIpWlLlO6qJuiP9kT9qfn7MY%3D HTTP/1.1" 412 11746 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0"

Hi, I have the same problem running nextcloud on a rasberry PI3 using DietPi/Nextcloud/Lighttpd and reproduced as well running this system in a VM using virtual box.
Setting the logging of nextcloud to debug I get:

[core] Debug: OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException: CSRF check failed at <>

  1. /var/www/nextcloud/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php line 95
    OC\AppFramework\Middleware\Security\SecurityMiddleware->beforeController(OC\Core\Controller\LoginController {}, "logout")
  2. /var/www/nextcloud/lib/private/AppFramework/Http/Dispatcher.php line 97
    OC\AppFramework\Middleware\MiddlewareDispatcher->beforeController(OC\Core\Controller\LoginController {}, "logout")
  3. /var/www/nextcloud/lib/private/AppFramework/App.php line 126
    OC\AppFramework\Http\Dispatcher->dispatch(OC\Core\Controller\LoginController {}, "logout")
  4. /var/www/nextcloud/lib/private/AppFramework/Routing/RouteActionHandler.php line 47
    OC\AppFramework\App::main("OC\Core\Controller\LoginController", "logout", OC\AppFramework\ ... {}, {_route: "core.login.logout"})
  5. <>
    OC\AppFramework\Routing\RouteActionHandler->__invoke({_route: "core.login.logout"})
  6. /var/www/nextcloud/lib/private/Route/Router.php line 297
    undefinedundefinedcall_user_func(OC\AppFramework\ ... {}, {_route: "core.login.logout"})
  7. /var/www/nextcloud/lib/base.php line 975
    OC\Route\Router->match("/logout")
  8. /var/www/nextcloud/index.php line 42
    OC::handleRequest()

GET /nextcloud/index.php/logout?requesttoken=DTGY0BwWUvscxsw7frSaWhfTaRezU1t9SeeJGGXoF%2BQ%3D%3AfXqpk1NEZqNyrr9YDPL5KFWQEFLhZTIuI9%2FmQRCQZIE%3D
from 192.168.16.37 by admin at 2019-09-23T14:33:41+00:00

Nextcloud
Version: 16.0.4.1
Installierte Apps: 36
Apps mit verfügbaren Aktualisierungen: 1

PHP
Version: 7.3.9
Arbeitspeicher-Grenzwert: 128 MB
Maximale Ausführungszeit: 3600
Maximale Größe zum Hochladen: 8388608 TB

Datenbank
Art: mysql
Version: 10.3.17
Größe: 1,3 MB

The bug is easy to reproduce. Tell me, if more traces are needed. I can deliver them quickly. As it is now, the combination Nextcloud/Lighttpd can't be used productively.
If you want to reproduce it by yourself do the following steps:
1) Install virtual box https://www.virtualbox.org/
2) Download DietPi for Virtual Box and install it https://dietpi.com/
3) start dietpi-software and install nextcloud
4) start browser on host system and login to nextcloud page of guest system
5) logout nextcloud in browser
The fault shows up extremly often. Typically you need 5 faulty logout trys until you have a successful one.

1. Install virtual box https://www.virtualbox.org/

2. Download DietPi for Virtual Box and install it https://dietpi.com/

3. start dietpi-software and install nextcloud

4. start browser on host system and login to nextcloud page of guest system

5. logout nextcloud in browser
   The fault shows up extremly often. Typically you need 5 faulty logout trys until you have a successful one.

Logout works in Chromium and Firefox.

cc @MichaIng any idea?

OK. I can reproduce it somehow. Like you said login, upload some files, delete some files or do something else and try to logout afterwards.

        public function isTokenValid(CsrfToken $token): bool {
                if(!$this->sessionStorage->hasToken()) {
                        return false;
                }

                $isEqual = hash_equals($this->sessionStorage->getToken(), $token->getDecryptedValue());
                if (!$isEqual) {
                        \OC::$server->getLogger()->warning('going to validate csrf token "' . $this->sessionStorage->getToken() . '" with "' . $token->getDecryptedValue() . '"');
                }

                return $isEqual;
        }

Added some logging to isTokenValid and ...

image

cc @rullzer @ChristophWurst :confused:

Could you add some logging to \OC\Security\CSRF\CsrfToken::getDecryptedValue so we see the values of the individual parts?

I was able to replicate as well on fresh NC17 installed on DietPi Buster VirtualBox image.
@kesselb you tested on DietPi as well or another system? Just in case our default Lighttpd config on Debian Buster based images:


lighttpd -pf /etc/lighttpd/lighttpd.conf

config {
    var.PID                        = 18245
    var.CWD                        = "/root"
    mimetype.assign                = (
        ".pcf.Z"       => "application/x-font-pcf",
        ".tar.bz2"     => "application/x-gtar-compressed",
        ".tar.gz"      => "application/x-gtar-compressed",
        ".ez"          => "application/andrew-inset",
        ".anx"         => "application/annodex",
        # 5
        ".atom"        => "application/atom+xml",
        ".atomcat"     => "application/atomcat+xml",
        ".atomsrv"     => "application/atomserv+xml",
        ".lin"         => "application/bbolin",
        ".cu"          => "application/cu-seeme",
        # 10
        ".davmount"    => "application/davmount+xml",
        ".dcm"         => "application/dicom",
        ".tsp"         => "application/dsptype",
        ".es"          => "application/ecmascript",
        ".epub"        => "application/epub+zip",
        # 15
        ".pfr"         => "application/font-tdpfr",
        ".spl"         => "application/futuresplash",
        ".gz"          => "application/gzip",
        ".hta"         => "application/hta",
        ".jar"         => "application/java-archive",
        # 20
        ".ser"         => "application/java-serialized-object",
        ".class"       => "application/java-vm",
        ".js"          => "application/javascript",
        ".json"        => "application/json",
        ".m3g"         => "application/m3g",
        # 25
        ".hqx"         => "application/mac-binhex40",
        ".cpt"         => "application/mac-compactpro",
        ".nb"          => "application/mathematica",
        ".nbp"         => "application/mathematica",
        ".mbox"        => "application/mbox",
        # 30
        ".mdb"         => "application/msaccess",
        ".doc"         => "application/msword",
        ".dot"         => "application/msword",
        ".mxf"         => "application/mxf",
        ".asn"         => "application/octet-stream",
        # 35
        ".bin"         => "application/octet-stream",
        ".deploy"      => "application/octet-stream",
        ".ent"         => "application/octet-stream",
        ".msp"         => "application/octet-stream",
        ".msu"         => "application/octet-stream",
        # 40
        ".oda"         => "application/oda",
        ".opf"         => "application/oebps-package+xml",
        ".ogx"         => "application/ogg",
        ".one"         => "application/onenote",
        ".onepkg"      => "application/onenote",
        # 45
        ".onetmp"      => "application/onenote",
        ".onetoc2"     => "application/onenote",
        ".pdf"         => "application/pdf",
        ".pgp"         => "application/pgp-encrypted",
        ".key"         => "application/pgp-keys",
        # 50
        ".sig"         => "application/pgp-signature",
        ".prf"         => "application/pics-rules",
        ".ai"          => "application/postscript",
        ".eps"         => "application/postscript",
        ".eps2"        => "application/postscript",
        # 55
        ".eps3"        => "application/postscript",
        ".epsf"        => "application/postscript",
        ".epsi"        => "application/postscript",
        ".ps"          => "application/postscript",
        ".rar"         => "application/rar",
        # 60
        ".rdf"         => "application/rdf+xml",
        ".rtf"         => "application/rtf",
        ".stl"         => "application/sla",
        ".smi"         => "application/smil+xml",
        ".smil"        => "application/smil+xml",
        # 65
        ".wasm"        => "application/wasm",
        ".xht"         => "application/xhtml+xml",
        ".xhtml"       => "application/xhtml+xml",
        ".xml"         => "application/xml",
        ".xsd"         => "application/xml",
        # 70
        ".dtd"         => "application/xml-dtd",
        ".xsl"         => "application/xslt+xml",
        ".xslt"        => "application/xslt+xml",
        ".xspf"        => "application/xspf+xml",
        ".zip"         => "application/zip",
        # 75
        ".apk"         => "application/vnd.android.package-archive",
        ".cdy"         => "application/vnd.cinderella",
        ".ddeb"        => "application/vnd.debian.binary-package",
        ".deb"         => "application/vnd.debian.binary-package",
        ".udeb"        => "application/vnd.debian.binary-package",
        # 80
        ".sfd"         => "application/vnd.font-fontforge-sfd",
        ".kml"         => "application/vnd.google-earth.kml+xml",
        ".kmz"         => "application/vnd.google-earth.kmz",
        ".xul"         => "application/vnd.mozilla.xul+xml",
        ".xlb"         => "application/vnd.ms-excel",
        # 85
        ".xls"         => "application/vnd.ms-excel",
        ".xlt"         => "application/vnd.ms-excel",
        ".xlam"        => "application/vnd.ms-excel.addin.macroEnabled.12",
        ".xlsb"        => "application/vnd.ms-excel.sheet.binary.macroEnabled.12",
        ".xlsm"        => "application/vnd.ms-excel.sheet.macroEnabled.12",
        # 90
        ".xltm"        => "application/vnd.ms-excel.template.macroEnabled.12",
        ".eot"         => "application/vnd.ms-fontobject",
        ".thmx"        => "application/vnd.ms-officetheme",
        ".cat"         => "application/vnd.ms-pki.seccat",
        ".pps"         => "application/vnd.ms-powerpoint",
        # 95
        ".ppt"         => "application/vnd.ms-powerpoint",
        ".ppam"        => "application/vnd.ms-powerpoint.addin.macroEnabled.12",
        ".pptm"        => "application/vnd.ms-powerpoint.presentation.macroEnabled.12",
        ".sldm"        => "application/vnd.ms-powerpoint.slide.macroEnabled.12",
        ".ppsm"        => "application/vnd.ms-powerpoint.slideshow.macroEnabled.12",
        # 100
        ".potm"        => "application/vnd.ms-powerpoint.template.macroEnabled.12",
        ".docm"        => "application/vnd.ms-word.document.macroEnabled.12",
        ".dotm"        => "application/vnd.ms-word.template.macroEnabled.12",
        ".odc"         => "application/vnd.oasis.opendocument.chart",
        ".odb"         => "application/vnd.oasis.opendocument.database",
        # 105
        ".odf"         => "application/vnd.oasis.opendocument.formula",
        ".odg"         => "application/vnd.oasis.opendocument.graphics",
        ".otg"         => "application/vnd.oasis.opendocument.graphics-template",
        ".odi"         => "application/vnd.oasis.opendocument.image",
        ".odp"         => "application/vnd.oasis.opendocument.presentation",
        # 110
        ".otp"         => "application/vnd.oasis.opendocument.presentation-template",
        ".ods"         => "application/vnd.oasis.opendocument.spreadsheet",
        ".ots"         => "application/vnd.oasis.opendocument.spreadsheet-template",
        ".odt"         => "application/vnd.oasis.opendocument.text",
        ".odm"         => "application/vnd.oasis.opendocument.text-master",
        # 115
        ".ott"         => "application/vnd.oasis.opendocument.text-template",
        ".oth"         => "application/vnd.oasis.opendocument.text-web",
        ".pptx"        => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
        ".sldx"        => "application/vnd.openxmlformats-officedocument.presentationml.slide",
        ".ppsx"        => "application/vnd.openxmlformats-officedocument.presentationml.slideshow",
        # 120
        ".potx"        => "application/vnd.openxmlformats-officedocument.presentationml.template",
        ".xlsx"        => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        ".xltx"        => "application/vnd.openxmlformats-officedocument.spreadsheetml.template",
        ".docx"        => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        ".dotx"        => "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
        # 125
        ".cod"         => "application/vnd.rim.cod",
        ".mmf"         => "application/vnd.smaf",
        ".sdc"         => "application/vnd.stardivision.calc",
        ".sds"         => "application/vnd.stardivision.chart",
        ".sda"         => "application/vnd.stardivision.draw",
        # 130
        ".sdd"         => "application/vnd.stardivision.impress",
        ".sdf"         => "application/vnd.stardivision.math",
        ".sdw"         => "application/vnd.stardivision.writer",
        ".sgl"         => "application/vnd.stardivision.writer-global",
        ".sxc"         => "application/vnd.sun.xml.calc",
        # 135
        ".stc"         => "application/vnd.sun.xml.calc.template",
        ".sxd"         => "application/vnd.sun.xml.draw",
        ".std"         => "application/vnd.sun.xml.draw.template",
        ".sxi"         => "application/vnd.sun.xml.impress",
        ".sti"         => "application/vnd.sun.xml.impress.template",
        # 140
        ".sxm"         => "application/vnd.sun.xml.math",
        ".sxw"         => "application/vnd.sun.xml.writer",
        ".sxg"         => "application/vnd.sun.xml.writer.global",
        ".stw"         => "application/vnd.sun.xml.writer.template",
        ".sis"         => "application/vnd.symbian.install",
        # 145
        ".cap"         => "application/vnd.tcpdump.pcap",
        ".pcap"        => "application/vnd.tcpdump.pcap",
        ".vsd"         => "application/vnd.visio",
        ".vss"         => "application/vnd.visio",
        ".vst"         => "application/vnd.visio",
        # 150
        ".vsw"         => "application/vnd.visio",
        ".wbxml"       => "application/vnd.wap.wbxml",
        ".wmlc"        => "application/vnd.wap.wmlc",
        ".wmlsc"       => "application/vnd.wap.wmlscriptc",
        ".wpd"         => "application/vnd.wordperfect",
        # 155
        ".wp5"         => "application/vnd.wordperfect5.1",
        ".wk"          => "application/x-123",
        ".7z"          => "application/x-7z-compressed",
        ".abw"         => "application/x-abiword",
        ".dmg"         => "application/x-apple-diskimage",
        # 160
        ".bcpio"       => "application/x-bcpio",
        ".torrent"     => "application/x-bittorrent",
        ".bz2"         => "application/x-bzip",
        ".cab"         => "application/x-cab",
        ".cbr"         => "application/x-cbr",
        # 165
        ".cbz"         => "application/x-cbz",
        ".cda"         => "application/x-cdf",
        ".cdf"         => "application/x-cdf",
        ".vcd"         => "application/x-cdlink",
        ".pgn"         => "application/x-chess-pgn",
        # 170
        ".mph"         => "application/x-comsol",
        ".cpio"        => "application/x-cpio",
        ".dcr"         => "application/x-director",
        ".dir"         => "application/x-director",
        ".dxr"         => "application/x-director",
        # 175
        ".dms"         => "application/x-dms",
        ".wad"         => "application/x-doom",
        ".dvi"         => "application/x-dvi",
        ".gsf"         => "application/x-font",
        ".pfa"         => "application/x-font",
        # 180
        ".pfb"         => "application/x-font",
        ".pcf"         => "application/x-font-pcf",
        ".mm"          => "application/x-freemind",
        ".gan"         => "application/x-ganttproject",
        ".gnumeric"    => "application/x-gnumeric",
        # 185
        ".sgf"         => "application/x-go-sgf",
        ".gcf"         => "application/x-graphing-calculator",
        ".gtar"        => "application/x-gtar",
        ".taz"         => "application/x-gtar-compressed",
        ".tbz"         => "application/x-gtar-compressed",
        # 190
        ".tgz"         => "application/x-gtar-compressed",
        ".hdf"         => "application/x-hdf",
        ".hwp"         => "application/x-hwp",
        ".ica"         => "application/x-ica",
        ".info"        => "application/x-info",
        # 195
        ".ins"         => "application/x-internet-signup",
        ".isp"         => "application/x-internet-signup",
        ".iii"         => "application/x-iphone",
        ".iso"         => "application/x-iso9660-image",
        ".jam"         => "application/x-jam",
        # 200
        ".jnlp"        => "application/x-java-jnlp-file",
        ".jmz"         => "application/x-jmol",
        ".chrt"        => "application/x-kchart",
        ".kil"         => "application/x-killustrator",
        ".skd"         => "application/x-koan",
        # 205
        ".skm"         => "application/x-koan",
        ".skp"         => "application/x-koan",
        ".skt"         => "application/x-koan",
        ".kpr"         => "application/x-kpresenter",
        ".kpt"         => "application/x-kpresenter",
        # 210
        ".ksp"         => "application/x-kspread",
        ".kwd"         => "application/x-kword",
        ".kwt"         => "application/x-kword",
        ".latex"       => "application/x-latex",
        ".lha"         => "application/x-lha",
        # 215
        ".lyx"         => "application/x-lyx",
        ".lzh"         => "application/x-lzh",
        ".lzx"         => "application/x-lzx",
        ".book"        => "application/x-maker",
        ".fb"          => "application/x-maker",
        # 220
        ".fbdoc"       => "application/x-maker",
        ".fm"          => "application/x-maker",
        ".frame"       => "application/x-maker",
        ".frm"         => "application/x-maker",
        ".maker"       => "application/x-maker",
        # 225
        ".mif"         => "application/x-mif",
        ".m3u8"        => "application/x-mpegURL",
        ".application" => "application/x-ms-application",
        ".manifest"    => "application/x-ms-manifest",
        ".wmd"         => "application/x-ms-wmd",
        # 230
        ".wmz"         => "application/x-ms-wmz",
        ".bat"         => "application/x-msdos-program",
        ".com"         => "application/x-msdos-program",
        ".dll"         => "application/x-msdos-program",
        ".exe"         => "application/x-msdos-program",
        # 235
        ".msi"         => "application/x-msi",
        ".nc"          => "application/x-netcdf",
        ".pac"         => "application/x-ns-proxy-autoconfig",
        ".nwc"         => "application/x-nwc",
        ".o"           => "application/x-object",
        # 240
        ".oza"         => "application/x-oz-application",
        ".p7r"         => "application/x-pkcs7-certreqresp",
        ".crl"         => "application/x-pkcs7-crl",
        ".pyc"         => "application/x-python-code",
        ".pyo"         => "application/x-python-code",
        # 245
        ".qgs"         => "application/x-qgis",
        ".shp"         => "application/x-qgis",
        ".shx"         => "application/x-qgis",
        ".qtl"         => "application/x-quicktimeplayer",
        ".rdp"         => "application/x-rdp",
        # 250
        ".rpm"         => "application/x-redhat-package-manager",
        ".rss"         => "application/x-rss+xml",
        ".rb"          => "application/x-ruby",
        ".sce"         => "application/x-scilab",
        ".sci"         => "application/x-scilab",
        # 255
        ".xcos"        => "application/x-scilab-xcos",
        ".shar"        => "application/x-shar",
        ".swf"         => "application/x-shockwave-flash",
        ".swfl"        => "application/x-shockwave-flash",
        ".scr"         => "application/x-silverlight",
        # 260
        ".sql"         => "application/x-sql",
        ".sit"         => "application/x-stuffit",
        ".sitx"        => "application/x-stuffit",
        ".sv4cpio"     => "application/x-sv4cpio",
        ".sv4crc"      => "application/x-sv4crc",
        # 265
        ".tar"         => "application/x-tar",
        ".gf"          => "application/x-tex-gf",
        ".pk"          => "application/x-tex-pk",
        ".texi"        => "application/x-texinfo",
        ".texinfo"     => "application/x-texinfo",
        # 270
        ".roff"        => "application/x-troff",
        ".t"           => "application/x-troff",
        ".tr"          => "application/x-troff",
        ".man"         => "application/x-troff-man",
        ".me"          => "application/x-troff-me",
        # 275
        ".ms"          => "application/x-troff-ms",
        ".ustar"       => "application/x-ustar",
        ".src"         => "application/x-wais-source",
        ".wz"          => "application/x-wingz",
        ".crt"         => "application/x-x509-ca-cert",
        # 280
        ".xcf"         => "application/x-xcf",
        ".fig"         => "application/x-xfig",
        ".xpi"         => "application/x-xpinstall",
        ".xz"          => "application/x-xz",
        ".amr"         => "audio/amr",
        # 285
        ".awb"         => "audio/amr-wb",
        ".axa"         => "audio/annodex",
        ".au"          => "audio/basic",
        ".snd"         => "audio/basic",
        ".csd"         => "audio/csound",
        # 290
        ".orc"         => "audio/csound",
        ".sco"         => "audio/csound",
        ".flac"        => "audio/flac",
        ".kar"         => "audio/midi",
        ".mid"         => "audio/midi",
        # 295
        ".midi"        => "audio/midi",
        ".m4a"         => "audio/mpeg",
        ".mp2"         => "audio/mpeg",
        ".mp3"         => "audio/mpeg",
        ".mpega"       => "audio/mpeg",
        # 300
        ".mpga"        => "audio/mpeg",
        ".m3u"         => "audio/mpegurl",
        ".oga"         => "audio/ogg",
        ".ogg"         => "audio/ogg",
        ".opus"        => "audio/ogg",
        # 305
        ".spx"         => "audio/ogg",
        ".sid"         => "audio/prs.sid",
        ".aif"         => "audio/x-aiff",
        ".aifc"        => "audio/x-aiff",
        ".aiff"        => "audio/x-aiff",
        # 310
        ".gsm"         => "audio/x-gsm",
        ".wax"         => "audio/x-ms-wax",
        ".wma"         => "audio/x-ms-wma",
        ".ra"          => "audio/x-realaudio",
        ".ram"         => "audio/x-realaudio",
        # 315
        ".rm"          => "audio/x-realaudio",
        ".pls"         => "audio/x-scpls",
        ".sd2"         => "audio/x-sd2",
        ".wav"         => "audio/x-wav",
        ".alc"         => "chemical/x-alchemy",
        # 320
        ".cac"         => "chemical/x-cache",
        ".cache"       => "chemical/x-cache",
        ".csf"         => "chemical/x-cache-csf",
        ".cascii"      => "chemical/x-cactvs-binary",
        ".cbin"        => "chemical/x-cactvs-binary",
        # 325
        ".ctab"        => "chemical/x-cactvs-binary",
        ".cdx"         => "chemical/x-cdx",
        ".cer"         => "chemical/x-cerius",
        ".c3d"         => "chemical/x-chem3d",
        ".chm"         => "chemical/x-chemdraw",
        # 330
        ".cif"         => "chemical/x-cif",
        ".cmdf"        => "chemical/x-cmdf",
        ".cml"         => "chemical/x-cml",
        ".cpa"         => "chemical/x-compass",
        ".bsd"         => "chemical/x-crossfire",
        # 335
        ".csm"         => "chemical/x-csml",
        ".csml"        => "chemical/x-csml",
        ".ctx"         => "chemical/x-ctx",
        ".cef"         => "chemical/x-cxf",
        ".cxf"         => "chemical/x-cxf",
        # 340
        ".emb"         => "chemical/x-embl-dl-nucleotide",
        ".embl"        => "chemical/x-embl-dl-nucleotide",
        ".spc"         => "chemical/x-galactic-spc",
        ".gam"         => "chemical/x-gamess-input",
        ".gamin"       => "chemical/x-gamess-input",
        # 345
        ".inp"         => "chemical/x-gamess-input",
        ".fch"         => "chemical/x-gaussian-checkpoint",
        ".fchk"        => "chemical/x-gaussian-checkpoint",
        ".cub"         => "chemical/x-gaussian-cube",
        ".gau"         => "chemical/x-gaussian-input",
        # 350
        ".gjc"         => "chemical/x-gaussian-input",
        ".gjf"         => "chemical/x-gaussian-input",
        ".gal"         => "chemical/x-gaussian-log",
        ".gcg"         => "chemical/x-gcg8-sequence",
        ".gen"         => "chemical/x-genbank",
        # 355
        ".hin"         => "chemical/x-hin",
        ".ist"         => "chemical/x-isostar",
        ".istr"        => "chemical/x-isostar",
        ".dx"          => "chemical/x-jcamp-dx",
        ".jdx"         => "chemical/x-jcamp-dx",
        # 360
        ".kin"         => "chemical/x-kinemage",
        ".mcm"         => "chemical/x-macmolecule",
        ".mmd"         => "chemical/x-macromodel-input",
        ".mmod"        => "chemical/x-macromodel-input",
        ".mol"         => "chemical/x-mdl-molfile",
        # 365
        ".rd"          => "chemical/x-mdl-rdfile",
        ".rxn"         => "chemical/x-mdl-rxnfile",
        ".sd"          => "chemical/x-mdl-sdfile",
        ".tgf"         => "chemical/x-mdl-tgf",
        ".mcif"        => "chemical/x-mmcif",
        # 370
        ".mol2"        => "chemical/x-mol2",
        ".b"           => "chemical/x-molconn-Z",
        ".gpt"         => "chemical/x-mopac-graph",
        ".mop"         => "chemical/x-mopac-input",
        ".mopcrt"      => "chemical/x-mopac-input",
        # 375
        ".mpc"         => "chemical/x-mopac-input",
        ".zmt"         => "chemical/x-mopac-input",
        ".moo"         => "chemical/x-mopac-out",
        ".mvb"         => "chemical/x-mopac-vib",
        ".prt"         => "chemical/x-ncbi-asn1-ascii",
        # 380
        ".aso"         => "chemical/x-ncbi-asn1-binary",
        ".val"         => "chemical/x-ncbi-asn1-binary",
        ".pdb"         => "chemical/x-pdb",
        ".ros"         => "chemical/x-rosdal",
        ".sw"          => "chemical/x-swissprot",
        # 385
        ".vms"         => "chemical/x-vamas-iso14976",
        ".vmd"         => "chemical/x-vmd",
        ".xtel"        => "chemical/x-xtel",
        ".xyz"         => "chemical/x-xyz",
        ".ttc"         => "font/collection",
        # 390
        ".otf"         => "font/ttf",
        ".ttf"         => "font/ttf",
        ".woff"        => "font/woff",
        ".woff2"       => "font/woff2",
        ".gif"         => "image/gif",
        # 395
        ".ief"         => "image/ief",
        ".jp2"         => "image/jp2",
        ".jpg2"        => "image/jp2",
        ".jpe"         => "image/jpeg",
        ".jpeg"        => "image/jpeg",
        # 400
        ".jpg"         => "image/jpeg",
        ".jpm"         => "image/jpm",
        ".jpf"         => "image/jpx",
        ".jpx"         => "image/jpx",
        ".pcx"         => "image/pcx",
        # 405
        ".png"         => "image/png",
        ".svg"         => "image/svg+xml",
        ".svgz"        => "image/svg+xml",
        ".tif"         => "image/tiff",
        ".tiff"        => "image/tiff",
        # 410
        ".djv"         => "image/vnd.djvu",
        ".djvu"        => "image/vnd.djvu",
        ".ico"         => "image/vnd.microsoft.icon",
        ".wbmp"        => "image/vnd.wap.wbmp",
        ".cr2"         => "image/x-canon-cr2",
        # 415
        ".crw"         => "image/x-canon-crw",
        ".ras"         => "image/x-cmu-raster",
        ".cdr"         => "image/x-coreldraw",
        ".pat"         => "image/x-coreldrawpattern",
        ".cdt"         => "image/x-coreldrawtemplate",
        # 420
        ".erf"         => "image/x-epson-erf",
        ".art"         => "image/x-jg",
        ".jng"         => "image/x-jng",
        ".bmp"         => "image/x-ms-bmp",
        ".nef"         => "image/x-nikon-nef",
        # 425
        ".orf"         => "image/x-olympus-orf",
        ".psd"         => "image/x-photoshop",
        ".pnm"         => "image/x-portable-anymap",
        ".pbm"         => "image/x-portable-bitmap",
        ".pgm"         => "image/x-portable-graymap",
        # 430
        ".ppm"         => "image/x-portable-pixmap",
        ".rgb"         => "image/x-rgb",
        ".xbm"         => "image/x-xbitmap",
        ".xpm"         => "image/x-xpixmap",
        ".xwd"         => "image/x-xwindowdump",
        # 435
        ".eml"         => "message/rfc822",
        ".iges"        => "model/iges",
        ".igs"         => "model/iges",
        ".mesh"        => "model/mesh",
        ".msh"         => "model/mesh",
        # 440
        ".silo"        => "model/mesh",
        ".vrml"        => "model/vrml",
        ".wrl"         => "model/vrml",
        ".x3db"        => "model/x3d+binary",
        ".x3dv"        => "model/x3d+vrml",
        # 445
        ".x3d"         => "model/x3d+xml",
        ".appcache"    => "text/cache-manifest",
        ".ics"         => "text/calendar",
        ".icz"         => "text/calendar",
        ".css"         => "text/css; charset=utf-8",
        # 450
        ".csv"         => "text/csv; charset=utf-8",
        ".323"         => "text/h323",
        ".htm"         => "text/html",
        ".html"        => "text/html",
        ".shtml"       => "text/html",
        # 455
        ".uls"         => "text/iuls",
        ".markdown"    => "text/markdown; charset=utf-8",
        ".md"          => "text/markdown; charset=utf-8",
        ".mml"         => "text/mathml",
        ".asc"         => "text/plain; charset=utf-8",
        # 460
        ".brf"         => "text/plain; charset=utf-8",
        ".conf"        => "text/plain; charset=utf-8",
        ".log"         => "text/plain; charset=utf-8",
        ".pot"         => "text/plain; charset=utf-8",
        ".spec"        => "text/plain; charset=utf-8",
        # 465
        ".srt"         => "text/plain; charset=utf-8",
        ".text"        => "text/plain; charset=utf-8",
        ".txt"         => "text/plain; charset=utf-8",
        ".rtx"         => "text/richtext",
        ".sct"         => "text/scriptlet",
        # 470
        ".wsc"         => "text/scriptlet",
        ".tsv"         => "text/tab-separated-values",
        ".tm"          => "text/texmacs",
        ".ttl"         => "text/turtle",
        ".vcard"       => "text/vcard",
        # 475
        ".vcf"         => "text/vcard",
        ".jad"         => "text/vnd.sun.j2me.app-descriptor",
        ".wml"         => "text/vnd.wap.wml",
        ".wmls"        => "text/vnd.wap.wmlscript",
        ".bib"         => "text/x-bibtex; charset=utf-8",
        # 480
        ".boo"         => "text/x-boo; charset=utf-8",
        ".h++"         => "text/x-c++hdr; charset=utf-8",
        ".hh"          => "text/x-c++hdr; charset=utf-8",
        ".hpp"         => "text/x-c++hdr; charset=utf-8",
        ".hxx"         => "text/x-c++hdr; charset=utf-8",
        # 485
        ".c++"         => "text/x-c++src; charset=utf-8",
        ".cc"          => "text/x-c++src; charset=utf-8",
        ".cpp"         => "text/x-c++src; charset=utf-8",
        ".cxx"         => "text/x-c++src; charset=utf-8",
        ".h"           => "text/x-chdr; charset=utf-8",
        # 490
        ".htc"         => "text/x-component",
        ".csh"         => "text/x-csh; charset=utf-8",
        ".c"           => "text/x-csrc; charset=utf-8",
        ".diff"        => "text/x-diff; charset=utf-8",
        ".patch"       => "text/x-diff; charset=utf-8",
        # 495
        ".d"           => "text/x-dsrc; charset=utf-8",
        ".hs"          => "text/x-haskell; charset=utf-8",
        ".java"        => "text/x-java; charset=utf-8",
        ".ly"          => "text/x-lilypond; charset=utf-8",
        ".lhs"         => "text/x-literate-haskell; charset=utf-8",
        # 500
        ".moc"         => "text/x-moc; charset=utf-8",
        ".p"           => "text/x-pascal; charset=utf-8",
        ".pas"         => "text/x-pascal; charset=utf-8",
        ".gcd"         => "text/x-pcs-gcd",
        ".pl"          => "text/x-perl; charset=utf-8",
        # 505
        ".pm"          => "text/x-perl; charset=utf-8",
        ".py"          => "text/x-python; charset=utf-8",
        ".scala"       => "text/x-scala; charset=utf-8",
        ".etx"         => "text/x-setext",
        ".sfv"         => "text/x-sfv",
        # 510
        ".sh"          => "text/x-sh; charset=utf-8",
        ".tcl"         => "text/x-tcl; charset=utf-8",
        ".tk"          => "text/x-tcl; charset=utf-8",
        ".cls"         => "text/x-tex; charset=utf-8",
        ".ltx"         => "text/x-tex; charset=utf-8",
        # 515
        ".sty"         => "text/x-tex; charset=utf-8",
        ".tex"         => "text/x-tex; charset=utf-8",
        ".vcs"         => "text/x-vcalendar",
        ".3gp"         => "video/3gpp",
        ".ts"          => "video/MP2T",
        # 520
        ".axv"         => "video/annodex",
        ".dl"          => "video/dl",
        ".dif"         => "video/dv",
        ".dv"          => "video/dv",
        ".fli"         => "video/fli",
        # 525
        ".gl"          => "video/gl",
        ".mp4"         => "video/mp4",
        ".mpe"         => "video/mpeg",
        ".mpeg"        => "video/mpeg",
        ".mpg"         => "video/mpeg",
        # 530
        ".ogv"         => "video/ogg",
        ".mov"         => "video/quicktime",
        ".qt"          => "video/quicktime",
        ".webm"        => "video/webm",
        ".mxu"         => "video/vnd.mpegurl",
        # 535
        ".flv"         => "video/x-flv",
        ".lsf"         => "video/x-la-asf",
        ".lsx"         => "video/x-la-asf",
        ".mkv"         => "video/x-matroska",
        ".mpv"         => "video/x-matroska",
        # 540
        ".mng"         => "video/x-mng",
        ".asf"         => "video/x-ms-asf",
        ".asx"         => "video/x-ms-asf",
        ".wm"          => "video/x-ms-wm",
        ".wmv"         => "video/x-ms-wmv",
        # 545
        ".wmx"         => "video/x-ms-wmx",
        ".wvx"         => "video/x-ms-wvx",
        ".avi"         => "video/x-msvideo",
        ".movie"       => "video/x-sgi-movie",
        ".ice"         => "x-conference/x-cooltalk",
        # 550
        ".sisx"        => "x-epoc/x-sisx-app",
        ".vrm"         => "x-world/x-vrml",
        "README"       => "text/plain; charset=utf-8",
        "Makefile"     => "text/x-makefile; charset=utf-8",
        ""             => "application/octet-stream",
        # 555
    )
    server.document-root           = "/var/www"
    server.upload-dirs             = ("/var/cache/lighttpd/uploads")
    server.errorlog                = "/var/log/lighttpd/error.log"
    server.pid-file                = "/var/run/lighttpd.pid"
    server.username                = "www-data"
    server.groupname               = "www-data"
    server.port                    = 80
    server.http-parseopts          = (
        "header-strict"            => "enable",
        "host-strict"              => "enable",
        "host-normalize"           => "enable",
        "url-normalize-unreserved" => "enable",
        "url-normalize-required"   => "enable",
        # 5
        "url-ctrls-reject"         => "enable",
        "url-path-2f-decode"       => "enable",
        "url-path-dotseg-remove"   => "enable",
        # 8
    )
    index-file.names               = ("index.php", "index.html", "index.lighttpd.html")
    url.access-deny                = ("~", ".inc")
    static-file.exclude-extensions = (".php", ".pl", ".fcgi")
    compress.cache-dir             = "/var/cache/lighttpd/compress/"
    compress.filetype              = ("application/javascript", "text/css", "text/html", "text/plain")
    url.redirect                   = (
        "^/.well-known/caldav"  => "/nextcloud/remote.php/dav",
        "^/.well-known/carddav" => "/nextcloud/remote.php/dav",
        "^/ocm-provider"        => "/nextcloud/ocm-provider",
        "^/ocs-provider"        => "/nextcloud/ocs-provider",
        # 4
    )
    fastcgi.server                 = (
        ".php" => (
            (
                "socket"                => "/run/php/php7.3-fpm.sock",
                "broken-scriptfilename" => "enable",
                # 2
            ),
        ),
    )
    server.modules                 = (
        "mod_indexfile",
        "mod_setenv",
        "mod_access",
        "mod_alias",
        "mod_redirect",
        "mod_fastcgi",
        "mod_rewrite",
        "mod_compress",
        "mod_dirlisting",
        "mod_staticfile",
        # 10
    )


    $SERVER["socket"] == "[::]:80" {
        # block 1

    } # end of $SERVER["socket"] == "[::]:80"

    $HTTP["url"] =~ "^/nextcloud($|/)" {
        # block 2
        dir-listing.activate = "disable"


        $HTTP["url"] =~ "^/nextcloud/(build|tests|config|lib|3rdparty|templates|data)($|/)" {
            # block 3
            url.access-deny = ("")

        } # end of $HTTP["url"] =~ "^/nextcloud/(build|tests|config|lib|3rdparty|templates|data)($|/)"

        $HTTP["url"] =~ "^/nextcloud/(\.|autotest|occ|issue|indie|db_|console)" {
            # block 4
            url.access-deny = ("")

        } # end of $HTTP["url"] =~ "^/nextcloud/(\.|autotest|occ|issue|indie|db_|console)"

        $HTTP["url"] =~ "^/nextcloud/.+[^/]\.(css|js|woff2?|svg|gif|map)$" {
            # block 5
            setenv.add-response-header = (
                "Cache-Control"                     => "public, max-age=15778463",
                "Referrer-Policy"                   => "no-referrer",
                "X-Content-Type-Options"            => "nosniff",
                "X-Download-Options"                => "noopen",
                "X-Frame-Options"                   => "SAMEORIGIN",
                # 5
                "X-Permitted-Cross-Domain-Policies" => "none",
                "X-Robots-Tag"                      => "none",
                "X-XSS-Protection"                  => "1; mode=block",
                # 8
            )

        } # end of $HTTP["url"] =~ "^/nextcloud/.+[^/]\.(css|js|woff2?|svg|gif|map)$"
    } # end of $HTTP["url"] =~ "^/nextcloud($|/)"
}

_Mostly Debian package defaults, the custom /nextcloud part is at the bottom.
PHP is as well default php7.3-fpm + APCu memory caching + Redis-based file locking. I can provide more details if required, just not sure what might play a role here 😉_

I have modified the source to get some additional logging:
public function getDecryptedValue(): string {
$token = explode(':', $this->value);
if (\count($token) !== 2) {
return '';
}
$obfuscatedToken = $token[0];
$secret = $token[1];
\OC::$server->getLogger()->info('obfuscatedToken: '. $obfuscatedToken .', secret: '. $secret);
$tmpReturn = base64_decode($obfuscatedToken) ^ base64_decode($secret);
\OC::$server->getLogger()->info('getDecryptedValue: '. $tmpReturn );
return base64_decode($obfuscatedToken) ^ base64_decode($secret);
}
}

With this I did the ususal test:
1) login as admin
2) goto user / protocol and see the logging
3) logout

this time successfull

4) login as admin
5) goto user / protocol and see the logging
6) logout (unsuccessfull)
7) push browsers back button
8) logout (unsuccessfull)
...
until successfull logout

Traces are attached. For details see the readme.
logs+traces.zip

Problem is not yet solved, additional logs and stack trace provided above. Issue, although Lighttpd not officially supported, is security-relevant, e.g. on public clients:

  • User logs out, receives error but might not recheck/ignore
  • Next user can access same Nextcloud session without login

I'm getting the same error with nginx, though also on https://mysite/index.php/apps/files/ajax/getstoragestats.php?dir=%2F.

I was able to reproduce this with nginx and front_controller_active true:
/logout?requesttoken=abc returns CSRF check failed, but index.php/logout?requesttoken=abc works.

I also can reproduce this issue on NC 17.0.1 using nginx.
Happy to provide logs if needed.
If I click logout twice it returns me to login screen, then upon logging with a new user I get the error:
Access forbidden
CSRF check failed

I was also getting the same error in NC 16.x - it is a smallish home server so it doesn't bother me that and I trawled through a bunch of forum posts and proposed fixes for similar issues to no avail.

This fixed this problem for me:

https://github.com/nextcloud/server/issues/1075#issuecomment-274376615

I also think this issue is a duplicate of this one: https://github.com/nextcloud/server/issues/1075

@pbalm
It is not an HTTPS-only issue. I get the same error when logging in+out via HTTP, hence forcing SSL/HTTPS is no solution there. I am testing with NC18 Beta 4 now and settings the two settings to "false" instead.


NC18 Beta 4 same issue.

'overwriteprotocol' => 'http',
'forcessl' => false,

Same issue (note I am testing HTTP here, to verify it is no HTTPS-only issue).


For testing/replicating:

  1. Login
  2. Go to settings
  3. Go to log viewer
  4. Logout

If the issue does not occur, try to restart webserver (and clear browser cache?) and redo the above. I also restarted Redis and MariaDB, but pretty sure that is not required.

Tested with:

root@VM-Buster:~# lighttpd -v
lighttpd/1.4.53 (ssl) - a light and fast webserver

root@VM-Buster:~# php -v
PHP 7.3.11-1~deb10u1 (cli) (built: Oct 26 2019 14:14:18) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.11, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.11-1~deb10u1, Copyright (c) 1999-2018, by Zend Technologies

root@VM-Buster:~# mariadb -v
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 57
Server version: 10.3.18-MariaDB-0+deb10u1 Debian 10

Just to wrap up some information, when reading through #1075:

  • It appears with all tested webservers: Apache, Nginx, Lighttpd
  • It appears with and without reverse proxy
  • It appears with HTTP + HTTPS
  • It appears when waiting for session timeout and as well when e.g. logging in, going to log viewer and logging out all in ~5 seconds.

So even that the above things seem to have some influence for people, none of it is a definite reason, nor can related changes solve it definitely. Not sure if its somehow possible, CSRF check fails, for whatever reason, to immediately mark the user as logged out for that particular session?

@MichaIng thanks for the detailed debugging info. Could you add the logs @kesselb added to his instance and additionally log the values (ref https://github.com/nextcloud/server/issues/17065#issuecomment-536923540) so we can get a bit more info about why this check is failing?

@ChristophWurst
I'll do. Any preference whether to do this on stable v17.0.2 or current v18 RC1? Latter makes more sense?

Thanks! It shouldn't matter :)

Okay I updated an instance to 18 RC2 and disabled all apps but log viewer to have latest code and remove any possible apps influence. Then edited:
lib/private/Security/CSRF/CsrfTokenManager.php

        public function isTokenValid(CsrfToken $token): bool {
                if(!$this->sessionStorage->hasToken()) {
                        return false;
                }

                // DEBUG START
                $isEqual = hash_equals($this->sessionStorage->getToken(), $token->getDecryptedValue());
                if (!$isEqual) {
                        \OC::$server->getLogger()->warning('going to validate csrf token "' . $this->sessionStorage->getToken() . '" with "' . $token->getDecryptedValue() . '"');
                }
                // DEBUG END

                return hash_equals(
                        $this->sessionStorage->getToken(),
                        $token->getDecryptedValue()
                );
        }

lib/private/Security/CSRF/CsrfToken.php

        public function getDecryptedValue(): string {
                $token = explode(':', $this->value);
                if (\count($token) !== 2) {
                        return '';
                }
                $obfuscatedToken = $token[0];
                $secret = $token[1];
                // DEBUG START
                \OC::$server->getLogger()->info('obfuscatedToken: '. $obfuscatedToken .', secret: '. $secret);
                $tmpReturn = base64_decode($obfuscatedToken) ^ base64_decode($secret);
                \OC::$server->getLogger()->info('getDecryptedValue: '. $tmpReturn );
                // DEBUG END
                return base64_decode($obfuscatedToken) ^ base64_decode($secret);
        }
  1. Access + login Nextcloud
  2. Access log viewer... my goodness, produces tenth of logs every second from getDecryptedValue, obviously the log viewer poll triggers the event.
  3. Log out:
Zugriff verboten
CSRF check failed
  1. Remove debug code
  2. Open Nextcloud freshly on new browser tab: I was still logged in, demonstrating the bug and its security issue very well!
  3. Check logs:
[no app in context] Info: obfuscatedToken: nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8=, secret: 1Uojl+2AKgpYDC+p6bY678RoUus2EgT1DPPem7GjQRY=
GET /nextcloud/index.php/apps/logreader/poll?lastReqId=Me8CKtvlgIogiTMhvoy3
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

[no app in context] Info: getDecryptedValue: IoWyYKJq+WeupuooHoRkzgcfFJ/jtp3Y
GET /nextcloud/index.php/apps/logreader/poll?lastReqId=Me8CKtvlgIogiTMhvoy3
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

# Below two entries come two times, as can be seen with slightly changed secret, having "+" replaced with white spaces, decrypted value changed accordingly?

[no app in context] Info: obfuscatedToken: nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8=, secret: 1Uojl 2AKgpYDC p6bY678RoUus2EgT1DPPem7GjQRY=
GET /nextcloud/index.php/logout?requesttoken=nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8%3D%3A1Uojl%2B2AKgpYDC%2Bp6bY678RoUus2EgT1DPPem7GjQRY%3D
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

[no app in context] Info: getDecryptedValue: IoWyÔÁâípQÔGúm©Æ   )³ál:7\wPJëñÂ
GET /nextcloud/index.php/logout?requesttoken=nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8%3D%3A1Uojl%2B2AKgpYDC%2Bp6bY678RoUus2EgT1DPPem7GjQRY%3D
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

[no app in context] Warning: going to validate csrf token "IoWyYKJq+WeupuooHoRkzgcfFJ/jtp3Y" with "IoWyÔÁâípQÔGúm©Æ )³ál:7\wPJëñÂ"
GET /nextcloud/index.php/logout?requesttoken=nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8%3D%3A1Uojl%2B2AKgpYDC%2Bp6bY678RoUus2EgT1DPPem7GjQRY%3D
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

[no app in context] Info: obfuscatedToken: nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8=, secret: 1Uojl 2AKgpYDC p6bY678RoUus2EgT1DPPem7GjQRY=
GET /nextcloud/index.php/logout?requesttoken=nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8%3D%3A1Uojl%2B2AKgpYDC%2Bp6bY678RoUus2EgT1DPPem7GjQRY%3D
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

[no app in context] Info: getDecryptedValue: IoWyÔÁâípQÔGúm©Æ   )³ál:7\wPJëñÂ
GET /nextcloud/index.php/logout?requesttoken=nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8%3D%3A1Uojl%2B2AKgpYDC%2Bp6bY678RoUus2EgT1DPPem7GjQRY%3D
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

# Below two entries again come two times, showing secret and decrypted value as it was before the logout.

[no app in context] Info: obfuscatedToken: nCV07rTLYHtzW0rcmcNVgIwHAIBMdWeTSrnx8cXTck8=, secret: 1Uojl+2AKgpYDC+p6bY678RoUus2EgT1DPPem7GjQRY=
GET /nextcloud/index.php/apps/logreader/poll?lastReqId=IBpRq6Ll1fjC4vocsFCP
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00

[no app in context] Info: getDecryptedValue: IoWyYKJq+WeupuooHoRkzgcfFJ/jtp3Y
GET /nextcloud/index.php/apps/logreader/poll?lastReqId=IBpRq6Ll1fjC4vocsFCP
from 192.168.178.21 by admin at 2020-01-09T22:20:49+00:00
  • As can be seen, the token secret, related to the logout, has two + replaced by white spaces, which leads to a changed decrypted value, I guess?
  • Afterwards (before I removed debug code and reloaded/re-accessed Nextcloud) token secret and decrypted value changed back to what they were before.
  • So finally it looks like that, for the logout request, the token secret is handled wrong, probably replacing/expending certain "magic" characters, or wrong variable type or such?

From GET request it can be seen that the + in secret is translated to %2B, at least within the log entry, as well when checking the log file directly or raw formatted output. Okay but this is correct URL coding for +.

In UweDoe logs above, I see the same, + being replaced by white spaces in logout related entries: https://github.com/nextcloud/server/issues/17065#issuecomment-537486778
Is there a way to force a certain token without + to test with? 😉


EDIT

Bingo! I restarted new sessions, until I got a token without + inside its secret (and obfuscated token string as well none by chance), and logout worked well:

[no app in context] Info: obfuscatedToken: 4L1Ejh5r2FHZONJDUy3WzWjlihWSXt2aAUKGGdFClFQ=, secret: qdIT90cgkiDyb7c2I1i5oiCK2H7oOb78Rwipc6Uypw0=
GET /nextcloud/index.php/apps/logreader/poll?lastReqId=J1ldwJroHzasyuDr2oMF
from 192.168.178.21 by admin at 2020-01-09T23:40:11+00:00

[no app in context] Info: obfuscatedToken: 4L1Ejh5r2FHZONJDUy3WzWjlihWSXt2aAUKGGdFClFQ=, secret: qdIT90cgkiDyb7c2I1i5oiCK2H7oOb78Rwipc6Uypw0=
GET /nextcloud/index.php/logout?requesttoken=4L1Ejh5r2FHZONJDUy3WzWjlihWSXt2aAUKGGdFClFQ%3D%3AqdIT90cgkiDyb7c2I1i5oiCK2H7oOb78Rwipc6Uypw0%3D
from 192.168.178.21 by admin at 2020-01-09T23:40:11+00:00

This explains why some users report contradictory solutions and sometimes waiting for a token timeout solves, sometimes creates the logout issue. It is simply about if the token strings contain + characters or not, or possible other affected characters, although I could not find any others.

Thanks :+1:

https://github.com/nextcloud/server/blob/5bf3d1bb384da56adbf205752be8f840aac3b0c5/lib/private/legacy/user.php#L280

https://github.com/nextcloud/server/blob/d393b1612bab004359621500ff5e771d10165a95/lib/private/AppFramework/Http/Request.php#L490

If we encode it first we probably have to decode it later ;) Are you able to reproduce with $token = urldecode($this->items['get']['requesttoken']);?

This explains why some users report contradictory solutions and sometimes waiting for a token timeout solves, sometimes creates the logout issue. It is simply about if the token strings contain + characters or not, or possible other affected characters, although I could not find any others.

Oh wow. I never thought about that.

Thanks you two, this is some stellar debugging work :pray:

@kesselb
lib/private/AppFramework/Http/Request.php

        public function passesCSRFCheck(): bool {
                if($this->csrfTokenManager === null) {
                        return false;
                }

                if(!$this->passesStrictCookieCheck()) {
                        return false;
                }

                if (isset($this->items['get']['requesttoken'])) {
                        $token = urldecode($this->items['get']['requesttoken']);
                } elseif (isset($this->items['post']['requesttoken'])) {
                        $token = $this->items['post']['requesttoken'];
                } elseif (isset($this->items['server']['HTTP_REQUESTTOKEN'])) {
                        $token = $this->items['server']['HTTP_REQUESTTOKEN'];
                } else {
                        //no token found.
                        return false;
                }
                $token = new CsrfToken($token);

                return $this->csrfTokenManager->isTokenValid($token);
        }

Issue stays the same:

[no app in context] Info: obfuscatedToken: NTDWiyTQK3ztBRgmc61+hmtdgcl4Y+6wKOkYZMtSoOw=, secret: BmKU5ku8ZyrZXVVrRMwLtA9p2IU+IMH5WqVPJr0L06Q=
GET /nextcloud/index.php/apps/logreader/poll?lastReqId=4Ii888Bm3GM431fg6zdS
from 192.168.178.21 by admin at 2020-01-10T11:54:42+00:00

[no app in context] Info: obfuscatedToken: NTDWiyTQK3ztBRgmc61 hmtdgcl4Y 6wKOkYZMtSoOw=, secret: BmKU5ku8ZyrZXVVrRMwLtA9p2IU IMH5WqVPJr0L06Q=
GET /nextcloud/index.php/logout?requesttoken=NTDWiyTQK3ztBRgmc61%2Bhmtdgcl4Y%2B6wKOkYZMtSoOw%3D%3ABmKU5ku8ZyrZXVVrRMwLtA9p2IU%2BIMH5WqVPJr0L06Q%3D
from 192.168.178.21 by admin at 2020-01-10T11:54:42+00:00
  • As can be seen, obfuscated token and secret strings are both still affected.

I checked what happens if I wrap all three into urldecode function, at this URL codes seem to be quick specific, but now + => whitespace happens on all token strings (EDIT: Expected since + decodes to white space):

{"reqId":"iCzR0Kw3n8MlmOts7i9f","level":1,"time":"2020-01-10T12:11:03+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"PROPFIND","url":"/nextcloud/remote.php/dav/files/admin/","message":"obfuscatedToken: YbRMj84EJi5KsV30 9XKGOXFMilO4oEx85EVO yRCvY=, secret: NIY zJttbFgv/wSigf6JS4uxehohkth5t9smcNj8WaI=","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
{"reqId":"iCzR0Kw3n8MlmOts7i9f","level":2,"time":"2020-01-10T12:11:03+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"PROPFIND","url":"/nextcloud/remote.php/dav/files/admin/","message":"going to validate csrf token \"U2rCUiJveNYVz+CSntH3opYHDJ3K4mST\" with \"U\u00a9\u0015_0%\u00b5puT\u008a\u00d0\u00d4\u00db\u009d\u0012\f\u00db\u00dc\u0016R\u0011\u0012\u008c\u00d2\u00ff/\u00b9\"","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
{"reqId":"iCzR0Kw3n8MlmOts7i9f","level":1,"time":"2020-01-10T12:11:03+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"PROPFIND","url":"/nextcloud/remote.php/dav/files/admin/","message":"obfuscatedToken: YbRMj84EJi5KsV30 9XKGOXFMilO4oEx85EVO yRCvY=, secret: NIY zJttbFgv/wSigf6JS4uxehohkth5t9smcNj8WaI=","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
{"reqId":"jJbXTmNhIed3wEVJryDE","level":1,"time":"2020-01-10T12:11:06+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"GET","url":"/nextcloud/index.php/logout?requesttoken=YbRMj84EJi5KsV30%2B9XKGOXFMilO4oEx85EVO%2ByRCvY%3D%3ANIY%2BzJttbFgv%2FwSigf6JS4uxehohkth5t9smcNj8WaI%3D","message":"obfuscatedToken: YbRMj84EJi5KsV30 9XKGOXFMilO4oEx85EVO yRCvY=, secret: NIY zJttbFgv/wSigf6JS4uxehohkth5t9smcNj8WaI=","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
{"reqId":"jJbXTmNhIed3wEVJryDE","level":1,"time":"2020-01-10T12:11:06+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"GET","url":"/nextcloud/index.php/logout?requesttoken=YbRMj84EJi5KsV30%2B9XKGOXFMilO4oEx85EVO%2ByRCvY%3D%3ANIY%2BzJttbFgv%2FwSigf6JS4uxehohkth5t9smcNj8WaI%3D","message":"obfuscatedToken: YbRMj84EJi5KsV30 9XKGOXFMilO4oEx85EVO yRCvY=, secret: NIY zJttbFgv/wSigf6JS4uxehohkth5t9smcNj8WaI=","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
{"reqId":"jJbXTmNhIed3wEVJryDE","level":2,"time":"2020-01-10T12:11:06+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"GET","url":"/nextcloud/index.php/logout?requesttoken=YbRMj84EJi5KsV30%2B9XKGOXFMilO4oEx85EVO%2ByRCvY%3D%3ANIY%2BzJttbFgv%2FwSigf6JS4uxehohkth5t9smcNj8WaI%3D","message":"going to validate csrf token \"U2rCUiJveNYVz+CSntH3opYHDJ3K4mST\" with \"U\u00a9\u0015_0%\u00b5puT\u008a\u00d0\u00d4\u00db\u009d\u0012\f\u00db\u00dc\u0016R\u0011\u0012\u008c\u00d2\u00ff/\u00b9\"","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
{"reqId":"jJbXTmNhIed3wEVJryDE","level":1,"time":"2020-01-10T12:11:06+00:00","remoteAddr":"192.168.178.21","user":"admin","app":"no app in context","method":"GET","url":"/nextcloud/index.php/logout?requesttoken=YbRMj84EJi5KsV30%2B9XKGOXFMilO4oEx85EVO%2ByRCvY%3D%3ANIY%2BzJttbFgv%2FwSigf6JS4uxehohkth5t9smcNj8WaI%3D","message":"obfuscatedToken: YbRMj84EJi5KsV30 9XKGOXFMilO4oEx85EVO yRCvY=, secret: NIY zJttbFgv/wSigf6JS4uxehohkth5t9smcNj8WaI=","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3970.5 Safari/537.36","version":"18.0.0.9"}
  • Probably something wrong with the urldecode function?

Hmm, probably some urlencode is missing? EDIT: request URL in browser and GET is encoded as required

php -r 'echo urlencode("abc+abc");';echo
abc%2Babc
php -r 'echo urldecode("abc%2Babc");';echo
abc+abc
php -r 'echo urldecode("abc+abc");';echo
abc abc
php -r 'echo urlencode("abc abc");';echo
abc+abc
  • + decodes to white space, so it must be encoded to %2B first before being decoded.

Or decode is done doubled somewhere?

  • %2B is shown in browser URL and GET, which should be correct
  • Probably it is decoded to + at some place and then decoded again, so + is decoded to white space?

Added logging now like this:
lib/private/AppFramework/Http/Request.php

        public function passesCSRFCheck(): bool {
                if($this->csrfTokenManager === null) {
                        return false;
                }

                if(!$this->passesStrictCookieCheck()) {
                        return false;
                }

                if (isset($this->items['get']['requesttoken'])) {
                        $token = $this->items['get']['requesttoken'];
            // START DEBUG
                        \OC::$server->getLogger()->warning('requesttoken: '. $token);
            // END DEBUG
                } elseif (isset($this->items['post']['requesttoken'])) {
                        $token = $this->items['post']['requesttoken'];
                } elseif (isset($this->items['server']['HTTP_REQUESTTOKEN'])) {
                        $token = $this->items['server']['HTTP_REQUESTTOKEN'];
                } else {
                        //no token found.
                        return false;
                }
                $token = new CsrfToken($token);

                return $this->csrfTokenManager->isTokenValid($token);
        }

Important part of the received log:

requesttoken: jW9QFyNHKQpKHVU b9Giylc03lxKyt7thEuh9ZE8niM=:wicnJRQDYnAyKDZqROHQgjtCsjswmZOH/i3YuNpIpmU=
  • White space inside, logout failed.

With $token = urldecode($this->items['get']['requesttoken']);:

requesttoken: 4XhN/pNv6jtLheHnUKQhqRPIl57JzmmEnp3nVQH3IAQ=:rjA6zKQroUEzsIKze5RT4X /mznSTu5PueGEqDGEI=
  • White spaces and slashes inside, looks even worse, logout failed.

With $token = urlencode($this->items['get']['requesttoken']); (just for debugging, of course this looks totally unreasonable):

requesttoken: eUWM5dtfC5leylElezVx4zqfE72Bv7Kw+kRm+NKf2Vc%3D%3ANg371+wbQOMm%2FzJxUAUDq1bpf9r77P%2FagCIftZnr4RE%3D
  • + are now there as wanted, but other characters like = are now encrypted which breaks logout again.

So from what I see, somewhere the URL decryption is done already, probably PHP internally when scraping request strings? However only the + is somehow decrypted doubled. The GET and browser request URL string looks totally fine.


Hack $token = str_replace(' ','+',$this->items['get']['requesttoken']);

requesttoken: m/1c4cFcSuhYHPvgPzPMSBsVszduK1kMg0Ky1LlkCbw=:1LUr0/YYAZIgKZi0FAO+AHdj31AUeBRm+STLmfIQMfo=
  • Logout succeeded 😃.
  • Obviously + is interpreted somewhere along the items[] array handling until read in passesCSRFCheck() function. Probably as string/array concatenation or something, so it needs to be escaped in the very first place? But I have not much knowledge about PHP coding 😅.

https://3v4l.org/aXnXQ

rawurlencode and rawurldecode should work.

@kesselb
I'll test it in the evening. See my last bloody workaround which works fine:

$token = str_replace(' ','+',$this->items['get']['requesttoken']);

I'm still a bit puzzled.

https://3v4l.org/aXnXQ

rawurlencode and rawurldecode should work.

https://3v4l.org/As3Bo
But they work just as fine with the normal ones.

In any case here php automatically does the decoding. They are url encoded so we can pass them in a url. See https://www.php.net/manual/en/function.urldecode.php and esp:

Warning The superglobals $_GET and $_REQUEST are already decoded. Using urldecode() on an element in $_GET or $_REQUEST could have unexpected and dangerous results.

@MichaIng how does the url in your network console look that gets accessed? Is that properly encoded?

A quick test file. Since that is easier than debugging nextcloud

https://gist.github.com/rullzer/14ca2778cb71f85a3272da3c4e6f2cdc

if you enter that via: <SERVER>?token=ABC%2BDEF+GHI

What does that give you all?

urlencode

Returns a string in which all non-alphanumeric characters except -_. have been replaced with a percent (%) sign followed by two hex digits and spaces encoded as plus (+) signs.

... which accordingly means that (+) signs are decoded as spaces. What I still don't get is that the (+) signs are correctly encoded first, it seems, but auto-decoded PHP-internally (?) wrong or doubled? I mean how does PHP know if the string is raw-encoded, or not, hence if (+) must be decoded or not?

For the encoding done in Nextcloud, it should not matter if raw or non-raw encode is used, since the request strings do not contain white spaces anyway. In both cases, (+) is correctly encoded, hence the decode function (PHP-internally, which is urldecode (non-raw)) should not matter as well. There is definitely another reason why (+), and only (+), is decoded two times (%2B => + => space), probably not even by URL decoding done PHP-internally, but probably at another place in code when handling the strings/arrays, etc...

However I am corrently not at home, will test the above later.

@rullzer

2020-01-11 00:16:08 root@VM-Buster:/var/www$ cat test.php
<?php
$token = $_GET['token'];
var_dump($token);
$encToken = urlencode($token);
?>
<br>
<a href="?token=<?php echo $token; ?>">Go to: ?<?php echo $token; ?></a><br>
<a href="?token=<?php echo $encToken; ?>">Go to: ?<?php echo $encToken; ?></a><br>

http://192.168.178.30/test.php?token=ABC%2BDEF+GHI

string(11) "ABC DEF GHI"
Go to: ?ABC DEF GHI
Go to: ?ABC+DEF+GHI

Using spaces, + or %2B all results in spaces in string, hence result is exactly the same in all cases 🤔. Spaces are encoded to +, so the encrypted string is as it should be.

So it is PHP-internal indeed, very strange.... So there is no chance to preserve a + from input URL? I can't believe it...


Reference: https://stackoverflow.com/questions/2671840/php-plus-sign-with-get-query
Further testing:

<?php echo $_GET['token']; ?><br>
<?php echo urlencode('A+B'); ?><br>
<?php echo rawurlencode('A+B'); ?><br>
<?php echo urldecode('A%2BB'); ?><br>
<?php echo rawurldecode('A%2BB'); ?>

Result, regardless of how + has been decoded or not in URL:

A B
A%2BB
A%2BB
A+B
A+B

So all research leads to urlencode/rawurlencode being the solution for lost + signs, but that doesn't work for me.


Back to webserver (lighttpd/1.4.53 Debian Buster package)

  • default:
server.http-parseopts = (
  "header-strict"           => "enable",# default
  "host-strict"             => "enable",# default
  "host-normalize"          => "enable",# default
  "url-normalize-unreserved"=> "enable",# recommended highly
  "url-normalize-required"  => "enable",# recommended
  "url-ctrls-reject"        => "enable",# recommended
  "url-path-2f-decode"      => "enable",# recommended highly (unless breaks app)
 #"url-path-2f-reject"      => "enable",
  "url-path-dotseg-remove"  => "enable",# recommended highly (unless breaks app)
 #"url-path-dotseg-reject"  => "enable",
 #"url-query-20-plus"       => "enable",# consistency in query string
)
  • Change to the following resolves the issue:
server.http-parseopts = (
  "header-strict"           => "enable",# default
  "host-strict"             => "enable",# default
  "host-normalize"          => "enable",# default
 #"url-normalize-unreserved"=> "enable",# recommended highly
 #"url-normalize-required"  => "enable",# recommended
 #"url-ctrls-reject"        => "enable",# recommended
 #"url-path-2f-decode"      => "enable",# recommended highly (unless breaks app)
 #"url-path-2f-reject"      => "enable",
 #"url-path-dotseg-remove"  => "enable",# recommended highly (unless breaks app)
 #"url-path-dotseg-reject"  => "enable",
 #"url-query-20-plus"       => "enable",# consistency in query string
)
  • identifying the malicious option...

The following works, proving url-normalize-required as malicious Lighttpd option:
_(url-query-20-plus has no effect btw, the comment made me give it a try)_

server.http-parseopts = (
  "header-strict"           => "enable",# default
  "host-strict"             => "enable",# default
  "host-normalize"          => "enable",# default
  "url-normalize-unreserved"=> "enable",# recommended highly
 #"url-normalize-required"  => "enable",# recommended
  "url-ctrls-reject"        => "enable",# recommended
  "url-path-2f-decode"      => "enable",# recommended highly (unless breaks app)
 #"url-path-2f-reject"      => "enable",
  "url-path-dotseg-remove"  => "enable",# recommended highly (unless breaks app)
 #"url-path-dotseg-reject"  => "enable",
 #"url-query-20-plus"       => "enable",# consistency in query string
)

Is it really the webservers job to manipulate URL/query strings on parsing, which can only (?) have any dangerous effect when forwarded to another server/handler like PHP? It is the task of the PHP script to handle those strings correctly and of the PHP implementation to limit access to defined areas, isn't it?
It was really the last idea I had to recheck/test webserver configs...

Summary

  • The Lighttpd option url-normalize-required seems to decode the URL (partly) before passing it to PHP.
  • This is enabled by default on Raspbian+Debian Buster Lighttpd package.
  • Generally those URL parse options seem dangerous to me, since unpredictable/unexpected, and I can't find similar options in Apache and Nginx. Hence for now I suppose that reports of this failure on the latter two webservers are due to wrong configured proxy servers and/or rewrites/redirects where query strings are handled wrong.

The question is if it should be ignored, since Lighttpd is not officially supported, or if some workaround should be implemented. Since $_GET['token'] regularly has no spaces, those could be simply replaced back with +, if present: str_replace(' ','+',$str). Shouldn't add some security risk and if the token string is wrong anyway for another reason (so that it contains spaces), then this will not produce additional damage at least.

Good finding :+1:

https://www.lighttpd.net/2019/5/27/1.4.54/ will be more strict and probably break other requests.

some workaround should be implemented.

Please keep in mind that such "hey it would be good ..." changes always have a price tag. At some point people don't remember why it has been added or expect the behaviour to be default.

If I understand you correctly it's possible to turn off the normalization. That would be something for the docs. Probably a own lighttpd page.

Also good to know: https://news.netcraft.com/archives/2019/12/10/december-2019-web-server-survey.html

I am also encountering this problem with nginx too. So I don't think it is
encountered only on lighthttpd.

On Sat, 11 Jan 2020, 9:58 pm kesselb, notifications@github.com wrote:

Good finding 👍

https://www.lighttpd.net/2019/5/27/1.4.54/ will be more strict and
probably break other requests.

some workaround should be implemented.

Please keep in mind that such "hey it would be good ..." changes always
have a price tag. At some point people don't remember why it has been added
or expect the behaviour to be default.

If I understand you correctly it's possible to turn off the normalization.
That would be something for the docs. Probably a own lighttpd page.

Also good to know:
https://news.netcraft.com/archives/2019/12/10/december-2019-web-server-survey.html


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/nextcloud/server/issues/17065?email_source=notifications&email_token=AGP7VZQY7UYJ63SR6FMU63TQ5GQ6VA5CNFSM4IU3GXY2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIV7KEA#issuecomment-573306128,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AGP7VZSIEEKGUL5DCFWTWQ3Q5GQ6VANCNFSM4IU3GXYQ
.

Please keep in mind that such "hey it would be good ..." changes always have a price tag. At some point people don't remember why it has been added or expect the behaviour to be default.

@kesselb
Such must always be implemented with proper comments and at best link to related discussion, so everyone is able to track why/where it's coming from. But after sleeping a night over it, I agree having a Lighttpd page in Nextcloud docs to point this out, and disable conflicting options right in the webserver, makes more sense then having query strings coded back and forth as a result of a workaround.

Btw: https://redmine.lighttpd.net/projects/lighttpd/wiki/Server_http-parseoptsDetails

  • Those url-normalize* all mean that %-encodings are decoded... That is all completely unreasonable IMO. Why would one encode characters if not for a certain reason, to decode manually afterwards or because PHP does this job already. That PHP does this job automatically on the $_GET array is already a reason for hundreds of stackoverflow and similar threads (from what I found yesterday 😉) and now the webserver does it as well... great job, tripple decoding for coders who expect the obvious and use urldecode in their scripts...
  • So IMO all those options must be disabled to have no unexpected translations, e.g. url-path-2f-decode > translate %2F to / and there is a bunch more that breaks random strings. Sadly one cannot simply remove the server.http-parseopts block since all those are enabled by default, hence must be disabled explicitly.

But another topic:
Since this issue only occurs on logout, it seems that this is the only case where the session token is transmitted via request URL hence parsed from $_GET? Is this really necessary? Wouldn't it be more reasonable to keep this server-internally hidden from eyes and monitors? In theory if one is able to catch the browser URL with obfuscated token and secret visible, from a publicly placed monitor, one would be able to log into the same session currently, as long as the token is valid?
I have no insight about how such in handled, but e.g. the log viewer app is well aware which session (token) it is accessed with without having it as part of the request URL (?). Couldn't the logout "button" get the session that is to be logged out (hence the token that is to be invalidated) as well receive this info server-internally?


@tsposato
Do you have any proxy, VPN, machine internal rewrites or redirects in front of your Nextcloud instance, aside of the redirects apart from the ones of the docs Nginx config example?

@MichaIng thanks for testing.
But this indeed very weird and troubling as well.

As you can see Nextcloud itself doesn't do the url decode on those but then happen when things are passed to php. So I agree this is an issue in the webserver configs.

As for why this is in the URL. It is because logout is a GET request. The token is there to prevent CSRF attacks. We now have more modern ways to deal with this. But the issue is that we can't guarantee they work in all versions. And being able to logout is kind of critical.

I discussed with @ChristophWurst the others day. For 19 we could try to migrate this menu to Vue. And then we could do some smarter things.

However, as we still want to pass the token. But then it will be passed in POST. We should double test if this is handled properly.

@rullzer
Sounds reasonable. Yeah as logout indeed is critical the method should be failsafe as possible. However this is the reason why a correct token is critical which is with Lighttpd defaults and some other cases (as report(s) above) not the case. Moving away from GET would at least avoid issues with pre-decoded URL parts.

I will open a new issue about adding Lighttpd to the docs. I currently have not the time for a PR, but will link a related threat from forum and the config we use on DietPi as a start.

@MichaIng could you modify the script I posted to see if POST is also double escaped?

And thanks a bunch for your debugging efforts. Really appercicated and good that we did find why it happens sometimes.

@rullzer
learning how to send a POST request via PHP: https://stackoverflow.com/questions/5647461/how-do-i-send-a-post-request-with-php#6609181

~Which method is used in Nextcloud, cURL or no cURL?~
EDIT: Okay 19 hits vs 0 hits of related function. So non-cURL method. Will test this night.

@MichaIng or just use curl.

curl -X POST -d 'token=FOO' SERVER

Thanks for all the debugging efforts everyone!

Besides the logout page I've also seen this error during the execution of the web updater. When finalizing the update (update schema, apps, ..) by clicking the button, I got this error as well. Going back to the previous page and clicking the button again worked after a few attempts. Same as during the logout.

Webserver: lighttpd 1.4.53
Nextcloud: 17.0.2

@GeorgFleig
Do you remember or can you replicate whether the URL in browser contains the token string, hence this is a GET request as well? Would fit actually, also fits to your solution to retry for certain times (until the token strings contain no +). Ah the others will know already.

Note that there's a known bug in lighttpd-1.4.53 involving expansion of + characters. This is planned to be fixed in 1.4.55.

https://redmine.lighttpd.net/issues/2999

I run into this same issue with nginx. Is this a similar problem with the nginx config? Is there a way I can test and get logs which will help?

I think there are two separate bugs here :(

@d235j
Many thanks for linking this, so at least we're not the only ones who recognised this to be an issue.

However I am not 100% sure about this really being a "bug" and as well the solution looks more like a workaround that makes the whole concept inconsistent.

+ IS in fact the correct URL encoding for spaces. So as this Lighttpd option is to decode the URL string, this is done totally correct. It just breaks thinks when a second decoding is done afterwards. This seems to be a bid unique to %2B => + => <space>, since it is one of rare (or only?) single characters, coding other characters.

Now from what I see, the "fix" simply excludes the + from decoding. So now when someone encodes a string with white spaces, those will be encoded as + (together with other characters to their %XX codes), but when Lighttpd decodes this via this option, all BUT the + is decoded back. Hence you have a half/half decoded string, which of course is a total mess for anything that wants to parse that afterwards.

Decoding MUST only be done once, in every case, it is as simple as this. As PHP decodes the $_GET array automatically, any previous decoding potentially breaks every PHP script which needs to read that, explicitly if contained raw string contains + symbols.

@tsposato
Do you have any proxy or VPN or custom rewrite/redirects on front of the Nginx webserver, so anything that in theory or obviously manipulates or writes the URL/query string to a new request?

@MichaIng I checked my server logs. The URL does indeed contain the requesttoken and this token contained %2B when the request was failing. No %2B for the successful requests. So this seems to be the same issue. The URL in question was /core/ajax/update.php?requesttoken=.

@GeorgFleig
Thanks for checking, so yes this is basically the same issue. Similarly it is hopefully possible to migrate this to a POST request.

@rullzer
Finally did the POST test, sorry for the delay:

2020-01-18 16:31:49 root@VM-Buster:/var/www$ cat index.php
<?php
$url = 'http://localhost/receive.php';
$data = array('raw' => 'A+B', 'encoded' => 'A%2BB');

$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'method'  => 'POST',
        'content' => http_build_query($data)));

$response = file_get_contents($url, false, stream_context_create($options));

echo 'POST data: ', var_dump($data), 'Response raw: ', $response, 'Response decoded ', urldecode($response);
echo 'GET: ', var_dump($_GET)
?>

2020-01-18 16:32:08 root@VM-Buster:/var/www$ cat receive.php
<?php var_dump($_POST) ?>

2020-01-18 16:32:11 root@VM-Buster:/var/www$ curl 'localhost?raw=A+B&encoded=A%2BB'
POST data: array(2) {
  ["raw"]=>
  string(3) "A+B"
  ["encoded"]=>
  string(5) "A%2BB"
}
Response raw: array(2) {
  ["raw"]=>
  string(3) "A+B"
  ["encoded"]=>
  string(5) "A%2BB"
}
Response decoded array(2) {
  ["raw"]=>
  string(3) "A B"
  ["encoded"]=>
  string(5) "A+B"
}
GET: array(2) {
  ["raw"]=>
  string(3) "A B"
  ["encoded"]=>
  string(3) "A B"
}

2020-01-18 16:32:16 root@VM-Buster:/var/www$ curl -X POST -d 'raw=A+B&encoded=A%2BB' localhost/receive.php
array(2) {
  ["raw"]=>
  string(3) "A B"
  ["encoded"]=>
  string(3) "A+B"
}
  • So indeed POST request content is not decoded by Lighttpd (I had all options enabled), compared to GET content.
  • AS can be seen, also PHP does not decode it, compared to $_GET array, which IMO is actually the safest thing, so one can do the decode at a defined place.
  • Opening the page in remote browser shows exactly the same.
  • curl command from shell decodes received POST data before printing it, it seems.

I'm also impacted with CSRF major issue. This issue make talk/spreed unusable ....

I understand you are still working on fixing this.

My simple question is : Is it possible to disable CSRF check in configuration file ?

Thanks for replying me

@simogeo
The problem is not the included security check itself, but that the whole URI query string is "destroyed" by any handler before it reaches the Nextcloud script. In case of the logout, the session token is added as regular HTTP query string as identifier which user to logout from which session. Hence it must be intact for the script to do it's job, while the security check failure is only a side-symptom of the actual issue.

Please check your webserver/proxy/load balancer, if present, if those manipulate the URI, especially the query string, like Lighttpd with this option enabled.

It must be taken as a matter of fact, that transferring information via URI query simply is not failsafe since webservers, load balancers, proxies and all such can and in at best rare cases alter/decode those, before it reaches the PHP handler, where it is decoded a second time, before it reaches Nextcloud scripts. For me it is not really understandable, why any of this entities should do this, as IMO it must be matter of the final page/script to do what ever it wants to do with the query string.

thanks @MichaIng for you reply.

Actually I use Apache2 as webserver with a standard configuration (and no load balancing). I never experienced that kind of CSRF issue and do not have on others applications running on same machine ... That's why I'm suspicous on nextcloud. Furthermore, I get this issue since some updated versions ...

By the way, I get an erratic behaviour on that issue. It sometimes works correctly, sometimes not. I don't know from where to start investigating.

D'ont you think this could be due to many trusted_domain in config file ? (I have two)

@simogeo
A wrong or missing trusted domain should lead to a different error message.

That the error occurs sometimes and sometimes not is expected when you read the above discussion. I works if your current session token contains no + character and it does not work if it contains one. This is since 2%B decodes to + while a + decodes to a white space. This is the only known case currently where a doubled decoding leads to a wrong character at the final PHP script.

So the behaviour in your case indicates that the root issue is the same. I am just not sure what or where the doubled decoding happens. Probably Apache2 has a similar setting than Lighttpd, but I don't know currently which it is and where to look for it. I suggest you go through your Apache2 config + all included config snippets and mod configs and watch out for things like HTTP/URL/query normalization/decoding.

Note that there's a known bug in lighttpd-1.4.53 involving expansion of + characters. This is planned to be fixed in 1.4.55.

https://redmine.lighttpd.net/issues/2999

I was running NC17 on Debian 10 (buster) with lighttpd 1.4.53 and was also affected by this. After upgrading lighttpd to 1.4.55 from buster backports, logout was successful now without that CSRF error message anymore.

Thanks again @MichaIng
And I guess, the default nextcloud .htaccess cannot cause this trouble ?

Here is mine :

<IfModule mod_headers.c>
  <IfModule mod_setenvif.c>
    <IfModule mod_fcgid.c>
       SetEnvIfNoCase ^Authorization$ "(.+)" XAUTHORIZATION=$1
       RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION
    </IfModule>
    <IfModule mod_proxy_fcgi.c>
       SetEnvIfNoCase Authorization "(.+)" HTTP_AUTHORIZATION=$1
    </IfModule>
  </IfModule>

  <IfModule mod_env.c>
    # Add security and privacy related headers
    Header always set Referrer-Policy "no-referrer"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Download-Options "noopen"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Permitted-Cross-Domain-Policies "none"
    Header always set X-Robots-Tag "none"
    Header always set X-XSS-Protection "1; mode=block"
    SetEnv modHeadersAvailable true
  </IfModule>

  # Add cache control for static resources
  <FilesMatch "\.(css|js|svg|gif)$">
    Header set Cache-Control "max-age=15778463"
  </FilesMatch>

  # Let browsers cache WOFF files for a week
  <FilesMatch "\.woff2?$">
    Header set Cache-Control "max-age=604800"
  </FilesMatch>
</IfModule>
<IfModule mod_php7.c>
  php_value mbstring.func_overload 0
  php_value default_charset 'UTF-8'
  php_value output_buffering 0
  <IfModule mod_env.c>
    SetEnv htaccessWorking true
  </IfModule>
</IfModule>
<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{HTTP_USER_AGENT} DavClnt
  RewriteRule ^$ /remote.php/webdav/ [L,R=302]
  RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
  RewriteRule ^\.well-known/host-meta /public.php?service=host-meta [QSA,L]
  RewriteRule ^\.well-known/host-meta\.json /public.php?service=host-meta-json [QSA,L]
  RewriteRule ^\.well-known/webfinger /public.php?service=webfinger [QSA,L]
  RewriteRule ^\.well-known/nodeinfo /public.php?service=nodeinfo [QSA,L]
  RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
  RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
  RewriteRule ^remote/(.*) remote.php [QSA,L]
  RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
  RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
  RewriteRule ^(?:\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule>
<IfModule mod_mime.c>
  AddType image/svg+xml svg svgz
  AddEncoding gzip svgz
</IfModule>
<IfModule mod_dir.c>
  DirectoryIndex index.php index.html
</IfModule>
AddDefaultCharset utf-8
Options -Indexes
<IfModule pagespeed_module>
  ModPagespeed Off
</IfModule>
#### DO NOT CHANGE ANYTHING ABOVE THIS LINE ####

ErrorDocument 403 //
ErrorDocument 404 //

@simogeo
Nope the .htaccess works fine on all instances I know. Do you use php-fpm or mod-php on Apache?

It is supposed to be mod-php !

@simogeo
Okay yes if you did not actively setup php-fpm it is mod_php by default on all distros I know.

Sadly this means I have no idea why you face the issue. Lastly it means that transferring access tokens via GET request or browser URI query string is simply not reliable due to some IMO bad webserver/proxy/whatever practice and Nextcloud should switch to POST requests where possible

The issue makes nextcloud instance web interface almost unusable ...

@MichaIng : thanks for all your effort and feedback. If someone has new idea, I'll take it !

I came upon this issue as it also affects front-channel logout uri usage when using nextcloud in an OIDC configuration where login/logout are not driven by the user clicking something in nextcloud itself. Logout needs to be a GET and needs to not have a CSRF token for that use case I believe (please correct me if I'm wrong - I'd love to be wrong here).

For an example of that see: https://gluu.org/docs/gluu-server/operation/logout/

I would need to affect a logout of nextcloud by logging out of a different application both of which are controlled by an OP such as gluu.

It is possible I could work around doing the single logout scenario in that fashion (the GET, which won't work due to CSRF token) if I had a post endpoint, and a URI that wouldn't fail (and therefore also without CSRF token).

just to let you know. I've been testing a bit with chrome and it seems I do note have the same issue. That means the problem could be caused by Firefox itself or some installed plugins. I'll investigate a bit more.

(I had a look on https://github.com/nextcloud/server/issues/13893)

From all we found, the issue is not related to the browser, but to the webserver. You can verify by trying a bid more often (multiple sessions) with both browsers. Expected is that logout sometimes fails and sometimes succeeds, as the reason is if the session token by chance contains a + character or not.

Expected is that logout sometimes fails and sometimes succeeds, as the reason is if the session token by chance contains a + character or not.

Okay then, wild idea: why not make sure there's no '+' in the session token but only alphanumerics (7bit ascii) in the first place?

From all we found, the issue is not related to the browser, but to the webserver. You can verify by trying a bid more often (multiple sessions) with both browsers. Expected is that logout sometimes fails and sometimes succeeds, as the reason is if the session token by chance contains a + character or not.

Indeed ... I have to say again that my problem is not only on logout but on "random" (ajax) call ... I've tried not forcing SSL redirect from .htaccess Apache file. (Should I start a new issue ?)

Very likely AJAX sends a GET request as well. To be true, I am not sure how those session tokens are created, probably a 3rd party library does this so that the characters are out of control of Nextcloud. I think the sustainable solution indeed is to switch to POST requests everywhere and by this avoid bearing the query string at all. While in case of single characters, the + sign seems to be the only issue here, just in theory the decoded string could contain other patterns which would then be re-decoded non-intentionally.

@ChristophWurst @rullzer
Any more info required from your side? I can do further testing/debugging and such, but I lack the insights and PHP coding experience to open a PR. As well it looks like a more fundamental change to switch everything to POST (not only logout), but it makes sense to implement it fully and consequently when already touching it?

In my case the "CSFR check failed" appeared in Firefox after I turned off opcache.save-comments, because I wanted to test the caching. Vivaldi showed me where the problem was.

Please verify that it can be repeatedly (new login sessions) replicated with opcache.save-comments enabled respectively disabled. Would be an interesting find but I cannot imagine how it can have an influence since cached PHP script comments should have no influence on the query string? But probably it breaks something else, causing the same error.
Since the error does not show up consistently based on the change of a + in the query string, it is important to verify that any change causes or fixes the error consistently.

Could you show the exact hint that Vivaldi gave you, pointing to opcache.save-comments?

I finally identified the issue which was relative to permissions on PHP sessions folder.

A chmod 777 / 755 on /var/lib/php/sessions fixed it !

Sessions works well on others vhosts...

Good to know that this leads to the same error.
733 should be btw sufficient, so that the webserver/PHP user is able to create session files. However doesn't matter much as long as the contained session files have 600.

Good to know that this leads to the same error.
733 should be btw sufficient, so that the webserver/PHP user is able to create session files. However doesn't matter much as long as the contained session files have 600.

Actually and strangely I needed to chmod 777 ... with 755 permissions users were not able to login !

755 of course does not work since it does not include write permissions (5 = 1 (execute) + 4 (read)). So the webserver/PHP is not able to create the session files. 733 implies write permissions (3 = 1 (execute) + 2 (write)) but denies the non-required read (file listing) permissions. Since session files are sensitive, I would follow the defaults and deny content listing for all users (but root).

Sure ! Thanks for pointing this out !

Actually and strangely I needed to chmod 777 ... with 755 permissions users were not able to login !

777 is most probably not necessary. Your lighttpd runs as certain user/group. Rights are given for user, group, and other. Why would _every_ other user need write permissions to your session files? And besides: this is also most certainly off-topic for this ticket?!

The default on Debian/Raspbian/Ubuntu is:

chown root:root /var/lib/php/sessions
chmod 1733 /var/lib/php/sessions
  • Via root owner + sticky bit it is possible that webserver/PHP can create files but noch remove them. Removal is instead regularly done via systemd unit or cron job, running as root.
  • root:www-data + 1730 would allow the same without granting _every_ user write access, however it limits usage to a single PHP "client" or FPM pool user, while generally multiple "clients" can invoke PHP (via different methods and users) and multiple FPM pools can run as different users, but all share the same session dir. So with root:www-data + 1730 one would need to add all PHP-invoking users to www-data group, which again implies other permissions that might not be wanted. I guess root:root + 1733 was chosen as best practical + security balance.

And besides: this is also most certainly off-topic for this ticket?!

That is true, enough about that 😅, however it is good to have PHP sessions dir in mind now to rule this out for further reports + testing.

And besides: this is also most certainly off-topic for this ticket?!

True but connected in a way ( " CSRF check failed" symptoms ....) and very worth value ! Stop _polluting_ then, but I wanted to shared that, just in case - and for others. @MichaIng : I will try default settings. I don't get why I ended up with this issue (I did not do any changes manually)

I ran into the same issue.

  • OS version ubuntu 18.04
  • Nextcloud was installed via Snap (19.0.1snap2)

I tried to find through open issues and couldn't find any way to resolve it.

@hoonto did you manage to find a force logout URL that doesn't need a token reference?

You mean a way to logout ALL current sessions? Since the token contains the info about which session to be logged out, only logging out all sessions would then be logically possible without it. But you don't want this being possible by just visiting an URL unauthenticated 😄.

Just to assure that its the same issue. When hovering the logout button one should see and be able to copy the URL, like

https://my.domain.org/nextcloud/logout?requesttoken=3%2BG8PjLJ%2BmziNaa9qToxFbzi7HhxYdp9aICSNePgqBU%3D%3AmtDTd2WTiiunds3y5QpnX8u4vyo2CI1KBPq5bKyF5X4%3D

There are two %2B sequences, coding for +. Replace those, and only those, percent signs with their encoding %25, so that %2B becomes %252B and the whole example string above becomes

https://my.domain.org/nextcloud/logout?requesttoken=3%252BG8PjLJ%252BmziNaa9qToxFbzi7HhxYdp9aICSNePgqBU%3D%3AmtDTd2WTiiunds3y5QpnX8u4vyo2CI1KBPq5bKyF5X4%3D

Now the first decoding will decode those back and the second decoding will result in the wanted +, so logout should always succeed, at least this is the theory. If this is repeatedly (!) the case (since the error depends on the by chance occurrence of + in session token), then you know that you need to find the proxy/webserver/whatever that causes the doubled URL decoding.

I had three %2B sections in my URI, I replaced them with %252B but it still gives me the same error. so i guess that hunch doesnt work for in this scenario

As was posted above, lighttpd's handling of %2B when normalizing URLs was broken, and URL normalization was enabled by default in lighttpd 1.4.53 [Correction: enabled by default in lighttpd 1.4.54, but also enabled in Debian Buster lighttpd 1.4.53 lighttpd.conf]. The bug is fixed in lighttpd 1.4.55 (released Jan 2020), which is available in buster-backports.
@LeSpocky confirmed this above on Mar 25: https://github.com/nextcloud/server/issues/17065#issuecomment-604067469

Please keep lighttpd's URL normalization enabled in lighttpd 1.4.55 and later, and upgrade to lighttpd 1.4.55 if running earlier versions.

@praveensl Using %252B is not the right long-term solution and will likely bite you later. It may be a short-term band-aid until you can upgrade to lighttpd 1.4.55.

To clarify, lighttpd URL normalization does not url-decode. Instead, it normalizes the encoding so that different % encodings all look the same, e.g. there is no need to encode a to %61 unless you are trying to fudge your way around a configuration that checks for a literal a and silently passes %61 (which is later decoded to a by the application). If you want to protect your /admin page, you do not want someone to bypass the restriction with /%61dmin.

Using %252B is not the right long-term solution and will likely bite you later. It may be a short-term band-aid until you can upgrade to lighttpd 1.4.55.

Of course this was only to test whether there is indeed doubled decoding the issue 😉. Completely unhandy anyway compared to simply trying a few more times.

If you want to protect your /admin page, you do not want someone to bypass the restriction with /%61dmin.

If this is possible, then this is a serious internal security issue as of course access permissions should be verified according to the final file/resource that is accessed. I mentioned it on the other issue, IMO manipulating the URI (that is passed and parsed by another handlers in case) cannot be a solution for internal security or stability issues that can be exploited by simply using a certain special URI. One never knows which part of the "unnormal" URI was intended and which one not, especially when its about the query string, but also thinking of special (intended) rewrites and such. Having now a few URL-codings decoded or changed while others stay the same only creates a completely unpredictable result for what any handler gets.

But while this topic does not belong here (lets focus on switching to POST) it is quite important if there are really security concerns when leaving those settings disabled in Lighttpd. I suggest we discuss this further on the Pi-hole issue: https://github.com/pi-hole/pi-hole/pull/3329
I'm especially interested if there are really any verified issues and why those cannot be (or were not) fixed internally then, or e.g. the URI is normalised only after all rewrites/redirects/handlers have been passed so that it is in fact only used by Lighttpd to access a local resource directly.

@gstrauss @MichaIng I'm currently testing out the snap based installation, so it runs on apache. also i tried to find the snap project to see if someone has similar issue but I cant seems to find anything relevant there. I'll try a fresh installation without snap and update here.

one of the inconveniences i've noticed here is the fact that issues in different projets (desktop/andriod/main/etc..) dont seems to get linked up well. I'm new here, but will try to keep linking issues where needed.

Setup a new ubuntu server and installed 19.01 on LAMP stack. I cant reproduce this issue anymore.

(multi-posting to https://github.com/pi-hole/pi-hole/pull/3329 Follow-ups there.)

One never knows which part of the "unnormal" URI was intended and which one not, especially when its about the query string, but also thinking of special (intended) rewrites and such. Having now a few URL-codings decoded or changed while others stay the same only creates a completely unpredictable result for what any handler gets.

I think you misunderstood what is meant by normalization. %-encoding has some complexity since there are slightly different rules for required characters to %-encode in different parts of the URI, but there is a normal form which consists of %-encoding the characters required to be %-encoded. Then, if a specific application is trying encode information in the URI, and needs non-required characters to remain %-encoded to preserve semantics, an application can do so more robustly by using base64 or hex (without %) or other encoding. If %-encoding is used instead, lighttpd provides some flags to loosen the normalization, e.g. url-path-2f-decode, url-path-dotseg-remove, url-query-20-plus.

If you want to protect your /admin page, you do not want someone to bypass the restriction with /%61dmin.

That example was oversimplified and does not apply to lighttpd. lighttpd %-decodes the url-path component for use in $HTTP["url"] conditions in lighttpd.conf. .. path segments are also removed to defend against path traversal attacks (applies to all web servers). This typically matches the user expectation of applying the lighttpd.conf condition to a path which often maps to a filesystem path.

However, URL rewrite and URL redirect produces a URI which must be properly %-encoded. The matching rules constructed by the end-user should match what is intended, and the resulting URI constructed from captured matches should be what is intended by the end-user. mod_rewrite and mod_redirect match on the %-encoded URI. To do otherwise could easily lose information in the encoding and result in broken URIs.

URI normalization allows an end-user to write mod_rewrite and mod_redirect matching rules relying on the fact that the URI against which it is matching is in a normalized form. When you disable this protection in lighttpd, you expose end-users to malicious actors that can manipulate the rewrite and redirect rules.

For those who need to construct complex URIs, lighttpd provides an enhanced syntax for %-encoding or %-decoding matched parts of the URI. https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModRewrite

The official lighttpd code base does not ship with mod_rewrite or mod_redirect loaded, and does not ship with any rewrite or redirect rules.

URI normalization enhances security for end-users employing URL rewrite and URL redirect and gives the end-user more power in controlling the construction of the resulting URI.

Any well-maintained linux distro is either shipping lighttpd 1.4.55, or has backported the lighttpd patch for the %2b decoding bug.

URI normalization in lighttpd first shipped in lighttpd 1.4.50 (Aug 2018) and was enabled by default in lighttpd 1.4.54 (May 2019). The %2b query string decoding bug was reported 7 months later in Jan 2020, patched the same day, and released in lighttpd 1.4.55 (Jan 2020) https://redmine.lighttpd.net/issues/2999

I hided and marked the discussion about whether the Lighttpd parse options are reasonable or not as OOT. Its not on Nextcloud to decide this, as Nextcloud does not aim to ship the whole webserver setup, compared to Pi-hole: https://github.com/pi-hole/pi-hole/pull/3329#issuecomment-667824140
Lets focus on collecting and debugging the cases that cause the CSRF check failure to either implement a fix or workaround into Nextcloud or document these in e.g. troubleshooting section of Nextcloud documentation: https://docs.nextcloud.com/server/latest/admin_manual/issues/general_troubleshooting.html#troubleshooting-web-server-and-php-problems

@hoonto did you manage to find a force logout URL that doesn't need a token reference?

No I didn't, but my solution around nextcloud allows me to grab the token from the head attribute data-requesttoken. Which is clumsy and brittle, but it is my only option right now.

It works, but I fear the day someone changes that name of that attribute or for some reason removes it entirely. I'd really like to have a simple POST logout.

Seeing this with the latest version. Only thing my logs show interestingly is a failed call to /apps items:
75.172.96.53 - - [09/Aug/2020:16:58:49 +0000] "GET /apps/accessibility/js/accessibility?v=0 HTTP/1.1" 200 85 "https://app.penguinzmedia.group/ocs/v2.php/cloud/capabilities" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0" 75.172.96.53 - - [09/Aug/2020:16:58:50 +0000] "GET /apps/theming/js/theming?v=0 HTTP/1.1" 200 232 "https://app.penguinzmedia.group/ocs/v2.php/cloud/capabilities" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0" 75.172.96.53 - - [09/Aug/2020:16:58:50 +0000] "GET /apps/encryption/ajax/getStatus HTTP/1.1" 200 77 "https://app.penguinzmedia.group/ocs/v2.php/cloud/capabilities" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0" 75.172.96.53 - - [09/Aug/2020:16:58:57 +0000] "GET /ocs/v2.php/apps/notifications/api/v2/notifications HTTP/1.1" 200 492 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0" 75.172.96.53 - - [09/Aug/2020:16:59:27 +0000] "GET /ocs/v2.php/apps/notifications/api/v2/notifications HTTP/1.1" 200 492 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"

FYI, I ran into the same issue, in my case with lighttpd, and it seems I found a workaround here. I created and enabled /etc/lighttpd/conf-available/10-parseopts-url-normalize-required.conf with this content:

server.http-parseopts := (
    "url-normalize-required" => "disable"
)

Not quite sure what other implications this will have, but I logged in&out a dozen or so times and so far it seems to be working. url-normalize-required is documented here.

I wonder if the problem is related to this lighttpd issue, but that seems not to be the case if the same happens with other web servers.

Jep as documented above: https://github.com/nextcloud/server/issues/17065#issuecomment-573261112
And yes, the Lighttpd issue you linked is the upstream report and fix, as the %2B decoding that causes the issue was not intended.
Current stable Debian and Raspbian versions (Buster) will most likely not receive this fix anymore, hence disabling the URL normalization is (aside of source compiling) the only way to fix it there, likely on other non-rolling Linux distros as well. And although having some discussion about the impact of this Lighttpd option, until now I could not find a single real example that disabling it has any security (or other negative) impact, means it should be just fine 😉.

lighttpd developer here: it is a terrible idea to disable that security setting since you will probably never re-enable it.
Yes, there was a bug in lighttpd that was fixed the same day it was reported and released the same month, and that was over 7 months ago.

If you want an update in your favorite distro, please make the request to the distro.
I submitted patches to Debian, but they're just sitting there: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=961843
If enough people ask Debian to pick up the patch, maybe they'll do so. That's a much better approach than disabling security features.

The fix is already available in Debian backports, which has lighttpd 1.4.55. The above link is to backport the fix to the main branch.

until now I could not find a single real example that disabling it has any security (or other negative) impact, means it should be just fine

That is a baseless statement and is incorrect. The setting would not exist without a reason.

url-normalization does not protect lighttpd, it protects custom lighttpd configurations and backend application servers, where admins and programmers may not be so careful to have explict allow and default deny rulesets.

It potentially breaks backend applications (as long as the query string is still manipulated by Lighttpd) which are responsible for their own security and how they deal with incoming requests. If a backend/application gets an unexpectedly manipulated query string, that potentially causes a security issue (like in this case, I know due to a bug) instead of fixing some. Whatever the webserver does, admins and application developers will always be able to create wide security holes by misconfiguration and insecure code/methods. And when backend developers are forced to double check query strings for each and every webserver individually, implement workarounds and compatibility code, exceptions or whatever, this potentially creates additional security issues.

I mean you know best if Lighttpd is secure enough for production use or not, without having these options enabled, but I just want to give you the view from PHP/backend developer perspective. Nextcloud here is not the only case where this v1.4.53 bug causes issues it is not the only case where Lighttpd creates the need for additional workarounds/compatibility code, at least would, but finally full/official support for this webserver is simply not implemented because of that, which is a pity as it always worked great for me. Sometimes it's good to stick with standards (how other webservers handle it) which developers and admins can rely on, trust in them being able to configure/code their environment securely, otherwise take the responsibility and consequences themselves.

Good point to vote for merging v1.4.55 into Buster stable 👍, that would really help: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=961843

I mean you know best how secure Lighttpd is without having these options enabled

Did you intentionally state the opposite of what I said and then attribute it to me? Your statement reads with malicious intent.

I do know how to secure lighttpd and it is best practice to retain the secure defaults (enabled). It is also best practice to run the latest official lighttpd release, where all known bugs have been addressed.

tl;dr: lighttpd developer states: do not disable the secure defaults
@MichaIng does not know better.

Sorry bad wording, "how secure" was meant to include "insecure", I rephrased it, so yes you know best if it is secure enough or not to disable this setting to workaround the bug. Sadly upgrading is simply not an option for many admins, when not being experienced with compiling and not all distros provide backports, Raspbian does not.

Btw, as Apache and Nginx do not have such options, are they insecure? Or does Lighttpd have some internal differences that requires those options to gain same security? Since you mentioned backend software as well of course this has nothing to do with Lighttpd and you simply seem to have a different view about security than Nginx and Apache developers (whether to normalise an URL before passing to handler or whether this is the job ob the backend application) which AFAIK do no query string normalisation before passing the request to an external PHP handler.

I have this issue on nginx + php-fpm + nextcloud 19.0.2

If we have a symbol '+' in the requesttoken autologout is failed and CSRF is received. Changing '+' to '%2B' in the URL give a result.

Nginx also decode URL if one make a rewrite. There you can see a ticket about and a thread on stackoverflow

https://stackoverflow.com/questions/28684300/nginx-pass-proxy-subdirectory-without-url-decoding/37584637#37584637
https://trac.nginx.org/nginx/ticket/727

Changing '+' to '%2B' in the URL give a result.

Was the + already visible in the browser address bar when doing the logout? Actually it should be always encoded there as %2B, at least was on all my tests, otherwise the expected decoding in the PHP $_GET array would already break it, so you mean the request send by the proxy, I guess. Above in this thread proxies (with other webserver) were as well mentioned as a possible reason for doubled decoding (once at the proxy, once by PHP). If I understand correctly with Nginx, it is the rewrite (without using $request_uri) that causes the decoding, not proxy_pass itself (basically you said it)? The last answer looks quite simply to omit the path element of the location without having anything decoded (due to no rewrite), but zero up-votes probably mean that it doesn't work.

One could see the whole issue from the other side and could argue to not use any character in URI/query string that can be URL decoded, in this case not use + at all. But it seems to be pretty standard (don't remember an exact example but pretty sure saw it elsewhere)? The (decoded) token is a combined hash already, so probably this is not possible without switching the hash algorithm? Here my insights end 😅.


I just asked about the status of the requested Lighttpd patches for Debian Buster. Good step to ask for integrating the patches only (instead of asking to merge the new upstream release) which should hopefully succeed "soon" 👍.

Was the + already visible in the browser address bar when doing the logout?

Yes it is. Changing it in browser to %2B and pressing Enter make a successfull logout.
Maybe a recommended Nginx configuration from Nextcloud can be modified to use a non-decoded $request_url in case of /logout?requesttoken=... ?

https://docs.nextcloud.com/server/latest/admin_manual/installation/nginx.html

That is very strange, as the request token is definitely encoded, otherwise would never work. Code has changed since we looked through it, but here is how it was that time: https://github.com/nextcloud/server/blob/5bf3d1bb384da56adbf205752be8f840aac3b0c5/lib/private/legacy/user.php#L280

Here is the logout URL of my instance:

https://<omitted>.org/nextcloud/logout?requesttoken=uCDwHbPgdKsuJPK71ePeLml92t%2BmDgGa0%2BuKxdXEbVs%3D%3A4nSCLtquRuJeEsKMsa%2B6VgVLqKbLOTDDqb35joTxAhA%3D

You see %2B and %3D, all as it needs to be.

Maybe a recommended Nginx configuration from Nextcloud can be modified to use a non-decoded $request_url in case of /logout?requesttoken=... ?

The correct logout URL is generated within the scripts based on the CSRF token and a secret, merged and encrypted, so it cannot be retrieved from any Nginx variable. The final URL is URL-encoded and that is what you see as link on the logout button. If that is really a non-encrypted version, there is something seriously wrong, prooobably it has to do with the browser (only showing or actually using decoded URLs from links), did you try a different one?

There are some strings from nginx access log:

1. <ip> - - [11/Sep/2020:18:32:07 +0300] "GET /logout?requesttoken=uBHp/FX7tBNnOkA/CQd/fDRDXH8Y4LO71mVVKKRxY2w=:90Gb0wO9zUkGTRpbTz4qNWcCDkh0st+LsDwUQvc3Ox4= HTTP/2.0" 412 15006 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"
2. <ip> - - [11/Sep/2020:18:35:01 +0300] "GET /logout?requesttoken=iOwyYG5amY2Eo1buEb0MtcIhNJZ3MVSZO1AXgsHmhJc=:uKl+KDgu8b7A0SCfYOp59IdYR9geVS7AYh5UqZKpzfw= HTTP/2.0" 412 15006 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"
3. <ip> - - [11/Sep/2020:18:52:09 +0300] "GET /logout?requesttoken=/Lon6w9VZqAp5+qoepPuw3HksLoX6TYmZsnpYtcebTw=:s+pVxFkTH/pIkLDMPKq7iiKl4o17u1oWAJCoCIRYNU4= HTTP/2.0" 412 15006 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"
4. <ip> - - [11/Sep/2020:18:55:03 +0300] "GET /logout?requesttoken=wPvSJg8KdyIp9W70TVCVxlINcpR1sjLRz/C9kdEV/ps=:8L6ebll+HxFthxiFPAfghxd0Adoc1kiIlr7+uoJat/A= HTTP/2.0" 412 15006 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"
5. <ip> - - [11/Sep/2020:19:12:10 +0300] "GET /logout?requesttoken=4GU4sfMAhCt+zrtAQGYpXXYnhgmIcXpfGkXKFMWESsU=:rzVKnqVG/XEfueEkBl98FCVm1D7kIxZvfByLfpbCErc= HTTP/2.0" 412 15006 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"
6. <ip> - - [11/Sep/2020:19:15:05 +0300] "GET /logout?requesttoken=/hgdn/MkXCSuWqAUI/GYiu3GYuy3rUysrKw6GoFefVc=:zl1R16VQNBfqKNZlUqbty6i/EaLeyTb19eJ5MdIRNDw= HTTP/2.0" 499 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"
7. <ip> - - [11/Sep/2020:19:15:05 +0300] "GET /logout?requesttoken=/hgdn/MkXCSuWqAUI/GYiu3GYuy3rUysrKw6GoFefVc=:zl1R16VQNBfqKNZlUqbty6i/EaLeyTb19eJ5MdIRNDw= HTTP/2.0" 303 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"
8. <ip> - - [11/Sep/2020:19:22:35 +0300] "GET /logout?requesttoken=4GU4sfMAhCt+zrtAQGYpXXYnhgmIcXpfGkXKFMWESsU=:rzVKnqVG/XEfueEkBl98FCVm1D7kIxZvfByLfpbCErc= HTTP/2.0" 412 15006 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"
9. <ip> - - [11/Sep/2020:19:23:13 +0300] "GET /logout?requesttoken=4GU4sfMAhCt%2BzrtAQGYpXXYnhgmIcXpfGkXKFMWESsU=:rzVKnqVG/XEfueEkBl98FCVm1D7kIxZvfByLfpbCErc= HTTP/2.0" 303 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36" "-"

412 - is the code when we have + in the URL.
303 - is the code when + is masked by %2B

Strings 6 and 7 - that was a session w/o + in the URL so it has made an autologout by himself
Strings 8 and 9 - I have changed + to %2B in the URL by hand after CSRF error.

URLs looks excactly like that in browser too. With + and :.

If that is really a non-encrypted version, there is something seriously wrong, prooobably it has to do with the browser (only showing or actually using decoded URLs from links), did you try a different one?

Of cource. Above You can see FF and Chrome. It is like that for may of our users, not only me.

And if you access Nextcloud directly without the proxy in between (if possible), the browser shows the URL correctly? Ah when course rewrite-decoding at the proxy happens in both directions, totally forgot about that.

Not sure I can access this installation w/o Nginx reverse proxy.
BUT! I just realize that if I press Logout button the URL in the log is different!

<ip> - - [12/Sep/2020:00:26:05 +0300] "GET /logout?requesttoken=qJLp3xlWff8ex82a%2FWJNr0W5hws0In2s2NsJW10TiuU%3D%3AxuuQ8GoEKL1QnpXAiVcs%2BC2OymBeTTPt87pDCRJG77Q%3D HTTP/2.0" 303 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"

As You can see it is encoded! Maybe the code for autologout is little different?

Maybe the code for autologout is little different?

Ah I missed the fact that it is about autologout in your case. Hmm as the code changed a bid where/how those logout URLs are generated, I'm not sure. @kesselb could you have a look whether logout button and autologout URLs are decoded differently?

A bid late now, but probably I find some time tomorrow to replicate it, autologout alone and with proxy.

Looks like. Here is the auto logout: https://github.com/nextcloud/server/blob/357455186279cfc1c542837e71090751d2feb66f/core/src/session-heartbeat.js#L129

Maybe the getRequestToken should be wrapped in encodeUriComponent

cc @rullzer @juliushaertl

Okay, getRequestToken is imported here: https://github.com/nextcloud/server/blob/master/core/src/session-heartbeat.js#L29
and ehm defined here? https://github.com/nextcloud/server/blob/master/core/src/OC/requesttoken.js
Can't see some encoding done at least.

Maybe the getRequestToken should be wrapped in encodeUriComponent

Yep, that shoud do the trick here I guess.

Any progess? I have installed 19.0.4.
Nothing has changed. On autologout requesttoken is still unencoded.
image

OP originally posted this issue with NextCloud and lighttpd.
Here's quick recap:

Most popular distros had lighttpd 1.4.55 available soon after its release in Jan 2020.
The exceptions were (as usual) Debian and Debian derivatives.

Still, Debian buster-backports has had lighttpd 1.4.55 available since early Mar 2020.

26 Sep 2020, Debian finally backported patches to Debian buster
bug closed: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=961843
Released 26 Sep 2020 in Debian Buster 10.6

.

Modifying the lighttpd security defaults is highly inadvisable.

Someone please file an issue with Raspian asking them to pick up the patches (and please post a link to the Raspian issue here).

For those using older version of Ubuntu, please file an issue with Ubuntu to pick up the patches (and please post a link to the Ubuntu issue here).

.

The issue with NextCloud not properly URL-encoding the autologout token should probably be filed as a separate issue so that it is not lost.

26 Sep 2020, Debian finally backported patches to Debian buster

Great news, thanks for sharing.

Someone please file an issue with Raspbian asking them to pick up the patches (and please post a link to the Raspian issue here).

Not necessary. Raspbian uses Debian sources, only build for armv6hf. The fixed version is available there as well: http://raspbian.raspberrypi.org/raspbian/pool/main/l/lighttpd/

For those using older version of Ubuntu, please file an issue with Ubuntu to pick up the patches (and please post a link to the Ubuntu issue here).

Not necessary. Lighttpd v1.4.53 and v1.4.54 are not used in any Ubuntu suite: https://packages.ubuntu.com/search?suite=all&searchon=names&keywords=lighttpd
Previous versions do not have those options and v1.4.55 has it fixed.

So the original case with Lighttpd is basically solved now 👍.
Since this issue collected cases where the same error occurred for reasons, i.e. auto-logout and certain proxy setups, and we started to think about migrating to generally more robust POST, not sure how to go on.

  • @juliushaertl @kesselb @Hedgehog57 shall we create a new issue for this specific auto-logout issue?
  • @rullzer shall we open a new issue about migrating to POST requests to generally increase robustness? The reported cases where proxies were responsible for some decoding would be covered as well by migrating to POST, I think.


Off topic

Modifying the lighttpd security defaults is highly inadvisable.

OOT, but I'm still not convinced, never got an answer to share an explicit example for an attack which is protected from by this, and never got an answer to why Apache2 and Nginx do not need such or if Lighttpd devs consider this missing on Apache2 and Nginx as well, which would mean that there is a difference in what is considered as reasonable/recommended security enforcement between webserver devs/teams. And I'm still thinking that explicitly the query thing is something that should never be touched by the webserver.

Hi @MichaIng,

IMHO yes it is necessary to create a new issue about autologout. It is still actual problem. As I understood You already know where is the problem with encoding in the code?

OOT, but I'm still not convinced, never got an answer to share an explicit example for an attack which is protected from by this

I am not posting exploits here. To make such a request shows that you are unfamiliar with responsible disclosure practices.

Also, you have demonstrated and very vocally projected your uninformed conclusions with circular logic "it's probably not an issue because I can't think of a reason". It is a fools-errand to attempt to disabuse a fool of the notion that they are foolish, and I won't attempt to do so here. You have not demonstrated credibility on the topic of security, and therefore I will continue to ignore and discard your ramblings about security. I encourage others to do so as well. You very likely have other skills, but in your posts here you have not demonstrated a solid understanding of security. Were I to share a low-impact example, I am almost certain you would dismiss it as low-impact. I have provided hints about interactions between servers and backends -- similar to the concepts in request smuggling attacks -- and you can see above that developers, including NextCloud developers, can make mistakes in properly encoding URLs. Developers can also make mistakes parsing URLs including query strings. And before you respond with what-aboutism, I have already multiple times above acknowledged my bug handling %2b in the query string and that a patch to fix the bug was produced the same day it was reported (1 Jan 2020).

tl;dr: I do not need to convince you that something is security-sensitive. Most people with a clue find it sufficient to realize that a large amount of effort was expended to develop these features in lighttpd, and that there were very likely (multiple) good reasons why that time and effort were spent doing so instead of directing the effort elsewhere.

I am not posting exploits here. To make such a request shows that you are unfamiliar with responsible disclosure practices.

If there are exploits, why are those not fixed Lighttpd-internally without manipulating the request arguments that are passed to the backend? Requiring a certain config option to be set to close a known exploit does not sound like a solid solution to me. But I agree that it is not a good idea to publicly share an example here how Lighttpd can be exploited 😉. I not try to argue against using those Lighttpd options (anymore), at least in case of Nextcloud they now do not cause issues anymore, I try to understand why those are important or reasonable but am unable until now. It is not about the %2b bug, yes that can happen, all fine, but it is about the general concept of touching parts of the URL which are only handled by backends where Lighttpd cannot really know what they are expecting or if a somehow not normalised URL implies any issue or is even wanted to be detected by the backend, e.g. for debugging either the backend or the client. But yeah, sorry for re-opening this discussion, I was not recognising that it's you, I am always hoping to get some other views on that.

I not try to argue against using those Lighttpd options (anymore), at least in case of Nextcloud they now do not cause issues anymore

When you are ignorant about a subject, you have no credibility to argue for or against. You remain ignorant of your ignorance, and that is sad, and yet you loudly argue and spread misinformation. Shame on you.

But I agree that it is not a good idea to publicly share an example here how Lighttpd can be exploited

This is not exploitable in lighttpd, by itself, as I explained in https://github.com/nextcloud/server/issues/17065#issuecomment-667824079 Again, you are making uninformed and false statements.

I try to understand why those are important or reasonable

You are not trying very hard. I wrote above: " I have provided hints about interactions between servers and backends -- similar to the concepts in request smuggling attacks". From your response above, it is clear that you have not even looked up the basics of request smuggling. https://googlethatforyou.com?q=request%20smuggling

Can yall stop having a security pissing match over a wide watched topic
please.

On Mon, Oct 12, 2020, 5:34 PM Glenn Strauss notifications@github.com
wrote:

I not try to argue against using those Lighttpd options (anymore), at
least in case of Nextcloud they now do not cause issues anymore

When you are ignorant about a subject, you have no credibility to argue
for or against. You remain ignorant of your ignorance, and that is sad,
and yet you loudly argue and spread misinformation. Shame on you.

But I agree that it is not a good idea to publicly share an example here
how Lighttpd can be exploited

This is not exploitable in lighttpd, by itself, as I explained in #17065
(comment)
https://github.com/nextcloud/server/issues/17065#issuecomment-667824079
Again, you are making uninformed and false statements.

I try to understand why those are important or reasonable

You are not trying very hard. I wrote above: " I have provided hints about
interactions between servers and backends -- similar to the concepts in
request smuggling attacks". From your response above, it is clear that you
have not even looked up the basics of request smuggling.
https://googlethatforyou.com?q=request%20smuggling


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/nextcloud/server/issues/17065#issuecomment-707414698,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AEJX2I34YL52LLBWOCYNCJTSKON7XANCNFSM4IU3GXYQ
.

I'm using NC 19.0.1 with Ubuntu 20.04 + Apache 2.

This issue has been a LONG running issue and till today, I'm getting the SAME error as everyone else!!

Is this be fixed in 19.0.4 or in the future? TQ

PS: And guys and gals, our discussion here is about NEXTCLOUD Access forbidden CSRF check failed on logout and not about webserver security settings and their features! Pls stick to the topic at hand. TQ

CSRF Check Failed

@juliushaertl @kesselb @Hedgehog57 shall we create a new issue for this specific auto-logout issue?

I just pushed the proposed fix for the auto-logout to https://github.com/nextcloud/server/pull/23402 I'm fine to keep it in this one.

@rullzer shall we open a new issue about migrating to POST requests to generally increase robustness? The reported cases where proxies were responsible for some decoding would be c

Makes sense from my POV, but should be a separate issue since the fix will also require adjusting the navigation which currently doesn't support sending post requests, so it is a larger change.

New request issue opened about migrating logout requests to POST, respectively passing the CSRF token via POST, as the initial request when hitting the logout button has to stay GET from what I can think of? #23413

Was this page helpful?
0 / 5 - 0 ratings