Skip to content

Commit

Permalink
Merge pull request #4312 from daniel-beck/user-content
Browse files Browse the repository at this point in the history
Generalize CSP page to document serving user content
  • Loading branch information
daniel-beck authored May 1, 2021
2 parents a436918 + a9eb60f commit 401dab3
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 37 deletions.
2 changes: 1 addition & 1 deletion content/doc/book/security/_chapter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sections:
# Individual how-to pages
- controller-isolation
- csrf-protection
- configuring-content-security-policy
- user-content
- build-authorization
- environment-variables
- markup-formatter
Expand Down
2 changes: 1 addition & 1 deletion content/doc/book/security/build-authorization.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Access Control for Builds
layout: section
layout: documentation
---

Similar to access control for users, builds in Jenkins run with an associated user authorization.
Expand Down
46 changes: 12 additions & 34 deletions content/doc/book/security/configuring-content-security-policy.adoc
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
---
title: Configuring Content Security Policy
layout: section
layout: documentation
---
ifdef::backend-html5[]
:toc: left
endif::[]

Jenkins 1.641 / Jenkins 1.625.3 introduce the `Content-Security-Policy` header to static files served by Jenkins (specifically `DirectoryBrowserSupport`).
This header is set to a very restrictive default set of permissions to protect Jenkins users from malicious HTML/JS files in workspaces, `/userContent`, or archived artifacts.

Unfortunately, several popular, useful plugins are affected by this and lose part of their functionality unless the default rules are relaxed.

*Alternatives*

TIP: Since Jenkins 2.200, it is possible to define a *Resource Root URL* in the Jenkins system configuration as an alternative to relaxing the Content Security Policy rules.
See its inline help for details.

This page describes the restrictions applied by potentially untrusted files served by Jenkins by default and how to customize them.

== The Default Rule Set

The default rule is set to:

[source,javascript]
----
sandbox; default-src 'none'; img-src 'self'; style-src 'self';
----

This rule set results in the following:
The default rule set results in the following:

* No JavaScript allowed at all
* No plugins (object/embed) allowed
Expand All @@ -37,7 +21,12 @@ This rule set results in the following:
* No XHR/AJAX allowed
* etc.

In detail:
The `Content-Security-Policy` header value is:

[source,javascript]
----
sandbox; default-src 'none'; img-src 'self'; style-src 'self';
----

* `sandbox` limits a number of things of what the page can do, similar to the `sandbox` attribute set on iframes.
For a full list of what is prohibited, see https://html.spec.whatwg.org/multipage/browsers.html#sandboxing-flag-set[this site].
Expand All @@ -51,21 +40,10 @@ Inline style sheets are prohibited.

See https://content-security-policy.com/[content-security-policy.com] for a reference on this header and its possible values.

== Getting things working

The most expedient approach is to use Jenkins 2.200+ and set up a second domain pointing to the same Jenkins instance (Jenkins URL:build.example.com; Resource Root URL: build-artifacts.example.com).
This will result in resources being served from the resource root URL instead of the Jenkins URL.
The advantage of this is that there are no cookies associated with this domain, and file paths are hopefully sufficiently non predictable that people won't be able to exfiltrate content.

=== Considerations

The resource root URLs linked from Jenkins include individual secret keys which can be shared by users to people who don't otherwise have permission to access Jenkins.
They have a site-wide configurable timeout.

== Relaxing The Rules
== Customizing Content Security Policy

This is highly discouraged.
If `resource root URL`  doesn't work for you, please reach out to the Jenkins team.
IMPORTANT: It is strongly recommended to set up the link:../user-content/#resource-root-url[Resource Root URL] instead of customizing Content-Security-Policy.
Most of the documentation below was written when `Content-Security-Policy` was first introduced and is retained for use by administrators unable to set up Jenkins to serve user content from a different domain.

=== Considerations

Expand Down
2 changes: 1 addition & 1 deletion content/doc/book/security/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ The default markup formatter renders text as entered (i.e. escaping HTML metacha
This chapter explains how to switch to a different markup formatter and explains what admins need to be aware of. +
_This is set up securely by default._

link:configuring-content-security-policy[Configuring Content Security Policy]::
link:user-content[Rendering User Content]::
By default, Jenkins strictly limits the features useable in user content (files from workspaces, archived artifacts, etc.) it serves.
This chapter discusses how to customize this and make HTML reports and similar content both functional and safe to view. +
_This is set up securely by default._
73 changes: 73 additions & 0 deletions content/doc/book/security/user-content.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: Rendering User Content
layout: section
---
ifdef::backend-html5[]
:toc:
ifdef::env-github[:imagesdir: ../resources]
ifndef::env-github[:imagesdir: ../../resources]
:hide-uri-scheme:
endif::[]

Multiple features of Jenkins, and many more in plugins, serve files that can be viewed or downloaded from Jenkins.
Some built-in examples of that are the workspace browser, archived artifacts, file parameters to builds, or the `/userContent/` directory.
Plugins like plugin:javadoc[Javadoc], plugin:htmlpublisher[HTML Publisher], or plugin:maven-plugin[Maven Integration] (when publishing the Maven site) prominently feature functionality that serves HTML controlled by users from Jenkins.

This can be a risk, as https://owasp.org/www-community/attacks/xss/[Cross-Site Scripting] attacks could be put into those HTML files by people with influence over builds who may not be fully trusted.

== Content-Security-Policy

By default, Jenkins serves files that could come from less trusted sources with a strict `Content-Security-Policy` HTTP response header.
This default prevents all JavaScript and other active elements, and only allows CSS and images served from other files in Jenkins.

While this is safe, it also prevents a lot of useful functionality from working, such as rich, dynamic HTML reports created during builds.
It is possible to link:../configuring-content-security-policy/[configure Content-Security-Policy].
This is often a difficult tradeoff between functionality and security, so should only be done with great care.

== Resource Root URL

As an alternative to relaxing `Content-Security-Policy`, administrators can configure Jenkins to serve files from potentially less trusted sources from a different domain.
This option can be configured in _Manage Jenkins » Configure System_ in the section _Serve resource files from another domain_.

// TODO Screenshot

// All of what follows is taken from https://github.com/jenkinsci/jenkins/blob/master/core/src/main/resources/jenkins/security/ResourceDomainConfiguration/help-url.html

If the resource root URL is defined, Jenkins will instead redirect requests for user-created resource files to URLs starting with the URL configured here.
These URLs will not set the CSP header, allowing JavaScript and similar features to work.
For this option to work as expected, the following constraints and considerations apply:

* The resource root URL must be a valid alternative choice for the Jenkins URL for requests to be processed correctly.
* The Jenkins URL must be set and it must be different from this resource root URL (in fact, a different host name is required).
* Once set, Jenkins will only serve resource URL requests via the resource root URL.
All other requests will get _HTTP 404 Not Found_ responses.

Once this URL has been set up correctly, Jenkins will redirect requests to workspaces, archived artifacts, and similar collections of usually user-generated content to URLs starting with the resource root URL.
Instead of a path like `job/name_here/ws`, resource URLs will contain a token encoding that path, the user for which the URL was created, and when it was created.
These resource URLs access static files as if the user for which they were created would access them: If the user’s permission to access these files is removed, the corresponding resource URLs will not work anymore either.
**These URLs are accessible to anyone without authentication until they expire, so sharing these URLs is akin to sharing the files directly.**

=== Security considerations

==== Authentication

Resource URLs do not require authentication (users will not have a valid session for the resource root URL).
Sharing a resource URL with another user, even one lacking Overall/Read permission for Jenkins, will grant that user access to these files until the URLs expire.

==== Expiration

Resource URLs expire after 30 minutes by default.
Expired resource URLs will redirect users to their equivalent Jenkins URLs, so that the user can reauthenticate, if necessary, and then be redirected back to a new resource URL that will be valid for another 30 minutes.
This will generally be transparent to the user if they have a valid Jenkins session.
Otherwise, they will need to authenticate with Jenkins again.
However, when browsing pages with HTML frames, like Javadoc sites, the login form cannot appear in a frame.
In these cases, users will need to reload the top-level frame to make the login form appear.

To change how quickly resource URLs expire, set the system property `jenkins.security.ResourceDomainRootAction.validForMinutes` to the desired value in minutes.
Earlier expiration might make it harder to use these URLs, while later expiration increases the likelihood of unauthorized users gaining access through URLs shared with them by authorized users.

==== Authenticity

Resource URLs encode the URL, the user for which they were created, and their creation timestamp.
Additionally, this string contains an https://en.wikipedia.org/wiki/HMAC[HMAC] to ensure the authenticity of the URL.
This prevents attackers from forging URLs that would grant them access to resource files as if they were another user.

0 comments on commit 401dab3

Please sign in to comment.