Security

Session management

Sessions are stored on the server in Posit Connect. Encrypted session cookies stored only on the client are deprecated, as they provide inferior security.

When signing into Posit Connect, a browser cookie is used to keep the user logged in. See the Limiting Session Lifetime section for details about the default session lifetime and how to change it.

The server periodically checks the data store for expired cookies and remove them. This happens once per hour by default, but is configurable using the Authentication.CookieSweepDuration configuration setting. This does not affect the lifetime of web sessions, which is controlled by the Authentication.Lifetime configuration setting.

API security

Preventing brute force & dictionary attacks

By default, Posit Connect allows as many login attempts as it can handle from any source when using the PAM, LDAP, and Password authentication providers. Users can log in directly by entering their user name and password.

Setting the Authentication.ChallengeResponseEnabled flag to true enables a CAPTCHA form in the login screen, and requires that CAPTCHA be solved in order to authenticate. Both visual and audio CAPTCHA challenges are provided for accessibility needs.

Hiding Posit Connect server version and build information

By default, Posit Connect sets the Server HTTP header to the Connect version with commit offset, which looks something like Posit Connect v1.2.3-1234. If you would like to hide this information you can configure Server.ServerName to be any string. If you would also like to hide the version and build information within the Connect dashboard you may configure the Server.HideVersion setting to be true.

Browser security

There are a variety of security settings that can be configured in Posit Connect. Some of these settings are enabled by default but can be customized while others are opt-in. Below are some of the security features worth considering.

Web sudo mode

When a user performs a sensitive operation in a web browser (such as creating a new API key), they will be asked to reenter their login credentials. Once the user enters their password properly, their session enters a privileged state internally referred to as web sudo mode which allows them to perform these sensitive operations for a certain window of time without entering their password again. Note that this privileged mode is a notion purely internal to Posit Connect and entirely unrelated to the server’s actual sudo or PAM settings.

Important

This feature is not available on servers configured to use Single Sign-On (SSO) via OAuth2, OpenID, SAML, or proxied authentication, as these providers don’t have a mechanism for re-prompting the user for their password.

For all other authentication providers, the WebSudoMode and WebSudoModeDuration configuration options are available within the section pertaining to that provider. If WebSudoMode is set to false, then this protection is disabled. Effectively, all authenticated users are always in privileged mode. WebSudoModeDuration controls the length of time for which a user stays in this privileged mode. From within the section pertaining to your authentication provider (such as [Password], [PAM], or [LDAP]), you can configure:

; /etc/rstudio-connect/rstudio-connect.gcfg

; This example is using password authentication. Use PAM or LDAP as appropriate.
[Password]
WebSudoMode = true
WebSudoModeDuration = 10m

In this case, users are prompted for their password before performing sensitive actions, and are then allowed to continue performing sensitive actions for up to 10 minutes without additional prompts. After that point, any sensitive actions require entering their password again.

Regardless of the setting, web sudo mode will never affect calls made outside of a browser using a token or an API key.

Limiting session lifetime

The default Posit Connect configuration enforces the following limits on authenticated sessions:

  1. Sessions are invalidated after 24 hours, regardless of activity.
  2. Inactive sessions are considered idle and invalidated after 8 hours.

Once a session is considered invalid, the user needs to reauthenticate before continuing to interact with Posit Connect.

These limits follow good security practices by ensuring that users enter their credentials daily.

The session lifetime and inactive threshold are configurable settings. Adjust the maximum session lifetime by changing the Authentication.Lifetime setting. Session inactivity is controlled with the Authentication.Inactivity setting.

Configure these session settings according to your organization’s security policies.

We use a 24 hour default for Authentication.Lifetime because it means that access is revalidated against your authentication provider (e.g., your Active Directory server) at least once a day. The 8 hour default for Authentication.Inactivity tries to avoid forcing a user to reauthenticate more than once during a typical work day.

Our first configuration example has shorter thresholds than the configured defaults. Users need to reauthenticate after being idle for 30 minutes or after their session lasts for 12 hours. The 30 minute inactivity limit means that sessions may be idle “no longer than a lunch break.”

; /etc/rstudio-connect/rstudio-connect.gcfg
[Authentication]
Lifetime = 12h
Inactivity = 30m

This second configuration example has longer thresholds than our configured defaults. Users need to reauthenticate once a week, or after being inactive for a full day. Adopt this type of configuration with care; your organization may want users to reauthenticate more frequently.

; /etc/rstudio-connect/rstudio-connect.gcfg
[Authentication]
Lifetime = 7d
Inactivity = 1d

Posit Connect uses session cookies to track and enforce both the session lifetime and inactive threshold.

Note

If a user’s session expires or is considered inactive with an application left running in their browser that application’s process is not terminated immediately. Further attempts to interact with the application then cause it to close and then the user will be asked to reenter credentials.

Note

Applications may be able to outlive sessions when opened in Solo mode if their timeout settings are greater than Authentication.Inactivity or Authentication.Lifetime. The settings Scheduler.ConnectionTimeout and Scheduler.ReadTimeout determine the default values for how long a browser running an application can remain idle. By default these are set to 1 hour but individual applications may set higher values independently from the server’s settings.

Guaranteeing HTTPS

If you can guarantee that your server should only ever be accessed over a TLS/SSL connection (HTTPS), then you can consider enabling the HTTPS.Permanent setting. This elevates the security of your server by requiring that future interactions between your users and this server must be encrypted. For more information on using SSL Certificates with Connect, see the Configuring SSL Certificates in Posit Connect section.

Note

Enabling this setting may keep users from being able to access your Posit Connect instance if you later disable HTTPS or if your certificate expires. Use this setting only if you will permanently provide a valid TLS/SSL certificate on this server.

Behind the scenes, this makes two changes:

  1. Introduces HTTP Strict Transport Security (HSTS) by adding a Strict-Transport-Security HTTP header with a max-age set to 30 days. The default can be overridden by setting HTTPS.StrictTransportSecurityMaxAge. HSTS ensures that your users’ browsers will not trust a service hosted at this location unless it is protected with a trusted TLS/SSL certificate.

  2. Enforces the Secure flag on cookies that are set. This prohibits your users’ browsers from sending their Posit Connect cookies to a server without an HTTPS-secured connection.

Strong HTTPS

You can constrain the TLS version used by HTTPS. This may help you meet the security policy for your organization.

The HTTPS.MinimumTLS setting specifies the minimum TLS version. Clients using a lower TLS version will be rejected. The default minimum TLS version is TLS 1.0. You can configure this setting to 1.0, 1.1, 1.2, or 1.3.

We recommend that you check that the browsers and clients used within your organization are compatible with your minimum TLS version choice. The SSL Labs User Agent List enumerates the TLS capabilities for most popular browsers.

Here is an HTTPS configuration permitting TLS versions 1.2 and above:

[HTTPS]
Listen = 443
MinimumTLS = 1.2
Note

Some Windows builds of the RCurl package are not compatible with TLS 1.1 or TLS 1.2. Windows users should execute options(rsconnect.http = 'curl') to use the local curl binary, if installed, instead of the outdated RCurl package.

Note

Older versions of the RStudio IDE may use webviews that are not compatible with TLS 1.1 or TLS 1.2. In this case, attempting to pair with Posit Connect without TLS 1.0 would open a blank screen instead of a login window. Open the blue link from the pairing window in the browser, or install a newer version of Posit Connect as a workaround.

We recommend using a secure proxy if you need finer control over HTTPS.

Using a secure proxy

If you would prefer that the Posit Connect process not have access to your TLS/SSL certificates, you may wish to configure a proxy to handle HTTPS requests. To accomplish this:

  • Ensure that your Server.Address is set to the proxy address and uses the https scheme.

  • Set HTTP.ForceSecure to true, which sets the Secure flag on all cookies.

  • Set HTTP.NoWarning to true to suppress the warning regarding running Posit Connect over an unsecured connection, because the connection between the client and the proxy is secured.

  • If necessary, enable the HTTPRedirect.Listen option to redirect proxied plain HTTP connections to HTTPS.

Note

Because the connection between the proxy and Posit Connect is not secured in this case, please ensure that the proxy and Posit Connect are connecting on a trusted network where an adversary would not be able to capture plain text credentials. For example, many cloud providers allow isolating servers from the internet while permitting load balancers to access them. Please see your cloud provider’s documentation for more details.

Content sniffing

The Server.ContentTypeSniffing setting can be used to configure HTTP responses with the X-Content-Type-Options header. This header can protect your users from a certain class of malicious uploads.

When Server.ContentTypeSniffing is disabled (the default), the X-Content-Type-Options HTTP header is given the value of nosniff. This instructs browsers not to inspect the content in an attempt to identify its type.

When Server.ContentTypeSniffing is enabled, the X-Content-Type-Options HTTP header is not sent. Browsers are free to analyze the content to detect its type.

Content embedding

The X-Frame-Options HTTP header is used to control what content can be embedded inside other content in a web browser. The relevant attack is commonly referred to as a clickjack attack and involves having your users interact with a sensitive service without their knowledge.

For the purposes of the X-Frame-Options header, Posit Connect distinguishes between “dashboard” and “user” content. The dashboard is any of the internal services or assets that are shipped with Posit Connect. User content is anything uploaded by a user (reports, applications, APIs, etc.)

Server.FrameOptionsContent configures the X-Frame-Options header value for user-uploaded content. By default it is NONE, meaning that the header is not set. This allows user-provided content to be embedded in iframes from any location. If you do not intend for others to embed user content on their sites, you can set this to a value of SAMEORIGIN to ensure that only sites on the same server can embed your users’ content. The Posit Connect dashboard itself uses iframes to present user content in the dashboard, so it is not recommended to set this option to DENY.

Server.FrameOptionsDashboard configures the X-Frame-Options header value for internal services and assets provided with Posit Connect and defaults to a value of DENY. This means that other sites can not embed the Posit Connect dashboard. This setting is more secure in that it protects against clickjacking attacks against the Connect dashboard, but if you plan to embed the dashboard elsewhere you may need to tune this setting.

Note

Some advertised values for this header are not supported across all browsers. Posit Connect does not restrict the values of these headers.

Authenticating embedded content

Connect content can be embedded into other websites via iframe. Connect’s access controls still govern embedded content, and users may need to authenticate if they are not already logged into Connect. In order for this to occur smoothly, both Connect and the embedded content should be configured for redirects back to the original site:

  1. Server.TrustedRedirect supplies Connect with a list of domains that it is allowed to redirect to after a successful auth attempt. By default, this is empty, meaning no external domains are trusted. You can use this setting multiple times as in the following example:
; /etc/rstudio-connect/rstudio-connect.gcfg
[Server]
TrustedRedirect = "https://parent-site.com"
TrustedRedirect = "https://another-site.com"
  1. Any embedded content must include the full redirect URL as a query parameter in the iframe source, using the framesource param. For example:
<iframe src="https://connect-site.com/app?framesource=https://parent-site.com/connectStuff">

This gives the authentication mechanism the information needed to return to the initial site after completion.

SameSite cookies

Posit Connect returns cookies with the attribute SameSite=None by default. This allows content hosted by Connect to be displayed embedded in iframes without additional options. With SameSite=None, each cookie emitted by Connect has a secondary cookie with -legacy suffix in its name and without the SameSite attribute. This second cookie is needed for additional compatibility with some browsers (i.e., Safari 12).

Note

If you don’t intend to embed content hosted by Connect in an iframe and your organization requires a more secure cookie setup, you can configure the Server.SameSite option with the Lax value as in the example below:

[Server]
SameSite = "Lax"

Custom headers

If you need to include additional HTTP headers that are not covered by any of the above features, you can include your own custom headers on all responses from Posit Connect using the Server.CustomHeader setting.

This feature can be used to accommodate various other security practices that are not explicitly available as options elsewhere in Connect. For instance, X-XSS-Protection, Content Security Policy (CSP), HTTP Public Key Pinning (HPKP), and Cross-origin Resource Sharing (CORS) could all be configured using custom headers.

Note

Custom headers are added to the HTTP response early during request processing. Values may later be overwritten or modified by other header settings. This includes both the security preferences described earlier in this chapter and other headers used internally by Posit Connect or by application or API frameworks such as Flask, Plumber, or Shiny. You should not depend on a custom header that conflicts with a header already in use by Posit Connect.

The Server.CustomHeader takes a value of the header name and its value separated by a colon. Whitespace surrounding the header name and its value are trimmed. You can use this setting multiple times as in the following example:

; /etc/rstudio-connect/rstudio-connect.gcfg
[Server]
CustomHeader = "HeaderA: some value"
CustomHeader = "HeaderB: another value"

Content Security Policy

A Content Security Policy (CSP) is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks resulting from execution of malicious content in the trusted web page context. It is a declarative policy that allows server administrators to inform the client about the sources from which the application expects to load resources.

Connect allows an admin to set a CSP by including a CustomHeader value in the server configuration file.

With the following CSP directive, Connect loads and allows user interaction.

[Server]
CustomHeader = "Content-Security-Policy: script-src 'self'"

However, because Connect hosts user-generated content provided by multiple frameworks, the CSP directive above will not work for all content. Connect provides a list of Jump Start Examples that describe how to publish a variety of different content types with Connect. For each content type provided in the Jump Start Examples, the following CSP directives allow each type of content to load and allow user interaction. Replace the recommended <CSP Value> in the CustomHeader directive with the value provided in the table below.

[Server]
CustomHeader = "Content-Security-Policy: <CSP Value>"
Content Type <CSP Value>
Bokeh App script-src 'self' 'unsafe-inline'
Jupyter Notebook script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdnjs.cloudflare.com
Parameterized R Markdown Document script-src 'self' 'unsafe-inline' data: https://mathjax.rstudio.com
Pin script-src 'self' 'unsafe-inline'
Plumber API script-src 'self' 'unsafe-inline'
Python API script-src 'self' 'unsafe-inline'
Python FastAPI script-src 'self' 'unsafe-inline'
Python Shiny App script-src 'self' 'unsafe-inline' 'unsafe-eval'
Quarto Content script-src 'self' 'unsafe-inline'
R Markdown Document script-src 'self' 'unsafe-inline' data: https://mathjax.rstudio.com
Shiny App script-src 'self' 'unsafe-inline' 'unsafe-eval'
Streamlit App script-src 'self' 'unsafe-inline' 'unsafe-eval'
Vetiver API script-src 'self' 'unsafe-inline'
Voilà Dashboard script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdnjs.cloudflare.com https://unpkg.com

The use of 'unsafe-inline' can be replaced with a hash value to tightly restrict the sources of scripts that can be loaded. Here is an example of using a hash value in the CSP directive instead of unsafe-inline:

[Server]
CustomHeader = "Content-Security-Policy: script-src 'self' 'sha256-gPjlli1HEdLlR0AZTY971/wQVOdSkl9mEinLnxrPpJw='"

However, because some frameworks generate scripts dynamically, the use of hashes can lead to a CSP directive that is not sustainable because of the frequently changing hashes. Additionally, if future upgrades of these frameworks change the scripts they use, new hashes will need to be added.

If you plan to host multiple content types on your Connect server, you should modify the CSP to include all of the CSP requirements for each expected content type. For example, if you expected to host both Jupyter Notebooks and R Markdown documents, you would set the CSP directive as follows:

CustomHeader = "Content-Security-Policy: `script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdnjs.cloudflare.com data: https://mathjax.rstudio.com`"

More information about Content-Security-Policy can be found at:

CSRF cookies

Cross-Site Request Forgery (often abbreviated as CSRF or XSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they are currently authenticated.

Note

How does Connect mitigate CSRF attacks?

Posit Connect uses a common mitigation strategy referred to as “Cookie-to-header” token validation.

Example of Posit Connect XSRF Cookie usage.

In order to mitigate CSRF attacks, upon an initial user session [1], the Connect server creates a cookie (RSC-XSRF) [2] containing a cryptographically secure, random token. JavaScript operating on the client side reads the value from this secure cookie and copies it into a custom HTTP header (X-Rsc-Xsrf) [3] sent with each transactional request. The server validates the presence and integrity of the token by comparing the request header with the cookie. [4] Attacker cannot perform the CSRF attack without the header which is made unavailable by TLS.

Important

The RSC-XSRF cookie cannot be set as “http-only” as it is required that Javascript is able to read the cookie value in order to set the request header.

Not setting “http-only” is not specific to Connect, but is a universal requirement for using “cookie-to-header” mitigation. This technique is implemented by many modern frameworks, such as Django and Angular.

Application environment variables

User-specified environment variables for applications are encrypted on-disk and in-memory. They are decrypted only when a process is about to be started.