In a previous article, we began talking about upcoming changes to Sugar's enforcement of a Content Security Policy. Well... it's here! In Sugar 11.0, we have introduced the Content Security Policy Admin module. This module will allow administrators to add domains to the CSP whitelist. Currently, the module has a single text field where you can place the value of the default-src
CSP directive.
Note that this directive is the highest level directive in CSPs. By setting the default-src
, you are also setting the following directives:
- child-src - defines the valid sources for web workers and nested browsing contexts like iframes
- connect-src - defines valid sources for fetch, XMLHttpRequest, WebSocket and EventSource connections
- font-src - defines valid sources for fonts to be loaded
- img-src - defines valid sources for images to be loaded
- media-src - defines valid sources for audio and video elements
- object-src - defines valid sources for object, embed and applet elements
- script-src - defines valid sources for JavaScript
- style-src - defines valid sources for stylesheets
Out of the box, the CSP will be:
default-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.pendo.io *.sugarcrm.com *.salesfusion.com *.salesfusion360.com *.sugarapps.com *.sugarapps.eu; img-src data: http: https:; object-src 'self'
Note that we already have an exception to the img-src
directive to allow ALL images. The current value is img-src data: http: https:;
. This piece of the CSP will allow all images from either the http or https protocol. At this time, the img-src
directive cannot be changed.
Whatever changes you do make in the admin module will be appended (or prepended) to the existing default-src
declaration. You can see that 'self'
is already defined in the directive. If you happen to add that in the admin module, nothing bad will happen - the resulting CSP will only have 'self'
listed once. This is also true for any domains that are already in the list (adding *.sugarcrm.com in the admin module will not result in multiple declarations).
Testing your CSP
While playing with this new feature, I found it helpful to view my application instance's CSP as I made changes. To start, I found the CSP that is used on our instance prior to any changes being made in the admin module. Then, as I made my adjustments, I would look to see how the policy had changed. This is only showing me what the policy is - not what effect the changes would have on resources being served up in the app. For that, I went manual - I simply looked over my site to see if anything was blocked.
There are a few viable methods for viewing a site's Content Security Policy. I employed 2 of the techniques. First, I went to https://gf.dev/csp-test where I simply entered the site URL and viewed the results. Pretty nice. BUT I like to work locally so this site wasn't going to do work for me without a bit of extra effort. That's when I switched to technique number 2 - Chrome's DevTools.
Hopefully, as developers, you are familiar with the browser developer's toolset. Here's a quick walkthrough of how to view your CSP (and other headers) from the Chrome DevTools Network tab.
- Begin by navigating to your Sugar instance and launching the Chrome DevTools (I usually just right-click on the page anywhere and choose the "Inspect" option).
- Next, switch to the Network tab of the DevTools window.
- Ensure that no filters are set OR (this is likely better) select the "Doc" filter. What we are looking for is the network information about the current document - the entire page
- Now that we are looking at the Network data and have our filters set properly, we need to refresh the page. This way we can see all of the headers etc for the page load
- In the resources list, you should see an item with status 200 and Type of "Document". It will likely use the domain as the name for this item in the list. Click on the item to view its details.
- In the resulting view, be sure that the "Headers" tab is active. Now, scroll down a bit to the "Response Headers" section where you should be able to find an entry for "Content-Security-Policy". That's it! This is your site's current CSP.
Setting your CSP
Now that we have covered the basics of what a CSP is and how to view yours, let's look at what we can do with the new admin module.
We have very few options in the new CSP admin module - actually just one for now. But, that's good! The new module is extremely simple. In that single field, you simply enter the domains that you would like to whitelist within Sugar. The domains should be separated by a space and wildcards are acceptable.
What if I wanted to add an iframe to a dashlet that displays content from https://zombo.com?The first part is the same as before - create the new "Web Page" dashlet with https://zombo.com/ as the URL. Previously, this would be all that was needed to display the content of the external site in our Sugar Dashboard. Now that we are enforcing Content Security Policies, your dashlet is going to appear to be broken and display a bold error message.
This is where we add our new step of white-listing the domain of our site. So, we open the new Content Security Policy admin module and add our domain to the CSP list.
As you can see in the screenshot, I added zombo.com to the Trusted Domains list. Once I hit save, the page will return to the Admin screen as expected but it will then also refresh the page. Why? Because the new policy needs to be loaded into the current session. This means that other active users are not going to see your changes yet. We explored options for auto-refreshing users' pages, but that's just way to disruptive. For now, users will not see changes from an update to the CSP without refreshing their current session. It will be the Administrator's responsibility to communicate to their users accordingly.
This two-step process (adding the iframe and the whitelist entry) is pretty straight-forward but can clearly cause some issues. If you add the iframe first and then update the CSP, for example, some users may see the broken dashlet until you add the domain to the whitelist. OH! And what about an MLP? You create a Module Loadable Package that adds a new iframe dashlet. That means uploading and installing the package and then remembering to update the CSP. Well, we thought of that one!
Other ways to update your CSP
For this update, we have added a new MLP manifest parameter for the CSP value. This parameter takes a space-delimited string of domains - just like the admin module. Setting the value of the default-src via MLP is an append operation. The values you put into the csp parameter of your manifest will be added to the CSP list in the admin module. Note that uninstall DOES NOT remove a value. Which makes sense because what if an admin put the same domain in for a different reason? So, remember to update the CSP after uninstalling an MLP with a csp parameter. Here is a sample assignment that will add 2 domains (and their subdomains) to the CSP:
'csp' => ['default-src' => '*.mashable.com *.usa.gov']
Enabling or disabling the CSP entirely is also possible - though not recommended. Adding the disable_CSP
config option in config_override.php
will allow you to turn CSP enforcement on or off.
$sugar_config['disable_CSP'] = true;
Finally, we have new API endpoints specifically for updating the CSP - /Administration/csp
. There is a POST
and GET
for this path. The GET
simply returns the value that you would see in the admin module. POST
will change that value. Each time you post, you are wiping out the previous policy and replacing it with yours - BUT ONLY THE CUSTOM VALUES. This is going to work the same as it does in the admin module. Any values you add to this field will be appended (or prepended) to the existing Content Security Policy. Any changes via API will also require a refresh for any active users to see the changes. Note the POST
call requires a csp_default_src
parameter. It is that parameter that you will set to the desired CSP string.
There's a lot of information in this post. Hopefully, however, you can now see that the process will be pretty simple. You add domains to the CSP field in the new admin module. Then your Sugar instance will allow content from those domains. Remember, if you are confused about CSP you can refer to the previous article or hit up Google. There are a ton of resources around this topic.