Warning: Altis v8 is no longer supported.

Browser Security

Altis includes a framework to ensure frontend security in browsers. Out of the box, Altis sends basic security headers, but we recommend sending more specific headers where you can.

To set browser security settings, set values in your composer.json configuration under extra.altis.modules.security.browser:

{
	"extra": {
		"altis": {
			"modules": {
				"security": {
					"browser": {
						"automatic-integrity": true
					}
				}
			}
		}
	}
}

Note: In this document, we'll only show the browser configuration for brevity.

You can also disable browser security altogether by setting browser to false:

{
	"browser": false
}

Content-Security-Policy

Altis can automatically gather and send Content-Security-Policy policies for you.

Site-wide policy

Out of the box, only basic policies are sent:

  • base-uri 'self' is sent, which disables the ability to output <base> tags, ensuring links and assets cannot be hijacked
  • object-src 'none' is sent, which blocks <object>, <embed>, and <applet> tags entirely

(These are considered best practices for all sites, but can be overridden if needed.)

To change the default Content-Security-Policy, you can configure it in your composer.json under extra.altis.modules.security.browser.content-security-policy:

{
	"browser": {
		"content-security-policy": {
			"base-uri": [
				"self"
			],
			"object-src": [
				"none"
			]
		}
	}
}

Keys under content-security-policy should be a valid directive, and the value should be either a string or list of strings:

{
	"browser": {
		"content-security-policy": {
			"base-uri": [
				"self"
			],
			"object-src": [
				"none"
			],
			"font-src": [
				"https://fonts.gstatic.com",
				"https://cdnjs.cloudflare.com"
			],
			"script-src": [
				"https:",
				"unsafe-inline"
			]
		}
	}
}

Special directives ('self', 'unsafe-inline', 'unsafe-eval', 'none', 'strict-dynamic') do not need to be double-quoted.

To build Content-Security-Policy policies, we recommend using the Laboratory CSP toolkit extension for Firefox, and the CSP Evaluator tool.

Page-specific policies

For page-specific policies, you can add a filter to altis.security.browser.content_security_policies to set policies. This filter receives an array, where the keys are the policy directive names. Each item can either be a string or a list of directive value strings:

add_filter( 'altis.security.browser.content_security_policies', function ( array $policies ) : array {
	// Policies can be set as strings.
	$policies['object-src'] = 'none';
	$policies['base-uri'] = 'self';

	// Policies can also be set as arrays.
	$policies['font-src'] = [
		'https://fonts.gstatic.com',
		'https://cdnjs.cloudflare.com',
	];

	// Special directives (such as `unsafe-inline`) are handled for you.
	$policies['script-src'] = [
		'https:',
		'unsafe-inline',
	];

	return $policies;
} );

You can also modify individual directives if desired:

// You can filter specific keys via the filter name.
add_filter( 'altis.security.browser.filter_policy_value.font-src', function ( array $values ) : array {
	$values[] = 'https://fonts.gstatic.com';
	return $values;
} );

// A filter is also available with the directive name in a parameter.
add_filter( 'altis.security.browser.filter_policy_value', function ( array $values, string $name ) : array {
	if ( $name === 'font-src' ) {
		$values[] = 'https://cdnjs.cloudflare.com';
	}

	return $values;
} );

Subresource Integrity

Altis automatically adds subresource integrity hashes where possible. These are generated for any files on the same server; i.e. any plugin or theme assets.

For external assets, you can manually set the integrity hash. After enqueuing (or registering) your asset, use the set_hash_for_script() or set_hash_for_style() helpers:

// Setting hashes for scripts.
use function Altis\Security\Browser\set_hash_for_script;
wp_enqueue_script( 'my-handle', 'https://...' );
set_hash_for_script( 'my-handle', 'sha384-...' );

// Setting hashes for styles.
use function Altis\Security\Browser\set_hash_for_style;
wp_enqueue_style( 'my-handle', 'https://...' );
set_hash_for_style( 'my-handle', 'sha384-...' );

Automatically-generated hashes are automatically cached in the object cache, linked to the filename and version of the script or stylesheet.

You can disable the automatic generation of the integrity hashes if desired by setting browser.automatic-integrity to false:

{
	"browser": {
		"automatic-integrity": false
	}
}

Security Headers

Altis automatically adds various miscellaneous security headers by default. These follow best-practices for web security and aim to provide a sensible, secure default.

In some cases, you may want to adjust or disable these headers depending on the use cases of your site.

X-Content-Type-Options

By default, Altis adds a X-Content-Type-Options header with the value set to nosniff. This prevents browsers from attempting to guess the content type based on the content, and instead forces them to follow the type set in the Content-Type header.

This should generally always be sent, and your content type should always be set explicitly. If you need to disable it, set browser.nosniff-header to false:

{
	"browser": {
		"nosniff-header": false
	}
}

X-Frame-Options

By default, Altis adds a X-Frame-Options header with the value set to sameorigin. This prevents your site from being iframed into another site, which can prevent clickjacking attacks.

This should generally always be sent, but in some cases, you may want to allow specific sites to iframe your site, or allow any sites. To disable the automatic header, set browser.frame-options-header to false:

{
	"browser": {
		"frame-options-header": false
	}
}

You can then send your own headers as needed. We recommend hooking into the template_redirect hook to send these headers.

X-XSS-Protection

By default, Altis adds a X-XSS-Protection header with the value set to 1; mode=block. This prevents browsers from loading if they detect cross-site scripting (XSS) attacks.

This should generally always be sent. If you need to disable it, set browser.xss-protection-header to false:

{
	"browser": {
		"xss-protection-header": false
	}
}