diff --git a/README.md b/README.md index 4b32920..bbc378e 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ If necessary, you may install it manually by downloading a Zip archive from [Git - REST API links - Oembed links - Windows Live Writer manifest links +- Set sensible security headers ### Capabilities @@ -95,6 +96,7 @@ The following filters can be used to override the default behavior of certain fe - `orbit_enable_rest_api_user_endpoints`: Enable or disable REST API user endpoints. Default `false` (disabled). - `orbit_enable_xmlrpc`: Enable or disable XML-RPC functionality. Default `false` (disabled). - `orbit_enable_expose_wordpress_version`: Show or hide the WordPress version in the site's frontend markup. Default `false` (hidden). +- `orbit_default_security_headers`: Set an array of security headers. ### Capabilities diff --git a/composer.lock b/composer.lock index 90d4af2..2fb36cb 100644 --- a/composer.lock +++ b/composer.lock @@ -168,16 +168,16 @@ }, { "name": "symfony/css-selector", - "version": "v7.3.0", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + "reference": "84321188c4754e64273b46b406081ad9b18e8614" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", - "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/84321188c4754e64273b46b406081ad9b18e8614", + "reference": "84321188c4754e64273b46b406081ad9b18e8614", "shasum": "" }, "require": { @@ -213,7 +213,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v7.3.0" + "source": "https://github.com/symfony/css-selector/tree/v7.3.6" }, "funding": [ { @@ -224,12 +224,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-25T14:21:43+00:00" + "time": "2025-10-29T17:24:25+00:00" }, { "name": "thecodingmachine/safe", @@ -912,27 +916,27 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.4.2", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e" + "reference": "b598aa890815b8df16363271b659d73280129101" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e", - "reference": "8e89a01c7b8fed84a12a2a7f5a23a44cdbe4f62e", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", + "reference": "b598aa890815b8df16363271b659d73280129101", "shasum": "" }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.1.2", - "squizlabs/php_codesniffer": "^3.13.4 || ^4.0" + "phpcsstandards/phpcsutils": "^1.2.0", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "phpcsstandards/phpcsdevtools": "^1.2.1", "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, @@ -990,32 +994,32 @@ "type": "thanks_dev" } ], - "time": "2025-10-28T17:00:02+00:00" + "time": "2025-11-12T23:06:57+00:00" }, { "name": "phpcsstandards/phpcsutils", - "version": "1.1.3", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9" + "reference": "fa82d14ad1c1713224a52c66c78478145fe454ba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9", - "reference": "8b8e17615d04f2fc2cd46fc1d2fd888fa21b3cf9", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/fa82d14ad1c1713224a52c66c78478145fe454ba", + "reference": "fa82d14ad1c1713224a52c66c78478145fe454ba", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.13.3 || ^4.0" + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "ext-filter": "*", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" }, "type": "phpcodesniffer-standard", @@ -1083,7 +1087,7 @@ "type": "thanks_dev" } ], - "time": "2025-10-16T16:39:32+00:00" + "time": "2025-11-11T00:17:56+00:00" }, { "name": "psr/container", @@ -1140,16 +1144,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.4", + "version": "3.13.5", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119" + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ad545ea9c1b7d270ce0fc9cbfb884161cd706119", - "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", + "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", "shasum": "" }, "require": { @@ -1166,11 +1170,6 @@ "bin/phpcs" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -1220,7 +1219,7 @@ "type": "thanks_dev" } ], - "time": "2025-09-05T05:47:09+00:00" + "time": "2025-11-04T16:30:35+00:00" }, { "name": "symfony/console", @@ -1952,16 +1951,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -2015,7 +2014,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -2026,12 +2025,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", diff --git a/includes/classes/Plugin.php b/includes/classes/Plugin.php index e66ae16..49ce55a 100644 --- a/includes/classes/Plugin.php +++ b/includes/classes/Plugin.php @@ -37,6 +37,7 @@ public function setup(): void { Performance\Fast404::instance()->setup(); Security\DisableAPI::instance()->setup(); Security\DisableXMLRPC::instance()->setup(); + Security\Headers::instance()->setup(); Security\HideAuthor::instance()->setup(); Security\HideVersion::instance()->setup(); Security\RemoveHeadLinks::instance()->setup(); diff --git a/includes/classes/Security/Headers.php b/includes/classes/Security/Headers.php new file mode 100644 index 0000000..0ce3940 --- /dev/null +++ b/includes/classes/Security/Headers.php @@ -0,0 +1,73 @@ + 'same-origin', + 'Cross-Origin-Resource-Policy' => 'same-origin', + + // Sensible privacy default + 'Referrer-Policy' => 'strict-origin-when-cross-origin', + + // Stops MIME sniffing + 'X-Content-Type-Options' => 'nosniff', + + // Prevent clickjacking inside iframes (legacy) + 'X-Frame-Options' => 'SAMEORIGIN', + + // Permissive CSP (websites should customise this, ideally) + 'Content-Security-Policy' => implode('; ', [ + "default-src 'self' https:", + "img-src 'self' https: data: blob:", + "script-src 'self' https: 'unsafe-inline' 'unsafe-eval'", + "style-src 'self' https: 'unsafe-inline'", + "frame-ancestors 'self'", + ]), + ]; + + // Only if SSL + if ( is_ssl() ) { + $default_security_headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'; + $default_security_headers['Content-Security-Policy'] .= '; upgrade-insecure-requests'; + } + + $security_headers = apply_filters( 'orbit_default_security_headers', $default_security_headers ); + + foreach ( $security_headers as $header => $value ) { + if ( ! empty( $value ) ) { + $headers[ $header ] = $value; + } + } + + return $headers; + } +} diff --git a/includes/lib/Symfony/Component/CssSelector/Parser/Token.php b/includes/lib/Symfony/Component/CssSelector/Parser/Token.php index 2855d4e..a36b68c 100644 --- a/includes/lib/Symfony/Component/CssSelector/Parser/Token.php +++ b/includes/lib/Symfony/Component/CssSelector/Parser/Token.php @@ -31,6 +31,9 @@ class Token public const TYPE_NUMBER = 'number'; public const TYPE_STRING = 'string'; + /** + * @param self::TYPE_*|null $type + */ public function __construct( private ?string $type, private ?string $value, @@ -38,7 +41,10 @@ public function __construct( ) { } - public function getType(): ?int + /** + * @return self::TYPE_*|null + */ + public function getType(): ?string { return $this->type; }