CSRF on /login security alert from security scans

I am using discourse via docker containers in a local docker swarm. The installation went smoothly and we have been able to get a working prototype deployed within a super short period of time. Thanks for the great docs!

We then needed to get our business security scans run to be able to set up the proper proxies for getting discourse accessible via the outside world. All went well, except for a missing CSFR protection on /login. We have the local logins enabled and are being alerted that the /login url (looks like it is linked to the nice login window that is presented over the main page on login request) does not appear to have CSRF protection.

We are deployed behind a firewall, so access to Github to use the Git OAuth is not possible. That said, I have enabled it because we can watch the authentication attempt as the request hits Github and then see the failure logged in production.log (expected because Git has not access back to our discourse install). I mention this because the login attempt to GitHub includes CSRF protection, but the local login does not.

Local:

Started GET "/login.html?_=1545151335383" for xxx.xxx.xxx.xxx at 2018-12-18 16:42:15 +0000
Processing by StaticController#show as HTML
  Parameters: {"_"=>"1545151335383", "id"=>"login"}
  Rendering static/login.html.erb
  Rendered static/login.html.erb (19.5ms)

GitHub:

Started GET "/auth/github" for xxx.xxx.xxx.xxx at 2018-12-18 18:34:32 +0000
(github) Setup endpoint detected, running now.
(github) Request phase initiated.
Started GET "/auth/github/callback?code=AUTHCODE" for xxx.xxx.xxx.xxx at 2018-12-18 18:34:52 +0000
(github) Setup endpoint detected, running now.
(github) Callback phase initiated.
(github) Authentication failure! csrf_detected: OmniAuth::Strategies::OAuth2::CallbackError, csrf_detected | CSRF detected
Started GET "/auth/failure?message=csrf_detected&strategy=github" for xxx.xxx.xxx.xxx at 2018-12-18 18:34:52 +0000
Processing by Users::OmniauthCallbacksController#failure as HTML
  Parameters: {"message"=>"csrf_detected", "strategy"=>"github"}
  Rendering users/omniauth_callbacks/failure.html.erb within layouts/no_ember
  Rendered users/omniauth_callbacks/failure.html.erb within layouts/no_ember (0.7ms)
  Rendered layouts/_head.html.erb (7.4ms)
  Rendered common/_discourse_stylesheet.html.erb (0.2ms)
  Rendered application/_header.html.erb (0.1ms)

Is /login missing CSRF protection or have we missed an installation step?

You mention that GitHub OAuth is not possible due to your firewall, so I’m not sure what the logs are supposed to be illustrating. The CSRF error on GitHub login would be expected if you have not configured it correctly.

What do you mean by this? If you’re being told this by an automated security scanner, then it is very likely to be a false positive.

1 Like

@David Thanks. I suspected it might be a false positive. What I was trying to illustrate is that the Github login appears to have CSRF protection, while the local login does not. I do not see any csrf_detected notifications in the log when using the local login.

I need to prove to the security team that the /login page is actually protected.

The full source code is available at https://github.com/discourse/discourse

From our security document:

@David Thanks! I have seen that documentation and forwarded along to the security team. I will dig into the source. I was surprised not see an csrf session logging into the production logs, but will look at the source to also forward the code block to them. Appreciated.

@David We did some more digging and monitoring of the requests and responses. It looks like the the CSRF token is not granted until the user logs in. When visiting the site the CSRF token is not being assigned. This is what our security folks are flagging - no CSRF token until logged in therefore, on initial visit we do not have a CSRF token. Is this intentional?

If we are logged in we see the following in the response:

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="TOKEN" />

Here is a get/response when not logged in. We do not see a meta tag with the csrf.

GET / HTTP/1.1
Host: astrodiscuss.usgs.gov
Connection: close
Purpose: prefetch
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

HTTP/1.1 200 OK
Server: nginx/1.14.0
Date: Wed, 19 Dec 2018 17:07:47 GMT
Content-Type: text/html; charset=utf-8
Connection: close
Vary: Accept-Encoding
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
X-Discourse-Route: list/latest
Cache-Control: no-cache, no-store
X-Discourse-Cached: true
X-Request-Id: 2df19db3-ca64-4920-a909-073854ab2b03
X-Runtime: 0.001948
X-Discourse-TrackView: 1
Strict-Transport-Security: max-age=31536000
Content-Length: 57226

<!DOCTYPE html>
<html lang="en" class="desktop-view not-mobile-device  anon">
  <head>
    <meta charset="utf-8">
    <title>AstroDiscuss</title>
    <meta name="description" content="USGS Astrogeology Discussion">
    <meta name="discourse_theme_ids" content="1">
    <meta name="discourse_current_homepage" content="latest">
    <meta name="author" content="">
<meta name="generator" content="Discourse 2.2.0.beta5 - https://github.com/discourse/discourse version 414aa1fe7a8e968b00a8bd8e103ce34a42a25028">
<link rel="icon" type="image/png" href="/images/default-favicon.ico">
<link rel="apple-touch-icon" type="image/png" href="https://astrodiscuss.usgs.gov/images/default-apple-touch-icon.png">
<meta name="theme-color" content="#111111">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=yes">

<script type="application/ld+json">{"@context":"http://schema.org","@type":"WebSite","url":"https://astrodiscuss.usgs.gov","potentialAction":{"@type":"SearchAction","target":"https://astrodiscuss.usgs.gov/search?q={search_term_string}","query-input":"required name=search_term_string"}}</script>
<link rel="search" type="application/opensearchdescription+xml" href="https://astrodiscuss.usgs.gov/opensearch.xml" title="AstroDiscuss Search">
...(more HTML)

From our security doc:

And the relevent piece of the code which fetches the CSRF code before performing the request:

https://github.com/discourse/discourse/blob/master/app/assets/javascripts/discourse/lib/ajax.js.es6#L149-L166

5 Likes