Skip to content
This repository was archived by the owner on Jul 27, 2018. It is now read-only.

Conversation

@jgarber623-gov
Copy link
Contributor

@jgarber623-gov jgarber623-gov commented Jan 10, 2018

Checklist

I have…

  • run the application locally (bin/rails server) and verified that my changes behave as expected.
  • run static code analysis (bin/rubocop) and vulnerability scan (bin/brakeman) against my changes.
  • run the test suite (bin/rake spec) and verified that all tests pass.
  • summarized below my changes and noted which issues (if any) this pull request fixes or addresses.
  • thoroughly outlined below the steps necessary to test my changes.

Summary of Changes

This pull request adds Twitter's secure_headers gem to the project and uses its features to implement more-secure HTTP response headers (e.g. X-Frame-Options, Content-Security-Policy) for routes served by the Rails app.

The move to do this was prompted by a conversation with @jobertabma at HackerOne. He noted the remote possibility of an attacker compromising a developer machine and taking advantage of our previous decision to offload header-setting to nginx instead of Rails/Action Dispatch.

Testing

To verify the changes proposed in this pull request…

  1. clone this repo,
  2. git checkout secure-headers,
  3. set up development dependencies according to CONTRIBUTING.md,
  4. run bin/rails server,
  5. load up http://localhost:3000 and check your browser's console for the appropriate response headers.


# HSTS (HTTP Strict Transport Security)
# This header tells browsers to cache the certificate for six months and to connect exclusively via HTTPS.
add_header Strict-Transport-Security "max-age=15768000" always;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we'd want to move some of these headers into the location blocks covering assets and/or error pages.

@hlieberman-gov What's your take?


# Disable ActionDispatch's default headers (these are handled by nginx)
config.action_dispatch.default_headers = {}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this anymore…

config.action_dispatch.default_headers.merge!(
'X-UA-Compatible' => 'IE=Edge'
)
end
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

secure_headers doesn't cover this IE-specific header, so adding this initializer here and merging it with Action Dispatch's default headers.

config.hsts = 'max-age=15768000'
config.referrer_policy = %w[origin-when-cross-origin strict-origin-when-cross-origin]
config.x_content_type_options = 'nosniff'
config.x_download_options = 'noopen'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one's new to me, but interesting: https://msdn.microsoft.com/library/jj542450(v=vs.85).aspx

}

config.hsts = 'max-age=15768000'
config.referrer_policy = %w[origin-when-cross-origin strict-origin-when-cross-origin]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't familiar with the Referrer Policy spec, but I like it.

config.x_content_type_options = 'nosniff'
config.x_download_options = 'noopen'
config.x_frame_options = 'deny'
config.x_permitted_cross_domain_policies = 'none'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# you can tell the browser that it can only download content from the domains you explicitly allow
# CSP can be quite difficult to configure, and cause real issues if you get it wrong
# There is website that helps you generate a policy here http://cspisawesome.com/
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://dap.digitalgov.gov https://www.google-analytics.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://www.google-analytics.com *.tile.openstreetmap.org; frame-ancestors 'none'; frame-src https://www.youtube.com;" always;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need to make sure this CSP header is delivered on root requests. For the error pages in particular, as well as any other directly delivered HTML, we should add one in.


# MIME type sniffing security protection
# There are very few edge cases where you wouldn't want this enabled.
add_header X-Content-Type-Options nosniff always;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we want this one delivered on static content.


# The X-Frame-Options header indicates whether a browser should be allowed
# to render a page within a frame or iframe.
add_header X-Frame-Options SAMEORIGIN always;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we ever iframe this page internally? Might be worth changing to DENY; either way, we should preserve this on static content.


# The X-XSS-Protection header is used by Internet Explorer version 8+
# The header instructs IE to enable its inbuilt anti-cross-site scripting filter.
add_header X-XSS-Protection "1; mode=block" always;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meh. If we can, great, otherwise, don't sweat it.


# HSTS (HTTP Strict Transport Security)
# This header tells browsers to cache the certificate for six months and to connect exclusively via HTTPS.
add_header Strict-Transport-Security "max-age=15768000" always;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HSTS we should pass on all requests, but it's not the end of the world if we don't do it for the static content, especially if we're planning on preloading.

style_src: %w['self' 'unsafe-inline']
}

config.hsts = 'max-age=15768000'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should bump to max-age=63072000; includeSubDomains; preload

jgarber623-gov added a commit that referenced this pull request Jan 12, 2018
jgarber623-gov added a commit that referenced this pull request Feb 1, 2018
jgarber623-gov added a commit that referenced this pull request Feb 1, 2018
jgarber623-gov added a commit that referenced this pull request Feb 1, 2018
jgarber623-gov added a commit that referenced this pull request Feb 1, 2018
jgarber623-gov added a commit that referenced this pull request Feb 27, 2018
jgarber623-gov added a commit that referenced this pull request Mar 8, 2018
@jgarber623-gov jgarber623-gov changed the title Implement secure_headers gem [WIP] Implement secure_headers gem Mar 9, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants