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

Security risk: Auth tokens tied to OPDS Authentitcation Document Id can be exploited by attackers #83

Open
mpdunlop opened this issue Aug 22, 2024 · 1 comment
Assignees

Comments

@mpdunlop
Copy link

While discussing an issue relating to OPDS Authentication it was mentioned that OPDS Clients should be storing authorization tokens against the id of the OPDS Authentication Document.

Tying authentication tokens to the id of the OPDS Authentication Document has security considerations. An attacker wanting to gain access to a user's account could craft an OPDS Publication Feed that requires authentication and return an OPDS Authentication Document that uses the same id as a legitimate OPDS Feed provider. If the user has previously authenticated using that document, and the OPDS Client looks up the auth token by the document's id, it will select a valid token and send it to the attacker.

  1. https://opds.contoso.org/publications.json requires authentication, first access returns OPDS Authentication Document with id https://auth.contoso.org/odps-auth.json
  2. User signs in and accesses their feed successfully
  3. Some time later, the user is later coerced into loading feed from attacker's domain (e.g. https://opds.contosoo.org/publications.json, a domain similar in appearance to an authentic one which is common in scams).
  4. The attacker has set this feed up to also requires authentication, and upon the OPDS Client first accessing it, it returns an OPDS Authentication Document with the same id as a legitimate OPDS provider, e.g. https://auth.contoso.org/odps-auth.json
  5. As the malicious authentication document's id matches the previously seen authentication document's id, the OPDS Client will use the authorization token issued previously and attempt to re-fetch the publication with the authorization token previously issued for the real contoso.org. This last step is the OPDS client leaking the valid token to the attacker.

OPDS Clients must not provide the token in this scenario. In the case of Basic Auth, this could result in usernames and passwords being entered by users and shared with the attacker. For OAuth, the access_token would be shared with the attacker.

In the short-term, OPDS clients who use the id field to cache authorization tokens should perform validation on the Authentication Document's Id (which the spec already defines as the canonical location for the Authentication Document) to ensure that it matches the address the authentication document is being served from. Failure to do so may result in user details being leaked to bad actors.

This may also have implications for the discussion in #43

@HadrienGardeur
Copy link
Member

HadrienGardeur commented Aug 22, 2024

Thank you for opening up this issue. It's a legitimate concern that needs to be addressed by a future revision of the draft IMO.

In your example, the catalog itself is an attacker. I see two different scenarios:

  • the client has already interacted with the Authorization Server of a legitimate catalog
  • the client has yet to interact with the Authorization Server of a legitimate catalog

In the first scenario, an attacker could:

  • use the authenticate property to point to a forged Authentication Document meant to intercept credentials or Access/Refresh Tokens
  • or send a forged Authentication Document in an HTTP response itself

In order to mitigate this issue, an Authentication Document could includes a list of trusted domains using a new property:

{
  "id": "https://example.com/authentication",
  "domains": ["example.com"]
}

An OPDS client would store this list of domains, alongside the id and the credentials or tokens (OAuth). It would then validate against this list of domains any request for a specific Authentication Document.

IMO, we can't simply match the id against the domain of a request because there are legitimate use cases where an OPDS catalog is spread across multiple domains.

This approach for mitigating the risk of an attacker stealing credentials/tokens through a catalog has limitations though.

An attacker could forge an Authentication Document with an extended list of domains that include domains meant to steal their credentials/tokens:

{
  "id": "https://example.com/authentication",
  "domains": ["example.com", "attacker.com"]
}

If it's the first time that a client encounters this id, it would consider the domain to be legitimate and add attacker.com to the list of authorized domains.

I think that the best way to mitigate this risk would be to only allow Authentication Documents to be served from the same domain used in their id.

This would mostly impact HTTP responses. Let's imagine that a legitimate catalog uses catalog.example.com and authorize.example.com:

  • While browsing catalog.example.com, an OPDS client discovers catalog.example.com/bookshelf.json
  • When fetching catalog.example.com/bookshelf.json it returns a 401 and points to an Authentication Document
  • Under the current draft for Authentication for OPDS, the Authentication Document itself could be served from catalog.example.com even if the id references authorize.example.com which could be used by an attacker as an attack vector
  • Instead of returning the Authentication Document in its HTTP response, catalog.example.com should instead:
    • redirect the user to the id of the Authentication Document using an HTTP redirection
    • use the Link header in its HTTP header
    • and/or use the authenticate property

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

No branches or pull requests

2 participants