Why is the way we authenticate the Service UI (and Classic UI too) against the API broken

In December when [1] was reported. The bug never made it to the release because it was Yadnyawalk Tale from our QE who found the problem in a test build. But anyway I started thinking and looking into how we authenticate in the Service UI.

First some technical background: We need to understand why in Rails (and other libraries) we use two authentication tokens.

We use:

  1. the session cookie,
  2. the CSRF token.

Why do we do that?

Because the 2 even though being transferred basically the same way have very different properties.

The session cookie is a cookie :wink: . That means it’s automatically added by the browser to each request w/o the javascript having to do anything.
Furthermore the session cookie is “HttpOnly” – it has the HttpOnly flag set. That means that the javascript CAN NOT get it’s value. See [3] for details.

Cookies are vulnerable to CSRF (cross site request forgery). Well that’s an oversimplification. Using cookies as the bearer of identity of the authenticated user (or the authentication user session) makes the authenticated session vulnerable to CSRF. See [4] for more info on CSRF.

To put it simple: If an attacker’s page manages to fire a request against your ManageIQ in the same browser session where you are logged in into ManageIQ, the request will have the correct cookie.

The CSRF token is not a cookie. It’s a secret that the javascript running inside the page owns. The javascript code adds CSRF tokens to requests that the application fires. It can be added as a header or as data in the POST request. It does not matter how, but the javascript code needs to add it actively to each request. (In case of POST data it can be added also as a hidden for field in HTML forms.)

In this aspect the CSRF token is equivalent to the API tokens that we use in ManageIQ to authenticate to the API.

Checking the CSRF token is mandatory on POST requests to prevent the CSRF that using just cookies would allow.

CSRF tokens are vulnerable to XSS (cross site scripting) [5] any malicious code that manages to run inside the page can read the token, use the token to do requests or even steal the token (e.g. by firing a request with that token against an attacker controller server).

As long as we use both CSRF token plus the session cookie, we are relatively safe. One deals with the weakness of the other.

I have to elaborate a bit on this “being safe”. In case of an XSS vulnerability an attacker manages to execute javascript code in the browser of an authenticated user. This may be enough for some serious damage, but in many cases such vulnerability will only allow a short piece of code to be executed or the code would not execute if it contains certain characters. The attacker is limited.

BUT if we use just the API and all we use to authenticate against the API is the token, then the attacker can comfortably elevate his abilities. He can simply take the token and open his own session with the server. He does not need the privileged user to keep his browser window opened to carry on his attack. He has the full power of the privileged user.

By using just the API token we are making the situation simple for the attacker. Once a simple programming oversight happens somewhere in future, the attacker would have a simple job.

[1] provides an example of such oversight.

This applies to the Service UI and also parts of the OPS UI that already use the REST API.

Let me elaborate in a an example:

  1. A low privileged user will create a snapshot on a VM with the malicious payload in the name of the snapshot using either OPS UI or the Service UI.
  2. Then a more privileged user displays the timeline in the UI and the payload gets executed in the context of the more privileged user.
  3. Javascript code in the payload steals the token.
  4. The token is all the attacker needs to fire his requests against the ManageIQ in whatever way he wants. He can create his own SUI session in a browser or use CURL or anything else.

I was searching yesterday for someone pointing out this problem elsewhere and I did find this [2] nice article that has many parts directly relevant to our situation with the API.

What to do next?

We should use hybrid API authentication:

  1. Keep the current mechanism for command-line or other clients.
  2. And implement cookie + token checking for web browser access.

Let’s get this fixed before there’s the next oversight and someone makes advantage of the situation.

[1] https://bugzilla.redhat.com/show_bug.cgi?id=1517396
[2] https://sakurity.com/blog/2015/03/04/hybrid_api_auth.html
[3] https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
[4] https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
[5] https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)