Integrating CSP for GitLab in Three Stages
This issue is intended to be a guide towards a full implementation of Content-Security-Policy both on GitLab.com and inside the GitLab application.
Summary
Content-Security-Policy is a tool designed to mitigate the all-too-common Cross-Site Scripting vulnerabilities seen on even the most modern web applications. CSP is implemented via an HTTP header that informs a web browser what types of scripts, forms, images, and various other content to load and what sources are allowed to provide these content types.
A large number of the day-to-day security issues GitLab deals with now are related to Cross-site Scripting and these issues will only grow with GitLab's popularity.
GitLab is way behind competitors and other cloud-based startups when it comes to integrating CSP. One previous attempt has been made (see issue 18231) but it overloaded our reporting service and broke innumerable features of the application.
I've created this issue as an attempted plan towards full CSP integration. The idea is to start by aiming low, with only a very basic CSP setting. This setting will be an embarrassment. It will tell anyone who sees it that we are way behind when it comes to implementing CSP. Hopefully that will motivate us moving forwards.
Some resources to understand how CSP works and how others have rolled out their CSP implementations are listed below. It will not be easy. We rely on a ton of inline Javascript, we allow users to post inline image links to any remote web service they wish using HTTP inside HTTPS pages, we utilize OAuth to numerous external entities that will break form restrictions. The GitLab application allows users to configure OAuth endpoints of their choosing which will also break secure CSP configurations.
https://content-security-policy.com/
https://developers.google.com/web/fundamentals/security/csp/
https://csp.withgoogle.com/docs/adopting-csp.html
CSP Mitigator Chrome Extension: https://chrome.google.com/webstore/detail/csp-mitigator/gijlobangojajlbodabkpjpheeeokhfa
https://blogs.dropbox.com/tech/2015/09/unsafe-inline-and-nonce-deployment/
https://github.com/blog/1477-content-security-policy
https://githubengineering.com/githubs-csp-journey/
https://githubengineering.com/githubs-post-csp-journey/
Old Issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/18231
I believe that we can accomplish a full, secure CSP rollout in three stages. The timeline for this rollout will be long and it will be fraught with landmines.
For stages 2 and 3 most of the work will be making substantial changes inside the GitLab application, especially on the front-end services.
We will need Infrastructure's help setting up a reporting service (Sentry may not be appropriate for this) and configuring the load balancer to act as a feature flag when we're ready near the end of each stage.
In each stage I've included a "target" CSP setting. These are the goal for that stage. They are expected to be adjusted as we progress.
Stage 1
Basic CSP tested, restrict scripts to specific hosts, deny flash/objects.
When completed this stage will provide only a marginal security benefit. XSS exploits will be prevented from loading scripts from random external sources but they will still be able to run inline scripts.
Target CSP Setting:
Content-Security-Policy: object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' piwik.gitlab.com https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/; style-src 'self' 'unsafe-inline'; img-src * data: blob:; frame-src 'self' https://www.google.com/recaptcha/; frame-ancestors 'self'; connect-src 'self' wss://gitlab.com;
-
Stand-up CSP reporting service. -
Decide on the most basic CSP policy to block script sources, object types, form locations if possible. -
Test a basic CSP policy inside a GitLab CE/EE test instance. -
Test the same basic CSP policy using the CSP Mitigator extension against GitLab.com -
Test the same basic CSP policy using the front-end proxy as a feature flag against specific test users in "report-only" mode. -
Test the same basic CSP policy using the front-end proxy as a feature flag against specific test users. -
Rollout stage 1 CSP to GitLab.com in "report-only" mode. -
Rollout stage 1 CSP to GitLab.com. -
Add stage 1 CSP to the GitLab CE/EE applications themselves as a configurable option.
Repeat these steps until we have a basic CSP configuration that breaks nothing and does not require re-factoring all inline scripts and image sources.
Stage 2
Integrate nonces, account for all services that require external form submissions. A list of valid form actions may not make it into this stage.
-
Make a first pass at refactoring all inline scripts to include nonces and tracking down all valid form actions. -
Test this CSP policy on a test GitLab instance that includes nonce and form requirements and fix all missing nonces and broken forms. -
Test the same CSP policy using the CSP Mitigator extension against GitLab.com and fix all missing nonces and broken forms. -
Test the same CSP policy using the front-end proxy as a feature flag against specific test users in "report-only" mode. -
Test the same CSP policy using the front-end proxy as a feature flag against specific test users. -
Rollout stage 2 CSP to GitLab.com in "report-only" mode. -
Rollout stage 2 CSP to GitLab.com. -
Add stage 2 CSP to the GitLab CE/EE applications themselves as a configurable option.
Stage 3
Replace all inline scripts. Proxy all images and restrict sources to the CDN/proxy. This is by far the most difficult stage and may not be possible to roll out in Omnibus or source applications.
-
Make a first pass at removing all inline scripts and proxying all images inside a CDN or GitLab proxy service. -
Test this CSP policy on a test GitLab instance. A proxy will likely be needed. -
Test the same CSP policy using the CSP Mitigator extension against GitLab.com. -
Test the same CSP policy using the front-end proxy as a feature flag against specific test users in "report-only" mode. -
Test the same CSP policy using the front-end proxy as a feature flag against specific test users. -
Rollout stage 3 CSP to GitLab.com in "report-only" mode. -
Rollout stage 3 CSP to GitLab.com. -
If possible, Add some variant of stage 3 CSP to the GitLab CE/EE applications themselves as a configurable option.