diff --git a/classes/display/DisplayHandler.class.php b/classes/display/DisplayHandler.class.php index d7b2c0844..5e8e60b2d 100644 --- a/classes/display/DisplayHandler.class.php +++ b/classes/display/DisplayHandler.class.php @@ -115,6 +115,16 @@ class DisplayHandler extends Handler } } + // Print security-related headers. + if($header_value = config('security.x_frame_options')) + { + header('X-Frame-Options: ' . $header_value); + } + if($header_value = config('security.x_content_type_options')) + { + header('X-Content-Type-Options: ' . $header_value); + } + // flush output buffer while (ob_get_level()) { diff --git a/common/defaults/config.php b/common/defaults/config.php index b3173bf47..e786796ad 100644 --- a/common/defaults/config.php +++ b/common/defaults/config.php @@ -61,6 +61,7 @@ return array( 'use_keys' => false, 'use_ssl' => false, 'use_ssl_cookies' => false, + 'samesite' => 'Lax', 'domain' => null, 'path' => null, 'lifetime' => 0, @@ -126,6 +127,8 @@ return array( 'robot_user_agents' => array(), 'check_csrf_token' => false, 'nofollow' => false, + 'x_frame_options' => 'SAMEORIGIN', + 'x_content_type_options' => 'nosniff', ), 'mobile' => array( 'enabled' => true, diff --git a/modules/admin/controllers/systemconfig/Security.php b/modules/admin/controllers/systemconfig/Security.php index 7340d38ed..7c2dab6c4 100644 --- a/modules/admin/controllers/systemconfig/Security.php +++ b/modules/admin/controllers/systemconfig/Security.php @@ -38,6 +38,8 @@ class Security extends Base Context::set('use_cookies_ssl', Config::get('session.use_ssl_cookies')); Context::set('check_csrf_token', Config::get('security.check_csrf_token')); Context::set('use_nofollow', Config::get('security.nofollow')); + Context::set('x_frame_options', Config::get('security.x_frame_options')); + Context::set('x_content_type_options', Config::get('security.x_content_type_options')); $this->setTemplateFile('config_security'); } @@ -106,11 +108,22 @@ class Security extends Base } $site_module_info = Context::get('site_module_info'); - $vars->use_samesite = preg_replace('/[^a-zA-Z]/', '', $vars->use_samesite); + if (!in_array($vars->use_samesite ?? '', ['Strict', 'Lax', 'None', ''])) + { + $vars->use_samesite = ''; + } if ($vars->use_samesite === 'None' && ($vars->use_session_ssl !== 'Y' || $site_module_info->security !== 'always')) { $vars->use_samesite = ''; } + if (!in_array($vars->x_frame_options ?? '', ['DENY', 'SAMEORIGIN', ''])) + { + $vars->x_frame_options = ''; + } + if (!in_array($vars->x_content_type_options ?? '', ['nosniff', ''])) + { + $vars->x_content_type_options = ''; + } Config::set('admin.allow', array_values($allowed_ip)); Config::set('admin.deny', array_values($denied_ip)); @@ -120,6 +133,8 @@ class Security extends Base Config::set('session.use_ssl_cookies', $vars->use_cookies_ssl === 'Y'); Config::set('security.check_csrf_token', $vars->check_csrf_token === 'Y'); Config::set('security.nofollow', $vars->use_nofollow === 'Y'); + Config::set('security.x_frame_options', strtoupper($vars->x_frame_options)); + Config::set('security.x_content_type_options', strtolower($vars->x_content_type_options)); // Save if (!Config::save()) diff --git a/modules/admin/lang/en.php b/modules/admin/lang/en.php index 183af1c14..8311202da 100644 --- a/modules/admin/lang/en.php +++ b/modules/admin/lang/en.php @@ -168,6 +168,8 @@ $lang->about_robot_user_agents = 'This list defines the list of browser user-age $lang->use_samesite = 'SameSite attribute'; $lang->use_samesite_empty = 'Do not use'; $lang->about_use_samesite = 'Set the SameSite attribute for session cookies and session keys.
Lax is the recommended setting for most sites. You may need to use None if you are having difficulties integrating with external services such as payment gateways.
However, None is only valid when used with SSL-only sessions.'; +$lang->about_x_frame_options = 'Block loading this site in an iframe from another site. This helps prevent clickjacking attacks.
SameOrigin is recommended for most sites. Deny will make iframes stop working even on this site.
Do not use this setting if you have already enabled the X-Frame-Options header in your server configuration.'; +$lang->about_x_content_type_options = 'Prevent browser sniffing of MIME types of documents and attached files.
Do not use this setting if you have already enabled the X-Content-Type-Options header in your server configuration.'; $lang->use_session_keys = 'Use session security keys'; $lang->about_use_session_keys = 'Use additional security keys to guard against session theft. This setting is highly recommended if you don\'t use SSL-only sessions.
This setting may cause some users to become logged out.'; $lang->use_session_ssl = 'Use SSL-only session'; @@ -176,7 +178,7 @@ $lang->use_cookies_ssl = 'Use SSL-only cookies'; $lang->about_use_cookies_ssl = 'Force all cookies to be SSL-only.'; $lang->check_csrf_token = 'Use CSRF tokens'; $lang->about_check_csrf_token = 'Use CSRF tokens to validate requests. This is more secure but may break some functionality.
If not selected, Rhymix will use only the Referer header to defend against CSRF attacks.'; -$lang->use_nofollow = 'Use nofollow attribute'; +$lang->use_nofollow = 'Add nofollow attribute to Links'; $lang->about_use_nofollow = 'Add rel="nofollow" to all links submitted by users in order to reduce the effectiveness of spamming.
This does not apply to content submitted by the administrator.'; $lang->use_object_cache = 'Use Cache'; $lang->cache_default_ttl = 'Cache default TTL'; diff --git a/modules/admin/lang/ko.php b/modules/admin/lang/ko.php index 64ea8172d..0f9e64eaa 100644 --- a/modules/admin/lang/ko.php +++ b/modules/admin/lang/ko.php @@ -166,9 +166,11 @@ $lang->mediafilter_classes = 'HTML class 허용'; $lang->about_mediafilter_classes = '게시물, 댓글 등에서 허용되는 HTML class 속성의 목록을 지정할 수 있습니다.
사이트 디자인이나 기능과 중복되는 class를 허용할 경우 악의적으로 디자인을 망가뜨리거나 다른 사용자의 혼란을 유발할 수 있습니다.
관리자가 작성한 글은 제한을 받지 않습니다.'; $lang->robot_user_agents = '로봇 user-agent'; $lang->about_robot_user_agents = '일반적인 검색엔진 크롤러 외에 로봇으로 취급해야 할 user-agent가 있다면 한 줄에 하나씩 입력해 주십시오.
악성 크롤러로 인한 서버 부하 및 과도한 트래픽을 방지하는 데 도움이 될 수 있습니다.'; -$lang->use_samesite = 'SameSite 속성 사용'; +$lang->use_samesite = 'SameSite 속성'; $lang->use_samesite_empty = '표기하지 않음'; $lang->about_use_samesite = '세션 쿠키, 보안키 등에 적용되는 SameSite 속성을 선택할 수 있습니다.
대부분의 사이트에는 Lax를 권장하며, 최신 브라우저에서 결제 연동 등에 문제가 있는 경우 None을 선택하시기 바랍니다.
단, None을 선택할 경우 SSL 전용 세션을 사용하여야 정상 작동합니다.'; +$lang->about_x_frame_options = '다른 사이트에서 이 사이트를 iframe으로 로딩하는 것을 차단합니다. Clickjacking 공격 방지에 도움이 됩니다.
대부분의 사이트에는 SameOrigin을 추천합니다. Deny로 설정하면 같은 사이트 내에서도 iframe이 작동하지 않습니다.
웹서버 설정에서 이미 X-Frame-Options 헤더를 출력하고 있는 경우에는 중복 사용하지 마십시오.'; +$lang->about_x_content_type_options = '브라우저가 문서나 첨부파일의 MIME type을 스니핑하여 임의로 처리하는 것을 막습니다.
웹서버 설정에서 이미 X-Content-Type-Options 헤더를 출력하고 있는 경우에는 중복 사용하지 마십시오.'; $lang->use_session_keys = '세션 보안키 사용'; $lang->about_use_session_keys = '세션 탈취를 방지하기 위한 보안키를 사용합니다. SSL 전용 세션을 사용하지 않을 경우 반드시 보안키를 사용하시기를 권장합니다.
사용자 환경에 따라 로그인이 풀리는 문제가 발생할 수 있습니다.'; $lang->use_session_ssl = 'SSL 전용 세션 사용'; @@ -177,7 +179,7 @@ $lang->use_cookies_ssl = 'SSL 전용 쿠키 사용'; $lang->about_use_cookies_ssl = '세션뿐 아니라 모든 쿠키를 SSL 전용으로 지정합니다.
SSL을 항상 사용하도록 설정되어 있는 경우에만 활성화됩니다.'; $lang->check_csrf_token = 'CSRF 토큰 사용'; $lang->about_check_csrf_token = 'CSRF 토큰을 사용하여 정상적인 요청 여부를 확인합니다. 보안이 향상되지만, 일부 서드파티 자료와 호환되지 않을 수 있습니다.
사용하지 않을 경우 리퍼러 헤더 확인만으로 CSRF 공격에 방어합니다.'; -$lang->use_nofollow = 'Nofollow 속성 사용'; +$lang->use_nofollow = '링크에 nofollow 추가'; $lang->about_use_nofollow = '사용자들이 작성한 글에 포함된 모든 링크에 rel="nofollow" 속성을 추가하여 스팸으로 인한 사이트 신뢰도 저하를 방지합니다.
관리자가 작성한 글에는 적용되지 않습니다.'; $lang->use_object_cache = '캐시 사용'; $lang->cache_default_ttl = '캐시 기본 TTL'; diff --git a/modules/admin/tpl/config_security.html b/modules/admin/tpl/config_security.html index 9fcb541df..ca23746da 100644 --- a/modules/admin/tpl/config_security.html +++ b/modules/admin/tpl/config_security.html @@ -45,17 +45,6 @@

{$lang->about_admin_ip_deny}

-
- -
- - - - -
-

{$lang->about_use_samesite}

-
-
@@ -101,6 +90,36 @@

{$lang->about_use_nofollow}

+
+ +
+ + + + +
+

{$lang->about_use_samesite}

+
+
+
+ +
+ + + +
+

{$lang->about_x_frame_options}

+
+
+
+ +
+ + +
+

{$lang->about_x_content_type_options}

+
+