[TikiWiki-commits] [Git][tikiwiki/tiki][27.x] [BP][FIX] Implement centralized security headers management
"Rodriguez Nyiringabo \(@rodriguezny\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <6a22df1290c38_38194600483d1@gitlab-sidekiq-low-urgency-cpu-bound-v2-679d75d87c-nnt68.mail> |
Rodriguez Nyiringabo pushed to branch 27.x at Tiki Wiki CMS Groupware / Tiki
Commits:
b34f1d52 by Rodriguez Nyiringabo at 2026-06-05T14:30:41+00:00
[BP][FIX] Implement centralized security headers management
---
* [BP][FIX] Implement centralized security headers management
---
* [BP][FIX] Implement centralized security headers management
---
* [FIX] Headelib: Rename method `add_security_headers` to `addSecurityHeaders` for consistency.
---
* [FIX] Headelib: Rename method addSecurityHeaders` to `add_security_headers` for consistency.
See merge request tikiwiki/tiki!10445
* [FIX] Implement centralized security headers management
---
* [FIX] Implement centralized security headers management
See merge request tikiwiki/tiki!10437
See merge request tikiwiki/tiki!10444
See merge request tikiwiki/tiki!10446
See merge request tikiwiki/tiki!10447
- - - - -
3 changed files:
- lib/headerlib.php
- lib/init/smarty.php
- tiki-login.php
Changes:
=====================================
lib/headerlib.php
=====================================
@@ -220,6 +220,208 @@ class HeaderLib
$this->title = urlencode($string);
}
+ /**
+ * Add security headers. By default these headers are not sent.
+ * To change go to admin > security > site access
+ */
+ public function addSecurityHeaders()
+ {
+ global $prefs;
+
+ if (! headers_sent()) {
+ if (! isset($prefs['http_header_frame_options'])) {
+ $frame = false;
+ } else {
+ $frame = $prefs['http_header_frame_options'];
+ }
+ if (! isset($prefs['http_header_xss_protection'])) {
+ $xss = false; // prevent smarty E_NOTICE
+ } else {
+ $xss = $prefs['http_header_xss_protection'];
+ }
+
+ if (! isset($prefs['http_header_content_type_options'])) {
+ $content_type_options = false; // prevent smarty E_NOTICE
+ } else {
+ $content_type_options = $prefs['http_header_content_type_options'];
+ }
+ if (! isset($prefs['http_header_access_control_allow_credentials'])) {
+ $access_control_allow_credentials = false;
+ } else {
+ $access_control_allow_credentials = $prefs['http_header_access_control_allow_credentials'];
+ }
+ if (! isset($prefs['http_header_access_control_allow_methods'])) {
+ $access_control_allow_methods = false;
+ } else {
+ $access_control_allow_methods = $prefs['http_header_access_control_allow_methods'];
+ }
+ if (! isset($prefs['http_header_access_control_allow_headers'])) {
+ $access_control_allow_headers = false;
+ } else {
+ $access_control_allow_headers = $prefs['http_header_access_control_allow_headers'];
+ }
+ if (! isset($prefs['http_header_cross_origin_embedder_policy'])) {
+ $cross_origin_embedder_policy = false;
+ } else {
+ $cross_origin_embedder_policy = $prefs['http_header_cross_origin_embedder_policy'];
+ }
+ if (! isset($prefs['http_header_cross_origin_resource_policy'])) {
+ $cross_origin_resource_policy = false;
+ } else {
+ $cross_origin_resource_policy = $prefs['http_header_cross_origin_resource_policy'];
+ }
+ if (! isset($prefs['http_header_cross_origin_opener_policy'])) {
+ $cross_origin_opener_policy = false;
+ } else {
+ $cross_origin_opener_policy = $prefs['http_header_cross_origin_opener_policy'];
+ }
+ if (! isset($prefs['http_header_content_security_policy'])) {
+ $content_security_policy = false; // prevent smarty E_NOTICE
+ } else {
+ $content_security_policy = $prefs['http_header_content_security_policy'];
+ }
+
+ if (! isset($prefs['http_header_strict_transport_security'])) {
+ $strict_transport_security = false; // prevent smarty E_NOTICE
+ } else {
+ $strict_transport_security = $prefs['http_header_strict_transport_security'];
+ }
+
+ if (! isset($prefs['http_header_public_key_pins'])) {
+ $public_key_pins = false; // prevent smarty E_NOTICE
+ } else {
+ $public_key_pins = $prefs['http_header_public_key_pins'];
+ }
+
+ if (! isset($prefs['http_header_referrer_policy'])) {
+ $referrer_policy = false;
+ } else {
+ $referrer_policy = $prefs['http_header_referrer_policy'];
+ }
+
+ if (! isset($prefs['http_header_permitted_cross_domain_policies'])) {
+ $permitted_cross_domain_policies = false;
+ } else {
+ $permitted_cross_domain_policies = $prefs['http_header_permitted_cross_domain_policies'];
+ }
+
+ if ($frame == 'y') {
+ $header_value = $prefs['http_header_frame_options_value'];
+ header('X-Frame-Options: ' . $header_value);
+ }
+ if ($xss == 'y') {
+ $header_value = $prefs['http_header_xss_protection_value'];
+ header('X-XSS-Protection: ' . $header_value);
+ }
+ if ($content_type_options == 'y') {
+ header('X-Content-Type-Options: nosniff');
+ }
+ if ($access_control_allow_credentials === 'y') {
+ header('Access-Control-Allow-Credentials: true');
+ }
+ if ($access_control_allow_methods === 'y') {
+ $header_value = trim($prefs['http_header_access_control_allow_methods_value']);
+ if ($access_control_allow_credentials === 'y' && $header_value === '*') {
+ Feedback::error(tr("CORS configuration error: Wildcard (*) is not allowed for Access-Control-Allow-Methods when http_header_access_control_allow_credential is enabled"));
+ header_remove('Access-Control-Allow-Methods');
+ } else {
+ header('Access-Control-Allow-Methods: ' . $header_value);
+ }
+ }
+ if ($access_control_allow_headers === 'y') {
+ $headers_value = trim($prefs['http_header_access_control_allow_headers_value']);
+ if ($access_control_allow_credentials === 'y' && $headers_value === '*') {
+ Feedback::error(tr("CORS configuration error: Wildcard (*) is not allowed for Access-Control-Allow-Headers when Access-Control-Allow-Credentials is enabled."));
+ header_remove('Access-Control-Allow-Headers');
+ } else {
+ header('Access-Control-Allow-Headers: ' . $headers_value);
+ }
+ }
+ if ($cross_origin_embedder_policy === 'y') {
+ switch (trim($prefs['http_header_cross_origin_embedder_policy_value'])) {
+ case 'require-corp':
+ header('Cross-Origin-Embedder-Policy: require-corp');
+ break;
+ case 'credentialless':
+ header('Cross-Origin-Embedder-Policy: credentialless');
+ break;
+ case 'unsafe-none':
+ header('Cross-Origin-Embedder-Policy: unsafe-none');
+ break;
+ default:
+ break;
+ }
+ }
+ if ($cross_origin_resource_policy === 'y') {
+ switch (trim($prefs['http_header_cross_origin_resource_policy_value'])) {
+ case 'same-origin':
+ header('Cross-Origin-Resource-Policy: same-origin');
+ break;
+ case 'same-site':
+ header('Cross-Origin-Resource-Policy: same-site');
+ break;
+ case 'cross-origin':
+ header('Cross-Origin-Resource-Policy: cross-origin');
+ break;
+ default:
+ break;
+ }
+ }
+ if ($cross_origin_opener_policy === 'y') {
+ switch (trim($prefs['http_header_cross_origin_opener_policy_value'])) {
+ case 'same-origin':
+ header('Cross-Origin-Opener-Policy: same-origin');
+ break;
+ case 'same-origin-allow-popups':
+ header('Cross-Origin-Opener-Policy: same-origin-allow-popups');
+ break;
+ case 'same-origin-plus-coep':
+ header('Cross-Origin-Opener-Policy: same-origin-plus-coep');
+ break;
+ case 'unsafe-none':
+ header('Cross-Origin-Opener-Policy: unsafe-none');
+ break;
+ default:
+ break;
+ }
+ }
+ if ($content_security_policy == 'y') {
+ $header_value = trim($prefs['http_header_content_security_policy_value']);
+ if ($header_value !== '') {
+ header('Content-Security-Policy: ' . $header_value);
+ }
+ }
+
+ if ($strict_transport_security == 'y') {
+ $header_value = trim($prefs['http_header_strict_transport_security_value']);
+ if ($header_value !== '') {
+ header('Strict-Transport-Security: ' . $header_value);
+ }
+ }
+
+ if ($public_key_pins == 'y') {
+ $header_value = trim($prefs['http_header_public_key_pins_value']);
+ if ($header_value !== '') {
+ header('Public-Key-Pins: ' . $header_value);
+ }
+ }
+
+ if ($referrer_policy === 'y') {
+ $header_value = trim($prefs['http_header_referrer_policy_value']);
+ if ($header_value !== '') {
+ header('Referrer-Policy: ' . $header_value);
+ }
+ }
+
+ if ($permitted_cross_domain_policies === 'y') {
+ $header_value = trim($prefs['http_header_permitted_cross_domain_policies_value']);
+ if ($header_value !== '') {
+ header('X-Permitted-Cross-Domain-Policies: ' . $header_value);
+ }
+ }
+ }
+ }
+
/**
* Add a js url from this tiki instance to top priority load order.
* These are usually dynamic created js scripts for configuration, module settings etc.
=====================================
lib/init/smarty.php
=====================================
@@ -384,6 +384,7 @@ class Smarty_Tiki extends \Smarty\Smarty
): void {
global $prefs;
+ $headerlib = TikiLib::lib('header');
$this->activateCustomErrorHandler();
if (! empty($prefs['feature_htmlpurifier_output']) and $prefs['feature_htmlpurifier_output'] == 'y') {
@@ -397,173 +398,7 @@ class Smarty_Tiki extends \Smarty\Smarty
}
}
- /**
- * Add security headers. By default there headers are not sent.
- * To change go to admin > security > site access
- */
- if (! headers_sent()) {
- if (! isset($prefs['http_header_frame_options'])) {
- $frame = false;
- } else {
- $frame = $prefs['http_header_frame_options'];
- }
- if (! isset($prefs['http_header_xss_protection'])) {
- $xss = false; // prevent smarty E_NOTICE
- } else {
- $xss = $prefs['http_header_xss_protection'];
- }
-
- if (! isset($prefs['http_header_content_type_options'])) {
- $content_type_options = false; // prevent smarty E_NOTICE
- } else {
- $content_type_options = $prefs['http_header_content_type_options'];
- }
-
- if (! isset($prefs['http_header_content_security_policy'])) {
- $content_security_policy = false; // prevent smarty E_NOTICE
- } else {
- $content_security_policy = $prefs['http_header_content_security_policy'];
- }
-
- if (! isset($prefs['http_header_strict_transport_security'])) {
- $strict_transport_security = false; // prevent smarty E_NOTICE
- } else {
- $strict_transport_security = $prefs['http_header_strict_transport_security'];
- }
-
- if (! isset($prefs['http_header_public_key_pins'])) {
- $public_key_pins = false; // prevent smarty E_NOTICE
- } else {
- $public_key_pins = $prefs['http_header_public_key_pins'];
- }
-
- if (! isset($prefs['http_header_referrer_policy'])) {
- $referrer_policy = false;
- } else {
- $referrer_policy = $prefs['http_header_referrer_policy'];
- }
-
- if (! isset($prefs['http_header_permitted_cross_domain_policies'])) {
- $permitted_cross_domain_policies = false;
- } else {
- $permitted_cross_domain_policies = $prefs['http_header_permitted_cross_domain_policies'];
- }
-
- if ($frame == 'y') {
- $header_value = $prefs['http_header_frame_options_value'];
- header('X-Frame-Options: ' . $header_value);
- }
- if ($xss == 'y') {
- $header_value = $prefs['http_header_xss_protection_value'];
- header('X-XSS-Protection: ' . $header_value);
- }
- if ($content_type_options == 'y') {
- header('X-Content-Type-Options: nosniff');
- }
- if ($access_control_allow_credentials === 'y') {
- header('Access-Control-Allow-Credentials: true');
- }
- if ($access_control_allow_methods === 'y') {
- $header_value = trim($prefs['http_header_access_control_allow_methods_value']);
- if ($access_control_allow_credentials === 'y' && $header_value === '*') {
- Feedback::error(tr("CORS configuration error: Wildcard (*) is not allowed for Access-Control-Allow-Methods when http_header_access_control_allow_credential is enabled"));
- header_remove('Access-Control-Allow-Methods');
- } else {
- header('Access-Control-Allow-Methods: ' . $header_value);
- }
- }
- if ($access_control_allow_headers === 'y') {
- $headers_value = trim($prefs['http_header_access_control_allow_headers_value']);
- if ($access_control_allow_credentials === 'y' && $headers_value === '*') {
- Feedback::error(tr("CORS configuration error: Wildcard (*) is not allowed for Access-Control-Allow-Headers when Access-Control-Allow-Credentials is enabled."));
- header_remove('Access-Control-Allow-Headers');
- } else {
- header('Access-Control-Allow-Headers: ' . $headers_value);
- }
- }
- if ($cross_origin_embedder_policy === 'y') {
- switch (trim($prefs['http_header_cross_origin_embedder_policy_value'])) {
- case 'require-corp':
- header('Cross-Origin-Embedder-Policy: require-corp');
- break;
- case 'credentialless':
- header('Cross-Origin-Embedder-Policy: credentialless');
- break;
- case 'unsafe-none':
- header('Cross-Origin-Embedder-Policy: unsafe-none');
- break;
- default:
- break;
- }
- }
- if ($cross_origin_resource_policy === 'y') {
- switch (trim($prefs['http_header_cross_origin_resource_policy_value'])) {
- case 'same-origin':
- header('Cross-Origin-Resource-Policy: same-origin');
- break;
- case 'same-site':
- header('Cross-Origin-Resource-Policy: same-site');
- break;
- case 'cross-origin':
- header('Cross-Origin-Resource-Policy: cross-origin');
- break;
- default:
- break;
- }
- }
- if ($cross_origin_opener_policy === 'y') {
- switch (trim($prefs['http_header_cross_origin_opener_policy_value'])) {
- case 'same-origin':
- header('Cross-Origin-Opener-Policy: same-origin');
- break;
- case 'same-origin-allow-popups':
- header('Cross-Origin-Opener-Policy: same-origin-allow-popups');
- break;
- case 'same-origin-plus-coep':
- header('Cross-Origin-Opener-Policy: same-origin-plus-coep');
- break;
- case 'unsafe-none':
- header('Cross-Origin-Opener-Policy: unsafe-none');
- break;
- default:
- break;
- }
- }
- if ($content_security_policy == 'y') {
- $header_value = trim($prefs['http_header_content_security_policy_value']);
- if ($header_value !== '') {
- header('Content-Security-Policy: ' . $header_value);
- }
- }
-
- if ($strict_transport_security == 'y') {
- $header_value = trim($prefs['http_header_strict_transport_security_value']);
- if ($header_value !== '') {
- header('Strict-Transport-Security: ' . $header_value);
- }
- }
-
- if ($public_key_pins == 'y') {
- $header_value = trim($prefs['http_header_public_key_pins_value']);
- if ($header_value !== '') {
- header('Public-Key-Pins: ' . $header_value);
- }
- }
-
- if ($referrer_policy === 'y') {
- $header_value = trim($prefs['http_header_referrer_policy_value']);
- if ($header_value !== '') {
- header('Referrer-Policy: ' . $header_value);
- }
- }
-
- if ($permitted_cross_domain_policies === 'y') {
- $header_value = trim($prefs['http_header_permitted_cross_domain_policies_value']);
- if ($header_value !== '') {
- header('X-Permitted-Cross-Domain-Policies: ' . $header_value);
- }
- }
- }
+ $headerlib->addSecurityHeaders();
/**
* By default, display is used with text/html content in UTF-8 encoding
=====================================
tiki-login.php
=====================================
@@ -27,6 +27,9 @@ if (empty($_POST['user'])) {
require_once('tiki-setup.php');
global $prefs;
+$headerlib = TikiLib::lib('header');
+$headerlib->addSecurityHeaders();
+
// Refresh not logged in since 30 days user's accounts list
$userlib = TikiLib::lib('user');
$userlib->refresh_locked_users_list();
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/b34f1d52f2e3adf87ee0beb9570dcc13ee862d36
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/b34f1d52f2e3adf87ee0beb9570dcc13ee862d36
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs