From c95168fb0ce0d8ca2253a43cc08b339a82989535 Mon Sep 17 00:00:00 2001 From: Kkigomi <112419763+kkigomi@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:26:28 +0900 Subject: [PATCH 1/3] =?UTF-8?q?IP=20=EB=B3=80=EA=B2=BD=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EC=9D=B8=ED=95=9C=20=EA=B4=80=EB=A6=AC=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=A0=91=EA=B7=BC=20=EC=8B=9C=20=EC=A0=91=EC=86=8D?= =?UTF-8?q?=EC=9D=B4=20=EC=A0=9C=ED=95=9C=EB=90=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0=20(#284)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `ss_mb_key`를 생성하고 검증할 때 IP를 제거하고 대체 함 프록시 등의 사용으로 IP가 수시로 변경되는 환경이라면 관리페이지 접근에 수시로 제한이 되는 문제를 해결하기 위함 * `ss_mb_key` 세션 값 생성 코드의 중복을 제거하기 위해 정리 * client_key 유효 시간을 세션 동안만 유지되도록 변경 --- adm/admin.lib.php | 7 +++---- bbs/login_check.php | 5 +++-- lib/common.lib.php | 47 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/adm/admin.lib.php b/adm/admin.lib.php index 58336b576..8bc521e2d 100644 --- a/adm/admin.lib.php +++ b/adm/admin.lib.php @@ -617,13 +617,12 @@ if (!$member['mb_id']) { } } -// 관리자의 아이피, 브라우저와 다르다면 세션을 끊고 관리자에게 메일을 보낸다. -$admin_key = md5($member['mb_datetime'] . get_real_client_ip() . $_SERVER['HTTP_USER_AGENT']); -if (get_session('ss_mb_key') !== $admin_key) { - +// 관리자의 클라이언트를 검증하여 일치하지 않으면 세션을 끊고 관리자에게 메일을 보낸다. +if (!verify_mb_key($member)) { session_destroy(); include_once G5_LIB_PATH . '/mailer.lib.php'; + // 메일 알림 mailer($member['mb_nick'], $member['mb_email'], $member['mb_email'], 'XSS 공격 알림', $_SERVER['REMOTE_ADDR'] . ' 아이피로 XSS 공격이 있었습니다.

관리자 권한을 탈취하려는 접근이므로 주의하시기 바랍니다.

해당 아이피는 차단하시고 의심되는 게시물이 있는지 확인하시기 바랍니다.' . G5_URL, 0); diff --git a/bbs/login_check.php b/bbs/login_check.php index ea654f3f7..3882f38c0 100644 --- a/bbs/login_check.php +++ b/bbs/login_check.php @@ -71,8 +71,9 @@ if (! (defined('SKIP_SESSION_REGENERATE_ID') && SKIP_SESSION_REGENERATE_ID)) { // 회원아이디 세션 생성 set_session('ss_mb_id', $mb['mb_id']); -// FLASH XSS 공격에 대응하기 위하여 회원의 고유키를 생성해 놓는다. 관리자에서 검사함 - 110106 -set_session('ss_mb_key', md5($mb['mb_datetime'] . get_real_client_ip() . $_SERVER['HTTP_USER_AGENT'])); +// FLASH XSS 공격에 대응하기 위하여 회원의 고유키를 생성해 놓는다. 관리자에서 검사함 +generate_mb_key($mb); + // 회원의 토큰키를 세션에 저장한다. /common.php 에서 해당 회원의 토큰값을 검사한다. if(function_exists('update_auth_session_token')) update_auth_session_token($mb['mb_datetime']); diff --git a/lib/common.lib.php b/lib/common.lib.php index edf06a002..f05c8e30b 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -2266,6 +2266,53 @@ function check_token() return true; } +/** + * 브라우저 검증을 위한 세션 반환 및 재생성 + * @param array $member 로그인 된 회원의 정보. 가입일시(mb_datetime)를 반드시 포함해야 한다. + * @param bool $regenerate true 이면 재생성 + * @return string + */ +function ss_mb_key($member, $regenerate = false) +{ + $client_key = ($regenerate) ? null : get_cookie('mb_client_key'); + + if (!$client_key) { + $client_key = get_random_token_string(16); + set_cookie('mb_client_key', $client_key, G5_SERVER_TIME * -1); + } + + $mb_key = md5($member['mb_datetime'] . $client_key) . md5($_SERVER['HTTP_USER_AGENT']); + + return $mb_key; +} + +/** + * 회원의 클라이언트 검증 + * @param array $member 로그인 된 회원의 정보. 가입일시(mb_datetime)를 반드시 포함해야 한다. + * @return bool + */ +function verify_mb_key($member) +{ + $mb_key = ss_mb_key($member); + $verified = get_session('ss_mb_key') === $mb_key; + + if (!$verified) { + ss_mb_key($member, true); + } + + return $verified; +} + +/** + * 회원의 클라이언트 검증 키 생성 + * 클라이언트 키를 다시 생성하여 생성된 키는 `ss_mb_key` 세션에 저장됨 + * @param array $member 로그인 된 회원의 정보. 가입일시(mb_datetime)를 반드시 포함해야 한다. + */ +function generate_mb_key($member) +{ + $mb_key = ss_mb_key($member, true); + set_session('ss_mb_key', $mb_key); +} // 문자열에 utf8 문자가 들어 있는지 검사하는 함수 // 코드 : http://in2.php.net/manual/en/function.mb-check-encoding.php#95289 From c869f29f0d58ddc49d0921bb5eba137ed9175f0b Mon Sep 17 00:00:00 2001 From: MayCactus <138797510+maycactus-FOSS@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:27:00 -0400 Subject: [PATCH 2/3] =?UTF-8?q?=EC=84=B8=EC=85=98=20=EC=BF=A0=ED=82=A4=20?= =?UTF-8?q?=EB=B3=B4=EC=95=88=20=EA=B0=95=ED=99=94=20(#282)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Enhance Session Cookie Security * Fix user registration link path --- common.php | 9 +++++++-- lib/common.lib.php | 4 ++++ mobile/skin/member/basic/login.skin.php | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/common.php b/common.php index c541f5f2b..3ba99a536 100644 --- a/common.php +++ b/common.php @@ -226,7 +226,12 @@ ini_set("session.gc_maxlifetime", 10800); // session data의 garbage collection ini_set("session.gc_probability", 1); // session.gc_probability는 session.gc_divisor와 연계하여 gc(쓰레기 수거) 루틴의 시작 확률을 관리합니다. 기본값은 1입니다. 자세한 내용은 session.gc_divisor를 참고하십시오. ini_set("session.gc_divisor", 100); // session.gc_divisor는 session.gc_probability와 결합하여 각 세션 초기화 시에 gc(쓰레기 수거) 프로세스를 시작할 확률을 정의합니다. 확률은 gc_probability/gc_divisor를 사용하여 계산합니다. 즉, 1/100은 각 요청시에 GC 프로세스를 시작할 확률이 1%입니다. session.gc_divisor의 기본값은 100입니다. -session_set_cookie_params(0, '/', null, false, true); +if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') { + session_set_cookie_params(0, '/', null, true, true); +} else { + session_set_cookie_params(0, '/', null, false, true); +} + ini_set("session.cookie_domain", G5_COOKIE_DOMAIN); function chrome_domain_session_name(){ @@ -381,7 +386,7 @@ if( $config['cf_cert_use'] || (defined('G5_YOUNGCART_VER') && G5_YOUNGCART_VER) $cookie_session_name = method_exists('XenoPostToForm', 'g5_session_name') ? XenoPostToForm::g5_session_name() : 'PHPSESSID'; foreach ($headers as $header) { if (!preg_match('~^Set-Cookie: '.$cookie_session_name.'=~', $header)) continue; - $header = preg_replace('~; secure(; HttpOnly)?$~', '', $header) . '; secure; SameSite=None'; + $header = preg_replace('~(; secure; HttpOnly)?$~', '; secure; HttpOnly; SameSite=None', $header); header($header, false); $g5['session_cookie_samesite'] = 'none'; break; diff --git a/lib/common.lib.php b/lib/common.lib.php index f05c8e30b..d55eda13e 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -155,6 +155,10 @@ function set_cookie($cookie_name, $value, $expire, $path='/', $domain=G5_COOKIE_ global $g5; $c = run_replace('set_cookie_params', array('path'=>$path, 'domain'=>$domain, 'secure'=>$secure, 'httponly'=>$httponly), $cookie_name); + + if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') { + $c['secure'] = true; + } setcookie(md5($cookie_name), base64_encode($value), G5_SERVER_TIME + $expire, $c['path'], $c['domain'], $c['secure'], $c['httponly']); } diff --git a/mobile/skin/member/basic/login.skin.php b/mobile/skin/member/basic/login.skin.php index 67aca531a..14631fd8c 100644 --- a/mobile/skin/member/basic/login.skin.php +++ b/mobile/skin/member/basic/login.skin.php @@ -33,7 +33,7 @@ add_stylesheet('',

회원로그인 안내

아이디/비밀번호 찾기 - 회원 가입 + 회원 가입
From ee75b32b3cbfd8f52cbeb8738782dae563d5b479 Mon Sep 17 00:00:00 2001 From: Kkigomi <112419763+kkigomi@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:27:18 +0900 Subject: [PATCH 3/3] =?UTF-8?q?adm/index.php=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EC=97=90=20=EC=BB=A8=ED=85=90=EC=B8=A0=EB=A5=BC=20=EC=82=BD?= =?UTF-8?q?=EC=9E=85=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94=20Hook=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=20(#283)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 코드 포맷 * adm/index.php 페이지에 컨텐츠를 삽입할 수 있는 Hook 추가 - adm_index_addtional_content_before - adm_index_addtional_content_after --- adm/index.php | 76 +++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/adm/index.php b/adm/index.php index 2ca6feacc..cd6eeebff 100644 --- a/adm/index.php +++ b/adm/index.php @@ -3,8 +3,10 @@ $sub_menu = '100000'; require_once './_common.php'; @require_once './safe_check.php'; + if (function_exists('social_log_file_delete')) { - social_log_file_delete(86400); //소셜로그인 디버그 파일 24시간 지난것은 삭제 + //소셜로그인 디버그 파일 24시간 지난것은 삭제 + social_log_file_delete(86400); } $g5['title'] = '관리자메인'; @@ -14,8 +16,12 @@ $new_member_rows = 5; $new_point_rows = 5; $new_write_rows = 5; -if (! auth_check_menu($auth, '200100', 'r', true)) { +$addtional_content_before = run_replace('adm_index_addtional_content_before', '', $is_admin, $auth, $member); +if ($addtional_content_before) { + echo $addtional_content_before; +} +if (!auth_check_menu($auth, '200100', 'r', true)) { $sql_common = " from {$g5['member_table']} "; $sql_search = " where (1) "; @@ -31,7 +37,7 @@ if (! auth_check_menu($auth, '200100', 'r', true)) { $sql_order = " order by {$sst} {$sod} "; - $sql = " select count(*) as cnt {$sql_common} {$sql_search} {$sql_order} "; + $sql = " SELECT count(*) as cnt {$sql_common} {$sql_search} {$sql_order} "; $row = sql_fetch($sql); $total_count = $row['cnt']; @@ -41,11 +47,11 @@ if (! auth_check_menu($auth, '200100', 'r', true)) { $leave_count = $row['cnt']; // 차단회원수 - $sql = " select count(*) as cnt {$sql_common} {$sql_search} and mb_intercept_date <> '' {$sql_order} "; + $sql = " SELECT count(*) as cnt {$sql_common} {$sql_search} and mb_intercept_date <> '' {$sql_order} "; $row = sql_fetch($sql); $intercept_count = $row['cnt']; - $sql = " select * {$sql_common} {$sql_search} {$sql_order} limit {$new_member_rows} "; + $sql = " SELECT * {$sql_common} {$sql_search} {$sql_order} limit {$new_member_rows} "; $result = sql_query($sql); $colspan = 12; @@ -78,7 +84,7 @@ if (! auth_check_menu($auth, '200100', 'r', true)) { + ?> @@ -115,7 +121,7 @@ if (! auth_check_menu($auth, '200100', 'r', true)) { - 자료가 없습니다.'; @@ -128,18 +134,17 @@ if (! auth_check_menu($auth, '200100', 'r', true)) {
회원 전체보기
- - + ?> @@ -223,7 +228,7 @@ if (! auth_check_menu($auth, '300100', 'r', true)) { - 자료가 없습니다.'; @@ -239,19 +244,19 @@ if (! auth_check_menu($auth, '300100', 'r', true)) { '; $link2 = ''; } - ?> + ?> @@ -307,7 +312,7 @@ if (! auth_check_menu($auth, '200200', 'r', true)) { - -