altis/browser-security

Browser security utilities for WordPress/Altis

Installs: 148 143

Dependents: 2

Suggesters: 0

Security: 0

Stars: 9

Watchers: 22

Forks: 3

Open Issues: 8

Type:wordpress-plugin

2.1.0 2023-05-08 13:18 UTC

This package is auto-updated.

Last update: 2024-10-24 15:16:51 UTC


README

Improve the browser security of your WordPress site.

Built for, and included with, Altis, the WordPress Digital Experience Platform for Enterprise.

Installation

You can use this plugin either directly as a submodule or as a Composer dependency.

# For submodule usage:
git submodule add https://github.com/humanmade/altis-browser-security.git wp-content/plugins/altis-browser-security

# For Composer usage:
composer require altis/browser-security

Configuration

If you are using this as part of the Altis DXP, configuration is handled via the configuration framework. Consult the Altis security module documentation.

As a standalone plugin, you can use the following constants to change the behaviour of this module:

  • ABS_AUTOMATIC_INTEGRITY (bool): True to enable automatic generation of integrity hashes, false to disable. (True by default.)
  • ABS_NOSNIFF_HEADER (bool): True to send X-Content-Type-Options: nosniff, false to disable. (True by default.)
  • ABS_FRAME_OPTIONS_HEADER (bool): True to send X-Frame-Options: SAMEORIGIN, false to disable. (True by default.)
  • ABS_XSS_PROTECTION_HEADER (bool): True to send X-XSS-Protection: 1; mode=block, false to disable. (True by default.)

Features

Subresource Integrity

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

These hashes will be automatically cached in the object cache, linked to the filename and version of the script or stylesheet.

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 Altis\Security\Browser;
wp_enqueue_script( 'my-handle', 'https://...' );
Browser\set_hash_for_script( 'my-handle', 'sha384-...' );

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

Content-Security-Policy

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

Out of the box, no policies are sent. CSP policies tend to be specific to sites, so no assumptions are made about what you may want.

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;
} );

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

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;
} );

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

Report-Only Policies

To send a Content-Security-Policy-Report-Only header, use the exact same process described above for the ordinary CSP policies with the alternative filter altis.security.browser.report_only_content_security_policies.

An external service must be used to ingest the reports from Report-Only policies. The external service will provide you with a reporting URL which you can use by adding a report-uri directive with the appropriate URL for processing reports.

As an example, you can add a reporting directive to your Report-Only policies by filtering the policies array:

add_filter( 'altis.security.browser.report_only_content_security_policies', function ( array $policies ) : array {
	$policies['report-uri'] = 'https://example.uriports.com/reports';
	return $policies;
} );

You can also modify individual directives for use in report-only policies in the same manner described above using the filters,

  • altis.security.browser.filter_report_only_policy_value.{ directive name }
  • altis.security.browser.filter_report_only_policy_value

Both normal and report-only policies may be used simultaneously.

Security Headers

This plugin automatically adds various 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.

Strict-Transport-Security

The Strict-Transport-Security header (sometimes called HSTS) is used to enforce HTTPS (TLS/SSL) connections when loading a site and can be used to enhance the site's security.

By default, Altis adds a Strict-Transport-Security header if your site is served over HTTPS, with the value set to max-age=86400 (one day). If you want to override this value (such as for longer durations, or to specify includeSubdomains), you can define the ABS_HSTS constant:

define( 'ABS_HSTS', 'max-age=31536000; includeSubDomains' );

To disable the automatic behaviour entirely, set the constant to false:

define( 'ABS_HSTS', false );

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 the ABS_NOSNIFF_HEADER constant:

define( 'ABS_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 the ABS_FRAME_OPTIONS_HEADER constant:

define( 'ABS_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 the ABS_XSS_PROTECTION_HEADER header:

define( 'ABS_XSS_PROTECTION_HEADER', false );

Restrict CORS origins

By default, WordPress will allow REST API requests from any Origin. This plugin adds a new filter altis.security.browser.rest_allow_origin to restrict CORS origins.

To completely disallow external requests, set the filter to false:

add_filter( 'altis.security.browser.rest_allow_origin', '__return_false' );

To allow specific origins only:

add_filter( 'altis.security.browser.rest_allow_origin', function ( $allow, $origin ) {

	$allowed_origins = [
		'https://www.example.com',
	];

	if ( in_array( $origin, $allowed_origins, true ) ) {
		return true;
	}

    return false;
}, 10, 2 );

To disallow all .local domains:

add_filter( 'altis.security.browser.rest_allow_origin', function ( $allow, $origin ) {
    if ( false !== strpos( $origin, '.local' ) ) {
        return false;
    }

    return $allow;
}, 10, 2 );

License

Altis Browser Security is licensed under the GPLv2 or later. Copyright 2019 Human Made and contributors.