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

Authentication methods for password protected link shares. #110

Open
C0rby opened this issue Mar 5, 2021 · 0 comments
Open

Authentication methods for password protected link shares. #110

C0rby opened this issue Mar 5, 2021 · 0 comments

Comments

@C0rby
Copy link
Contributor

C0rby commented Mar 5, 2021

tl;dr

For ownCloud Web we needed a different way to authenticate downloads of password protected link shares. The current design of the share manager doesn't allow us to implement this alternative authentication method namely pre-signed urls.
We are using the share password hash as the signing key but in the current implementation the share password hash is not accessible outside of the share manager.

To allow this alternative authentication method I propose three options:

  • Include the password hash in the PublicShare struct
    • The simplest solution
    • May leak the password hash when the PublicShare struct is included in a response
  • Add the password hash as a return value of GetPublicShare and GetPublicShareByToken
    • Second simplest solution
    • Doesn't leak the hash if the PublicShare is included in a response
  • Implement different authentication strategies which can be used in the share manager
    • Complex to implement
    • Mixes transport specific auth stuff with the share manager

Long explanation

This http://localhost:8080/index.php/s/2LfFihmw6cD7qxU is an example public link. The last part 2LfFihmw6cD7qxU is the random token identifying the share.
For password protected shares the credentials can be included in the 'Authorization' header using basic auth where 'public' is the username and the share password is the password.

When we want to download a file using the anchor tag <a href="...." we can't supply the Authorization header to the request.
In ownCloud 10 this worked by using cookies but in ownCloud Web we don't have cookies.
Because of that we have decided to use signed URLs. The advantage of signed-URLs is that, just like with unprotected public links, the possession of the URL is proof of authorization. Meaning anyone who has the signed URL can download the resource.

The general idea is this:

The client sends a PROPFIND request to the backend (including the credentials in the auth header)
    The client has to request the `downloadURL` attribute to receive the signed URL
The backend does the normal credential check
The backend generates the PROPFIND response
    When the client requested the `downloadURL` attribute the signed URL is generated and returned as the `downloadURL`
The client can now issue GET requests the `downloadURL`

The detailed signing process looks as follows:

Let's assume we have a shared tree like this:

Share Root
    some-file.txt
    Folder/
        another-file.txt

To create the signature we need:

The resource path relative to the share root: `/Folder/another-file.txt`
A timestamp of the expiration date for the signature. Right now it's 30 minutes from the moment of signing
The share token
The share password (hash)

And then we calculate the HMAC like this:

HMAC_SHA512/256(SHA256(share_password_hash), share_token + resource_path + timestamp)

The HMAC_SHA512/256 just means that we are using SHA512 as the hash function but want to receive a code with a length of 256 bits.
Then to create the signed URL we take the resource path and add the signature and the expiration timestamp as query parameters.

To verify the signature the backend will repeat the process above but this time it will take the timestamp from the requested URL.

If the current time is earlier than the expiration time continue with step 2. otherwise return an authentication failed response
Calculate the HMAC
Compare the signature passed via the query parameter with the calculated one
    If it doesn't match return an authentication failed response
Continue serving the resource

Frequently Asked Questions

Why do we need HMAC instead of just hashes?

Let's assume we would use hashes like this:

Hash(share_token + resource_path) = signature

Then all the information needed to create the signature would be public and the security of our share would be reduced to a public link without password.

Okay then let's include a secret like this:

Hash(share_token + resource_path + secret) = signature

Cool we just reinvented HMAC so let's use that instead. ;)

Can we do the signing on the client side?

If we wanted to do client side signing we would need a shared secret between the backend and the client.
The client knows the share password can't we use that?

The backend shouldn't store the password in plain text but in hashed format. Also the password should be hashed with a random salt.
The client could in fact also hash the password before using it as a HMAC key but the client doesn't have access to the random salt from the backend. Therefore it could never generate the same HMAC.

Okay what about another secret?

We could generate a new secret just for signing but this would require more changes to the API because the client would need to be able to request that secret.
Also we would need to store that in addition to the other share data.

Can we use the share token as a signing key?

Technically yes but the share token is public and therefore anyone with the knowledge of the share token can create the signature and this again reduces the security of the share to a public link without password.

I hope this document clarified the design of signed URLs for password protected shares.

C0rby pushed a commit to C0rby/cs3apis that referenced this issue Mar 12, 2021
For some alternative public share authentication methods we need to be able to access the public share password. Some more details are documented here: cs3org#110
C0rby pushed a commit to C0rby/cs3apis that referenced this issue Mar 12, 2021
For some alternative public share authentication methods we need to be able to access the public share password. Some more details are documented here: cs3org#110
C0rby pushed a commit to C0rby/cs3apis that referenced this issue Mar 15, 2021
For some alternative public share authentication methods we need to be able to access the public share password. Some more details are documented here: cs3org#110
C0rby pushed a commit to C0rby/cs3apis that referenced this issue Mar 15, 2021
For some alternative public share authentication methods we need to be able to access the public share password. Some more details are documented here: cs3org#110
C0rby pushed a commit to C0rby/cs3apis that referenced this issue Mar 16, 2021
For some alternative public share authentication methods we need to be able to access the public share password. Some more details are documented here: cs3org#110
labkode pushed a commit that referenced this issue Mar 17, 2021
For some alternative public share authentication methods we need to be able to access the public share password. Some more details are documented here: #110
C0rby pushed a commit to C0rby/reva that referenced this issue Mar 26, 2021
Implemented the mechanism proposed here: cs3org/cs3apis#110.
The signature authentication is limited to downloads.
C0rby pushed a commit to C0rby/reva that referenced this issue Mar 26, 2021
Implemented the mechanism proposed here: cs3org/cs3apis#110.
The signature authentication is limited to downloads.
C0rby pushed a commit to C0rby/reva that referenced this issue Mar 26, 2021
Implemented the mechanism proposed here: cs3org/cs3apis#110.
The signature authentication is limited to downloads.
C0rby pushed a commit to C0rby/reva that referenced this issue Mar 26, 2021
Implemented the mechanism proposed here: cs3org/cs3apis#110.
The signature authentication is limited to downloads.
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

1 participant