wopiserver icon indicating copy to clipboard operation
wopiserver copied to clipboard

Encrypt access tokens

Open micbar opened this issue 1 year ago • 14 comments

Description

We need to encrypt our JWTs before we send them to the Web Application.

Spec

https://www.rfc-editor.org/rfc/rfc7516

To do

  • [x] Implement Key generation
  • [x] Implement Encrypt/Decrypt
  • [x] Add config switch
  • [ ] Add Documentation
  • [ ] Test with invalid tokens

Config

This can be enabled in the wopiserver.conf

# location of the secret files. Requires a restart of the
# WOPI server when either the files or their content change.
wopisecretfile = /etc/wopi/wopisecret
iopsecretfile = /etc/wopi/iopsecret
jwesecretfile = /etc/wopi/jwesecret
encryptjwetoken = True

Outcome

Payload is encrypted, headers are readable

1664985777406

micbar avatar Oct 05 '22 15:10 micbar

The reasoning is that the REVA access tokens is send inside the WOPI JWT token to following services:

  • Office Application
  • Client Browser
  • depending on deployment: reverse proxy

The REVA access token is only intended to be used by the WOPI server and should never be exposed to 3rd party services.

wkloucek avatar Oct 05 '22 16:10 wkloucek

The REVA access token is only intended to be used by the WOPI server and should never be exposed to 3rd party services.

This PR implements an interesting feature indeed, thanks. But I dare challenging this statement: AFAIU currently the web UI holds the Reva access token as well, so it does not seem it is meant for backend services only or for limited distribution - clients have a way to hold it and reuse it as they like. Also, if we were to restrict the WOPI server to not include the Reva token within its own token, the WOPI server would become a stateful service requiring a central key/value store for the Reva tokens. IMHO this would over-complexify the service, for relatively little added benefit (WOPI traffic is https as well as client browser traffic).

glpatcern avatar Oct 05 '22 16:10 glpatcern

The REVA access token is only intended to be used by the WOPI server and should never be exposed to 3rd party services.

This PR implements an interesting feature indeed, thanks. But I dare challenging this statement: AFAIU currently the web UI holds the Reva access token as well, so it does not seem it is meant for backend services only or for limited distribution - clients have a way to hold it and reuse it as they like. Also, if we were to restrict the WOPI server to not include the Reva token within its own token, the WOPI server would become a stateful service requiring a central key/value store for the Reva tokens. IMHO this would over-complexify the service, for relatively little added benefit (WOPI traffic is https as well as client browser traffic).

ownCloud Web uses an OIDC access token (also JWT for most OIDC providers) - but never a REVA JWT token. These OIDC access tokens are typically short lived.

We still transport the REVA access token inside the WOPI JWT token to prevent the WOPI server becoming a stateful application. But since the token is now encrypted, only the WOPI server can inspect it.

wkloucek avatar Oct 05 '22 18:10 wkloucek

We still transport the REVA access token inside the WOPI JWT token to prevent the WOPI server becoming a stateful application. But since the token is now encrypted, only the WOPI server can inspect it.

Correct. This adds no more state to the wopiserver. If we scale the wopiserver into multiple ones, we need to share the config volume with the secrets. But that was already the case for the wopisecret and the iopsecret

Difference between OIDC tokens and Reva Access Tokens

Web token payload

{
  "aud": "web",
  "exp": 1665046243,
  "jti": "B13TElT2QKAw58AhEswPfZxV34skINBn",
  "iat": 1664959843,
  "iss": "https://localhost:9200",
  "sub": "vn047YDEoJdbFHQ7@x0o8AjgeB8vaEK8M5rD1nIR359aUVKRXsY8LSSOCzV_8rJwROifQQAn9PxBxgomJlmPNEQ",
  "lg.t": "1",
  "scp": "profile email openid",
  "lg.i": {
    "dn": "Admin",
    "id": "uid=admin,ou=users,o=libregraph-idm",
    "un": "admin"
  },
  "lg.p": "identifier-ldap"
}

Reva Access Token payload

{
  "appediturl": "http://localhost:8090/hosting/wopi/word/edit",
  "appname": "OnlyOffice",
  "appviewurl": "http://localhost:8090/hosting/wopi/word/view",
  "endpoint": "1284d238-aa92-42ce-bdc4-0b0000009157$some-admin-user-id-0000-000000000000",
  "exp": 1665067872,
  "filename": "some-admin-user-id-0000-000000000000/Neue Datei (1).docx",
  "folderurl": "https://localhost:9200/f/1284d238-aa92-42ce-bdc4-0b0000009157$some-admin-user-id-0000-000000000000!f42aefa3-0f90-4d21-8ade-95b0c8658383",
  "iss": "cs3org:wopiserver:git",
  "userid": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJyZXZhIiwiZXhwIjoxNjY1MDY3ODcyLCJpYXQiOjE2NjQ5ODE0NzIsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0OjkyMDAiLCJ1c2VyIjp7ImlkIjp7ImlkcCI6Imh0dHBzOi8vbG9jYWxob3N0OjkyMDAiLCJvcGFxdWVfaWQiOiJzb21lLWFkbWluLXVzZXItaWQtMDAwMC0wMDAwMDAwMDAwMDAiLCJ0eXBlIjoxfSwidXNlcm5hbWUiOiJhZG1pbiIsIm1haWwiOiJhZG1pbkBleGFtcGxlLm9yZyIsImRpc3BsYXlfbmFtZSI6IkFkbWluIiwiZ3JvdXBzIjpbIjUwOWE5ZGNkLWJiMzctNGY0Zi1hMDFhLTE5ZGNhMjdkOWNmYSJdLCJ1aWRfbnVtYmVyIjo5OSwiZ2lkX251bWJlciI6OTl9LCJzY29wZSI6eyJ1c2VyIjp7InJlc291cmNlIjp7ImRlY29kZXIiOiJqc29uIiwidmFsdWUiOiJleUp3WVhSb0lqb2lMeUo5In0sInJvbGUiOjF9fX0.eMVvQJRl_4P8tRWqQYZfhejcBHUyS2Ct5Z-GDq-AxEI",
  "username": "Admin",
  "viewmode": "VIEW_MODE_READ_WRITE",
  "wopiuser": "some-admin-user-id-0000-000000000000@https://localhost:9200"
}

Payload the userid which is in fact a Reva Token

{
  "aud": "reva",
  "exp": 1665067872,
  "iat": 1664981472,
  "iss": "https://localhost:9200",
  "user": {
    "id": {
      "idp": "https://localhost:9200",
      "opaque_id": "some-admin-user-id-0000-000000000000",
      "type": 1
    },
    "username": "admin",
    "mail": "[email protected]",
    "display_name": "Admin",
    "groups": [
      "509a9dcd-bb37-4f4f-a01a-19dca27d9cfa"
    ],
    "uid_number": 99,
    "gid_number": 99
  },
  "scope": {
    "user": {
      "resource": {
        "decoder": "json",
        "value": "eyJwYXRoIjoiLyJ9"
      },
      "role": 1
    }
  }
}

micbar avatar Oct 05 '22 18:10 micbar

@glpatcern @C0rby @wkloucek I think this is an important gain in security.

micbar avatar Oct 05 '22 19:10 micbar

@micbar as mentioned I approve this feature, there's no question. I'm just claiming that there's not such security gain as the surface attack is very small: either the client needs to be compromised (and then all bets are off, an attacker would have much more juice to look out in the browser's cache than the WOPI token...), or the application endpoint needs to be compromised (which I guess we must exclude, but consequences would be much worse as the whole content of users' documents gets exfiltrated anyway!).

Also, another option worth considering in the future is to downscope the Reva token to the area of interest for WOPI operations - essentially read/write on the file and potentially other files in the same folder, nothing else.

BTW I actually assumed we expose the Reva token on web and I now realize this is not the default, but it's what we're doing and we're even going one step further as you've seen on https://github.com/cs3org/reva/pull/3315, for as important usability reasons. More details on that will come from @labkode.

glpatcern avatar Oct 06 '22 09:10 glpatcern

BTW I actually assumed we expose the Reva token on web and I now realize this is not the default, but it's what we're doing and we're even going one step further as you've seen on https://github.com/cs3org/reva/pull/3315, for as important usability reasons. More details on that will come from @labkode.

Seen it. See my comment. IMO we should never work with reva tokens on clients.

micbar avatar Oct 06 '22 10:10 micbar

... or the application endpoint needs to be compromised (which I guess we must exclude, but consequences would be much worse as the whole content of users' documents gets exfiltrated anyway!).

Also, another option worth considering in the future is to downscope the Reva token to the area of interest for WOPI operations - essentially read/write on the file and potentially other files in the same folder, nothing else.

In some cases like SaaS Web Office (eg. Office 365) the attack surface is unknown and out of your control. So one should better not give them credentials, they do not need.

Exactly, the REVA token should be scoped. But also the WOPI token is already scoped to the current document, so we would be fine for the beginning.

wkloucek avatar Oct 06 '22 10:10 wkloucek

I think this concept is good.

In some cases like SaaS Web Office (eg. Office 365) the attack surface is unknown and out of your control. So one should better not give them credentials, they do not need.

This also increases the difficulty of attacks via macros in documents. As of right now, it's possible to get access to a users reva token by sharing a document containing a macro. Sure there is a warning when opening those documents but as we saw in the past documents containing macros is a widely used and working attack surface.

C0rby avatar Oct 12 '22 14:10 C0rby

This also increases the difficulty of attacks via macros in documents. As of right now, it's possible to get access to a users reva token by sharing a document containing a macro.

@C0rby can you please elaborate on this? Are you saying that there's a known flaw in Office 365 such that the WOPI token gets exposed if a document contains a (specially-crafted, I guess) macro?

glpatcern avatar Oct 12 '22 14:10 glpatcern

I wasn't been able to test this in Office365 yet but at least on OnlyOffice there is the option to add macros to a document under the plugins tab. image These are JavaScript macros. This code for example is able to print the download url of the current document to the browser console:

(function()
{
    console.log(parent.fileInfo.DownloadUrl);
})();

This download url also contains the wopi token (which contains the reva token) as a query parameter.

If I, as an attacker, would want to get the tokens of other people I could just send this download url to a server under my control instead of printing it to the console.

Whether this is a flaw or not depends on the person you ask, I guess. Macros are there to allow the user to execute arbitrary code. So this works as designed.

I would like to test if something like this works on Office365 but currently in our demo instance I'm unable to open a document there.

C0rby avatar Oct 12 '22 15:10 C0rby

This may be considered a serious flaw on the macro engine in OnlyOffice, and the fact that the WOPI token is exposed (regardless the Reva token being encrypted) is already a sufficient threat - as I mentioned, with that any document can easily be exfiltrated or deleted.

Yet, as an attacker, you'd need to get control over the client's browser to be able to execute that macro. Otherwise how would you force a client to execute your macro?

glpatcern avatar Oct 12 '22 16:10 glpatcern

Yet, as an attacker, you'd need to get control over the client's browser to be able to execute that macro. Otherwise how would you force a client to execute your macro?

The attacker could just share a document with a macro to users of the instance. Yes, this means the attacker needs to have an account or access to an account of an oCIS deployment and the sharees need to open the document.

But both situations are not impossible.

C0rby avatar Oct 14 '22 07:10 C0rby

OK, so we're back to a "traditional" phishing attack. Surely not to be neglected, but the attack surface is not getting significantly larger. IMHO once an attacker gets access to an organization, there's plenty of easier penetration paths than this to leverage.

glpatcern avatar Oct 14 '22 08:10 glpatcern