Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

addressbook-query can be used without credentials to check if an addressbook contains matching cards #1548

Open
mstilkerich opened this issue Mar 17, 2024 · 1 comment

Comments

@mstilkerich
Copy link
Contributor

Hello,

sabre/dav appears to execute addressbook-query reports without first checking authorization on the target addressbook (e.g., anonymous request). Only when the query finds at least a matching card, the authorization will be performed based on each result card (see trace below on where the authorization is performed). However, in case no matching card is found, addressbookQueryReport would not check authorization and instead return an empty result with 207 status code.

This means it is possible for anyone to check if an addressbook contains cards matching a query filter or not. Tested this with Baïkal 0.9.4.

I also tried against a nextcloud 28 server, where I could not reproduce this behavior (i.e. I get the expected 401 in this case), even though nextcloud 28 also includes Sabre/DAV 4.5.0.

▶   2552: Sabre\DAVACL\Plugin->[email protected]:209
    2553: Sabre\DAVACL\Plugin->[email protected]:936
    2554: Sabre\DAV\Server->[email protected]:89
    2555: Sabre\DAV\Server->[email protected]:1052
    2556: Sabre\DAV\Server->[email protected]:984
    2557: [email protected]:941
    2558: Sabre\DAV\Server->[email protected]:941
    2559: Sabre\CardDAV\Plugin->[email protected]:453
    2560: Sabre\CardDAV\Plugin->[email protected]:194
    2561: Sabre\DAV\Server->[email protected]:89
    2562: Sabre\DAV\CorePlugin->[email protected]:690
    2563: Sabre\DAV\Server->[email protected]:89
    2564: Sabre\DAV\Server->[email protected]:472
    2565: Sabre\DAV\Server->[email protected]:253
    2566: Sabre\DAV\Server->[email protected]:321
    2567: Baikal\Core\Server->[email protected]:119 
    2568: {main}@dav.php:69

HTTP trace - Query with no results:

"REPORT /dav.php/addressbooks/mikey/default/ HTTP/1.1" 207
>>>>>>>>
REPORT /dav.php/addressbooks/mikey/default/ HTTP/1.1
Content-Length: 504
User-Agent: GuzzleHttp/7
Host: baikal.localdomain
Depth: 1
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0"?>
<CARDDAV:addressbook-query xmlns:DAV="DAV:" xmlns:CARDDAV="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/">
 <DAV:prop>
  <DAV:getetag/>
  <CARDDAV:address-data/>
 </DAV:prop>
 <CARDDAV:filter test="anyof">
  <CARDDAV:prop-filter name="EMAIL" test="anyof">
   <CARDDAV:text-match negate-condition="no" collation="i;unicode-casemap" match-type="contains">gmailxxx</CARDDAV:text-match>
  </CARDDAV:prop-filter>
 </CARDDAV:filter>
</CARDDAV:addressbook-query>

<<<<<<<<
HTTP/1.1 207 Multi-Status
Date: Sun, 17 Mar 2024 09:56:04 GMT
Server: Apache/2.4.57 (Debian)
X-Powered-By: PHP/8.1.27
Set-Cookie: PHPSESSID=d5f51c5a8f5975246a207aaf8ac4b3b6; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Sabre-Version: 4.5.0
Vary: Brief,Prefer
Content-Length: 214
Content-Type: application/xml; charset=utf-8

<?xml version="1.0"?>
<d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav"/>

--------
NULL

Http trace (Query with results):

"REPORT /dav.php/addressbooks/mikey/default/ HTTP/1.1" 401
>>>>>>>>
REPORT /dav.php/addressbooks/mikey/default/ HTTP/1.1
Content-Length: 501
User-Agent: GuzzleHttp/7
Host: baikal.localdomain
Depth: 1
Content-Type: application/xml; charset=UTF-8

<?xml version="1.0"?>
<CARDDAV:addressbook-query xmlns:DAV="DAV:" xmlns:CARDDAV="urn:ietf:params:xml:ns:carddav" xmlns:CS="http://calendarserver.org/ns/">
 <DAV:prop>
  <DAV:getetag/>
  <CARDDAV:address-data/>
 </DAV:prop>
 <CARDDAV:filter test="anyof">
  <CARDDAV:prop-filter name="EMAIL" test="anyof">
   <CARDDAV:text-match negate-condition="no" collation="i;unicode-casemap" match-type="contains">gmail</CARDDAV:text-match>
  </CARDDAV:prop-filter>
 </CARDDAV:filter>
</CARDDAV:addressbook-query>

<<<<<<<<
HTTP/1.1 401 Unauthorized
Date: Sun, 17 Mar 2024 09:57:07 GMT
Server: Apache/2.4.57 (Debian)
X-Powered-By: PHP/8.1.27
Set-Cookie: PHPSESSID=520a9f447ece440af07907fdd48faf27; path=/; HttpOnly
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
X-Sabre-Version: 4.5.0
WWW-Authenticate: Digest realm="BaikalDAV",qop="auth",nonce="65f6be73c4f5c",opaque="d66d5f0524036afcb61420e358f990ce"
Content-Length: 470
Content-Type: application/xml; charset=utf-8

<?xml version="1.0" encoding="utf-8"?>
<d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
  <s:sabredav-version>4.5.0</s:sabredav-version>
  <s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
  <s:message>No 'Authorization: Digest' header found. Either the client didn't send one, or the server is misconfigured. Login was needed for privilege: {DAV:}read on addressbooks/mikey/default/C031E892-3579-48C3-B834-C5E664728D41.vcf</s:message>
</d:error>

--------
NULL
@kesselb
Copy link
Contributor

kesselb commented May 14, 2024

I also tried against a nextcloud 28 server, where I could not reproduce this behavior (i.e. I get the expected 401 in this case), even though nextcloud 28 also includes Sabre/DAV 4.5.0.

We are using a wrapper for DavAclPlugin to prevent some cases of user enumeration.

Related pull request: https://github.com/nextcloud/server/pull/43664/files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants