From d149ccdae2b112b281703bc3780c7a36d1e2397a Mon Sep 17 00:00:00 2001 From: Arcturus Date: Thu, 19 Sep 2024 20:57:55 +0900 Subject: [PATCH] security patch --- .../adm/member_form_update.php | 40 +++- AvocadoEdition_Light/adm/menu_list_update.php | 3 +- AvocadoEdition_Light/bbs/member_confirm.php | 10 +- AvocadoEdition_Light/bbs/memo.php | 5 +- AvocadoEdition_Light/bbs/qawrite.php | 5 +- AvocadoEdition_Light/bbs/write_update.php | 165 ++++++++------- AvocadoEdition_Light/head.sub.php | 12 -- AvocadoEdition_Light/lib/common.lib.php | 200 ++++++++++++------ AvocadoEdition_Light/lib/hook.lib.php | 143 +++++++++++++ 9 files changed, 422 insertions(+), 161 deletions(-) create mode 100644 AvocadoEdition_Light/lib/hook.lib.php diff --git a/AvocadoEdition_Light/adm/member_form_update.php b/AvocadoEdition_Light/adm/member_form_update.php index 1db67f6..0f97d84 100644 --- a/AvocadoEdition_Light/adm/member_form_update.php +++ b/AvocadoEdition_Light/adm/member_form_update.php @@ -34,6 +34,45 @@ $_POST['mb_nick'] = $_POST['mb_name']; $mb_zip1 = substr($_POST['mb_zip'], 0, 3); $mb_zip2 = substr($_POST['mb_zip'], 3); +// 관리자가 자동등록방지를 사용해야 할 경우 ( 회원의 비밀번호 변경시 캡챠를 체크한다 ) +if ($mb_password && function_exists('get_admin_captcha_by') && get_admin_captcha_by()) { + include_once(G5_CAPTCHA_PATH . '/captcha.lib.php'); + + if (!chk_captcha()) { + alert('자동등록방지 숫자가 틀렸습니다.'); + } +} + +$check_keys = array( + 'mb_name', + 'mb_homepage', + 'mb_tel', + 'mb_addr1', + 'mb_addr2', + 'mb_addr3', + 'mb_addr_jibeon', + 'mb_signature', + 'mb_leave_date', + 'mb_intercept_date', + 'mb_mailling', + 'mb_sms', + 'mb_open', + 'mb_profile', + 'mb_level' +); + +for ($i = 1; $i <= 10; $i++) { + $check_keys[] = 'mb_' . $i; +} + +foreach ($check_keys as $key) { + if (in_array($key, array('mb_signature', 'mb_profile'))) { + $posts[$key] = isset($_POST[$key]) ? clean_xss_tags($_POST[$key], 1, 1, 0, 0) : ''; + } else { + $posts[$key] = isset($_POST[$key]) ? clean_xss_tags($_POST[$key], 1, 1) : ''; + } +} + $sql_common = " mb_name = '{$_POST['mb_name']}', mb_nick = '{$_POST['mb_nick']}', mb_email = '{$_POST['mb_email']}', @@ -158,5 +197,4 @@ if ($w == '') { sql_query($sql); } else alert('제대로 된 값이 넘어오지 않았습니다.'); - goto_url('./member_form.php?' . $qstr . '&w=u&mb_id=' . $mb_id); diff --git a/AvocadoEdition_Light/adm/menu_list_update.php b/AvocadoEdition_Light/adm/menu_list_update.php index b008e15..268cb2e 100644 --- a/AvocadoEdition_Light/adm/menu_list_update.php +++ b/AvocadoEdition_Light/adm/menu_list_update.php @@ -23,7 +23,8 @@ for ($i = 0; $i < $count; $i++) { $code = $_POST['code'][$i]; $me_name = $_POST['me_name'][$i]; - $me_link = $_POST['me_link'][$i]; + // kve-2021-0755 gnuboard 3a3434104c + $me_link = html_purifier($_POST['me_link'][$i]); if (!$code || !$me_name) continue; diff --git a/AvocadoEdition_Light/bbs/member_confirm.php b/AvocadoEdition_Light/bbs/member_confirm.php index c84af75..37b48c3 100644 --- a/AvocadoEdition_Light/bbs/member_confirm.php +++ b/AvocadoEdition_Light/bbs/member_confirm.php @@ -14,7 +14,15 @@ else $g5['title'] = '회원 비밀번호 확인'; include_once('./_head.sub.php'); -$url = clean_xss_tags($_GET['url']); +// gnuboard xss patch - 2457055514 +$url = isset($_GET['url']) ? clean_xss_tags($_GET['url']) : ''; + +while (1) { + $tmp = preg_replace('/&#[^;]+;/', '', $url); + if ($tmp == $url) + break; + $url = $tmp; +} // url 체크 check_url_host($url); diff --git a/AvocadoEdition_Light/bbs/memo.php b/AvocadoEdition_Light/bbs/memo.php index 5031218..029ba39 100644 --- a/AvocadoEdition_Light/bbs/memo.php +++ b/AvocadoEdition_Light/bbs/memo.php @@ -14,8 +14,11 @@ if ($kind == 'recv') $unkind = 'send'; else if ($kind == 'send') $unkind = 'recv'; -else +else { + // xss patch - gnuboard 2e81619ea8 + $kind = clean_xss_tags(trim($kind)); alert('' . $kind . '값을 넘겨주세요.'); +} $sql = " select count(*) as cnt from {$g5['memo_table']} where me_{$kind}_mb_id = '{$member['mb_id']}' "; $row = sql_fetch($sql); diff --git a/AvocadoEdition_Light/bbs/qawrite.php b/AvocadoEdition_Light/bbs/qawrite.php index 4809807..3f087a8 100644 --- a/AvocadoEdition_Light/bbs/qawrite.php +++ b/AvocadoEdition_Light/bbs/qawrite.php @@ -74,9 +74,10 @@ if (is_file($skin_file)) { else $content = "\n\n\n\n====== 이전 답변내용 =======\n"; - $content .= get_text($write['qa_content'], 0); + // gnuboard xss patch 210624 - f631b3dca7 + $content .= get_text(html_purifier($write['qa_content']), 0); } else { - $content = get_text($write['qa_content'], 0); + $content = get_text(html_purifier($write['qa_content']), 0); } $editor_html = editor_html('qa_content', $content, $is_dhtml_editor); diff --git a/AvocadoEdition_Light/bbs/write_update.php b/AvocadoEdition_Light/bbs/write_update.php index fc635a6..8d7d087 100644 --- a/AvocadoEdition_Light/bbs/write_update.php +++ b/AvocadoEdition_Light/bbs/write_update.php @@ -452,7 +452,7 @@ if (!$group['gr_use_access'] && $board['bo_read_level'] < 2 && !$secret) { // 파일개수 체크 $file_count = 0; -$upload_count = count($_FILES['bf_file']['name']); +$upload_count = !empty($_FILES['bf_file']['name']) ? count($_FILES['bf_file']['name']) : 0; for ($i = 0; $i < $upload_count; $i++) { if ($_FILES['bf_file']['name'][$i] && is_uploaded_file($_FILES['bf_file']['tmp_name'][$i])) @@ -477,101 +477,104 @@ $chars_array = array_merge(range(0, 9), range('a', 'z'), range('A', 'Z')); // 가변 파일 업로드 $file_upload_msg = ''; $upload = array(); -for ($i = 0; $i < count($_FILES['bf_file']['name']); $i++) { - $upload[$i]['file'] = ''; - $upload[$i]['source'] = ''; - $upload[$i]['filesize'] = 0; - $upload[$i]['image'] = array(); - $upload[$i]['image'][0] = ''; - $upload[$i]['image'][1] = ''; - $upload[$i]['image'][2] = ''; - // 삭제에 체크가 되어있다면 파일을 삭제합니다. - if (isset($_POST['bf_file_del'][$i]) && $_POST['bf_file_del'][$i]) { - $upload[$i]['del_check'] = true; +if ($upload_count != 0) { + for ($i = 0; $i < count($_FILES['bf_file']['name']); $i++) { + $upload[$i]['file'] = ''; + $upload[$i]['source'] = ''; + $upload[$i]['filesize'] = 0; + $upload[$i]['image'] = array(); + $upload[$i]['image'][0] = ''; + $upload[$i]['image'][1] = ''; + $upload[$i]['image'][2] = ''; - $row = sql_fetch(" select bf_file from {$g5['board_file_table']} where bo_table = '{$bo_table}' and wr_id = '{$wr_id}' and bf_no = '{$i}' "); - @unlink(G5_DATA_PATH . '/file/' . $bo_table . '/' . $row['bf_file']); - // 썸네일삭제 - if (preg_match("/\.({$config['cf_image_extension']})$/i", $row['bf_file'])) { - delete_board_thumbnail($bo_table, $row['bf_file']); - } - } else - $upload[$i]['del_check'] = false; + // 삭제에 체크가 되어있다면 파일을 삭제합니다. + if (isset($_POST['bf_file_del'][$i]) && $_POST['bf_file_del'][$i]) { + $upload[$i]['del_check'] = true; - $tmp_file = $_FILES['bf_file']['tmp_name'][$i]; - $filesize = $_FILES['bf_file']['size'][$i]; - $filename = $_FILES['bf_file']['name'][$i]; - - $filename = get_safe_filename($filename); - - // 서버에 설정된 값보다 큰파일을 업로드 한다면 - if ($filename) { - if ($_FILES['bf_file']['error'][$i] == 1) { - $file_upload_msg .= '\"' . $filename . '\" 파일의 용량이 서버에 설정(' . $upload_max_filesize . ')된 값보다 크므로 업로드 할 수 없습니다.\\n'; - continue; - } else if ($_FILES['bf_file']['error'][$i] != 0) { - $file_upload_msg .= '\"' . $filename . '\" 파일이 정상적으로 업로드 되지 않았습니다.\\n'; - continue; - } - } - - if (is_uploaded_file($tmp_file)) { - // 관리자가 아니면서 설정한 업로드 사이즈보다 크다면 건너뜀 - if (!$is_admin && $filesize > $board['bo_upload_size']) { - $file_upload_msg .= '\"' . $filename . '\" 파일의 용량(' . number_format($filesize) . ' 바이트)이 게시판에 설정(' . number_format($board['bo_upload_size']) . ' 바이트)된 값보다 크므로 업로드 하지 않습니다.\\n'; - continue; - } - - //=================================================================\ - // 090714 - // 이미지나 플래시 파일에 악성코드를 심어 업로드 하는 경우를 방지 - // 에러메세지는 출력하지 않는다. - //----------------------------------------------------------------- - $timg = @getimagesize($tmp_file); - // image type - if ( - preg_match("/\.({$config['cf_image_extension']})$/i", $filename) || - preg_match("/\.({$config['cf_flash_extension']})$/i", $filename) - ) { - if ($timg['2'] < 1 || $timg['2'] > 16) - continue; - } - //================================================================= - - $upload[$i]['image'] = $timg; - - // 4.00.11 - 글답변에서 파일 업로드시 원글의 파일이 삭제되는 오류를 수정 - if ($w == 'u') { - // 존재하는 파일이 있다면 삭제합니다. - $row = sql_fetch(" select bf_file from {$g5['board_file_table']} where bo_table = '$bo_table' and wr_id = '$wr_id' and bf_no = '$i' "); + $row = sql_fetch(" select bf_file from {$g5['board_file_table']} where bo_table = '{$bo_table}' and wr_id = '{$wr_id}' and bf_no = '{$i}' "); @unlink(G5_DATA_PATH . '/file/' . $bo_table . '/' . $row['bf_file']); - // 이미지파일이면 썸네일삭제 + // 썸네일삭제 if (preg_match("/\.({$config['cf_image_extension']})$/i", $row['bf_file'])) { delete_board_thumbnail($bo_table, $row['bf_file']); } + } else + $upload[$i]['del_check'] = false; + + $tmp_file = $_FILES['bf_file']['tmp_name'][$i]; + $filesize = $_FILES['bf_file']['size'][$i]; + $filename = $_FILES['bf_file']['name'][$i]; + + $filename = get_safe_filename($filename); + + // 서버에 설정된 값보다 큰파일을 업로드 한다면 + if ($filename) { + if ($_FILES['bf_file']['error'][$i] == 1) { + $file_upload_msg .= '\"' . $filename . '\" 파일의 용량이 서버에 설정(' . $upload_max_filesize . ')된 값보다 크므로 업로드 할 수 없습니다.\\n'; + continue; + } else if ($_FILES['bf_file']['error'][$i] != 0) { + $file_upload_msg .= '\"' . $filename . '\" 파일이 정상적으로 업로드 되지 않았습니다.\\n'; + continue; + } } - // 프로그램 원래 파일명 - $upload[$i]['source'] = $filename; - $upload[$i]['filesize'] = $filesize; + if (is_uploaded_file($tmp_file)) { + // 관리자가 아니면서 설정한 업로드 사이즈보다 크다면 건너뜀 + if (!$is_admin && $filesize > $board['bo_upload_size']) { + $file_upload_msg .= '\"' . $filename . '\" 파일의 용량(' . number_format($filesize) . ' 바이트)이 게시판에 설정(' . number_format($board['bo_upload_size']) . ' 바이트)된 값보다 크므로 업로드 하지 않습니다.\\n'; + continue; + } - // 아래의 문자열이 들어간 파일은 -x 를 붙여서 웹경로를 알더라도 실행을 하지 못하도록 함 - $filename = preg_replace("/\.(php|phtm|htm|cgi|pl|exe|jsp|asp|inc)/i", "$0-x", $filename); + //=================================================================\ + // 090714 + // 이미지나 플래시 파일에 악성코드를 심어 업로드 하는 경우를 방지 + // 에러메세지는 출력하지 않는다. + //----------------------------------------------------------------- + $timg = @getimagesize($tmp_file); + // image type + if ( + preg_match("/\.({$config['cf_image_extension']})$/i", $filename) || + preg_match("/\.({$config['cf_flash_extension']})$/i", $filename) + ) { + if ($timg['2'] < 1 || $timg['2'] > 16) + continue; + } + //================================================================= - shuffle($chars_array); - $shuffle = implode('', $chars_array); + $upload[$i]['image'] = $timg; - // 첨부파일 첨부시 첨부파일명에 공백이 포함되어 있으면 일부 PC에서 보이지 않거나 다운로드 되지 않는 현상이 있습니다. (길상여의 님 090925) - $upload[$i]['file'] = abs(ip2long($_SERVER['REMOTE_ADDR'])) . '_' . substr($shuffle, 0, 8) . '_' . replace_filename($filename); + // 4.00.11 - 글답변에서 파일 업로드시 원글의 파일이 삭제되는 오류를 수정 + if ($w == 'u') { + // 존재하는 파일이 있다면 삭제합니다. + $row = sql_fetch(" select bf_file from {$g5['board_file_table']} where bo_table = '$bo_table' and wr_id = '$wr_id' and bf_no = '$i' "); + @unlink(G5_DATA_PATH . '/file/' . $bo_table . '/' . $row['bf_file']); + // 이미지파일이면 썸네일삭제 + if (preg_match("/\.({$config['cf_image_extension']})$/i", $row['bf_file'])) { + delete_board_thumbnail($bo_table, $row['bf_file']); + } + } - $dest_file = G5_DATA_PATH . '/file/' . $bo_table . '/' . $upload[$i]['file']; + // 프로그램 원래 파일명 + $upload[$i]['source'] = $filename; + $upload[$i]['filesize'] = $filesize; - // 업로드가 안된다면 에러메세지 출력하고 죽어버립니다. - $error_code = move_uploaded_file($tmp_file, $dest_file) or die($_FILES['bf_file']['error'][$i]); + // 아래의 문자열이 들어간 파일은 -x 를 붙여서 웹경로를 알더라도 실행을 하지 못하도록 함 + $filename = preg_replace("/\.(php|phtm|htm|cgi|pl|exe|jsp|asp|inc)/i", "$0-x", $filename); - // 올라간 파일의 퍼미션을 변경합니다. - chmod($dest_file, G5_FILE_PERMISSION); + shuffle($chars_array); + $shuffle = implode('', $chars_array); + + // 첨부파일 첨부시 첨부파일명에 공백이 포함되어 있으면 일부 PC에서 보이지 않거나 다운로드 되지 않는 현상이 있습니다. (길상여의 님 090925) + $upload[$i]['file'] = abs(ip2long($_SERVER['REMOTE_ADDR'])) . '_' . substr($shuffle, 0, 8) . '_' . replace_filename($filename); + + $dest_file = G5_DATA_PATH . '/file/' . $bo_table . '/' . $upload[$i]['file']; + + // 업로드가 안된다면 에러메세지 출력하고 죽어버립니다. + $error_code = move_uploaded_file($tmp_file, $dest_file) or die($_FILES['bf_file']['error'][$i]); + + // 올라간 파일의 퍼미션을 변경합니다. + chmod($dest_file, G5_FILE_PERMISSION); + } } } diff --git a/AvocadoEdition_Light/head.sub.php b/AvocadoEdition_Light/head.sub.php index 1837da4..1b6577a 100644 --- a/AvocadoEdition_Light/head.sub.php +++ b/AvocadoEdition_Light/head.sub.php @@ -67,7 +67,6 @@ if (defined('_INDEX_')) { <?php echo $g5_head_title; ?> - @@ -81,23 +80,18 @@ if (defined('_INDEX_')) { echo ''; } ?> - - - - - ' . PHP_EOL; // overflow scroll 감지 @@ -131,11 +122,9 @@ if (defined('_INDEX_')) { if (!defined('G5_IS_ADMIN')) echo $config['cf_add_script']; ?> - - - diff --git a/AvocadoEdition_Light/lib/common.lib.php b/AvocadoEdition_Light/lib/common.lib.php index d7b16b2..3b53712 100644 --- a/AvocadoEdition_Light/lib/common.lib.php +++ b/AvocadoEdition_Light/lib/common.lib.php @@ -3,6 +3,10 @@ if (!defined('_GNUBOARD_')) exit; include_once(dirname(__FILE__) . '/pbkdf2.compat.php'); +include_once __DIR__ . "/hook.lib.php"; +include_once __DIR__ . '/Hook/hook.class.php'; +include_once __DIR__ . '/Hook/hook.extends.class.php'; + /************************************************************************* ** ** 일반 함수 모음 @@ -1438,7 +1442,8 @@ function sql_connect($host, $user, $pass, $db = G5_MYSQL_DB) global $g5; if (function_exists('mysqli_connect') && G5_MYSQLI_USE) { - $link = mysqli_connect($host, $user, $pass, $db); + mysqli_report(MYSQLI_REPORT_OFF); + $link = @mysqli_connect($host, $user, $pass, $db) or die('MySQL Host, User, Password, DB 정보에 오류가 있습니다.'); // 연결 오류 발생 시 스크립트 종료 if (mysqli_connect_errno()) { @@ -1477,12 +1482,27 @@ function sql_set_charset($charset, $link = null) mysql_query(" set names {$charset} ", $link); } +function sql_data_seek($result, $offset = 0) +{ + if (!$result) + return; + + if (function_exists('mysqli_set_charset') && G5_MYSQLI_USE) + mysqli_data_seek($result, $offset); + else + mysql_data_seek($result, $offset); +} + +function _callback_sql_show_tables($m) +{ + return "show tables like '" . str_replace("`", "", $m[1]) . "'"; +} // mysqli_query 와 mysqli_error 를 한꺼번에 처리 // mysql connect resource 지정 - 명랑폐인님 제안 function sql_query($sql, $error = G5_DISPLAY_SQL_ERROR, $link = null) { - global $g5; + global $g5, $g5_debug; if (!$link) $link = $g5['connect_db']; @@ -1495,11 +1515,19 @@ function sql_query($sql, $error = G5_DISPLAY_SQL_ERROR, $link = null) // `information_schema` DB로의 접근을 허락하지 않습니다. $sql = preg_replace("#^select.*from.*where.*`?information_schema`?.*#i", "select 1", $sql); + if (preg_match("#^desc(?:ribe)?\s+(.*)#i", $sql)) { + $sql = preg_replace_callback("#^desc(?:ribe)?\s+(.*)#i", '_callback_sql_show_tables', trim($sql)); + } + if (function_exists('mysqli_query') && G5_MYSQLI_USE) { if ($error) { $result = @mysqli_query($link, $sql) or die("

$sql

" . mysqli_errno($link) . " : " . mysqli_error($link) . "

error file : {$_SERVER['SCRIPT_NAME']}"); } else { - $result = @mysqli_query($link, $sql); + try { + $result = @mysqli_query($link, $sql); + } catch (Exception $e) { + $result = null; + } } } else { if ($error) { @@ -1509,6 +1537,8 @@ function sql_query($sql, $error = G5_DISPLAY_SQL_ERROR, $link = null) } } + run_event('sql_query_after', $result, $sql); + return $result; } @@ -1531,9 +1561,15 @@ function sql_fetch($sql, $error = G5_DISPLAY_SQL_ERROR, $link = null) // 결과값에서 한행 연관배열(이름으로)로 얻는다. function sql_fetch_array($result) { + if (!$result) + return array(); + if (function_exists('mysqli_fetch_assoc') && G5_MYSQLI_USE) - $row = @mysqli_fetch_assoc($result); - else + try { + $row = @mysqli_fetch_assoc($result); + } catch (Exception $e) { + $row = null; + } else $row = @mysql_fetch_assoc($result); return $row; @@ -1545,6 +1581,9 @@ function sql_fetch_array($result) // 단, 결과 값은 스크립트(script) 실행부가 종료되면서 메모리에서 자동적으로 지워진다. function sql_free_result($result) { + if (!is_resource($result)) + return; + if (function_exists('mysqli_free_result') && G5_MYSQLI_USE) return mysqli_free_result($result); else @@ -1629,7 +1668,6 @@ function sql_error_info($link = null) } } - // PHPMyAdmin 참고 function get_table_define($table, $crlf = "\n") { @@ -2864,9 +2902,44 @@ function get_search_string($stx) } // XSS 관련 태그 제거 -function clean_xss_tags($str) +// gnuboard - 258f94e597, d4f554e653 +function clean_xss_tags($str, $check_entities = 0, $is_remove_tags = 0, $cur_str_len = 0, $is_trim_both = 1) { - $str = preg_replace('#]*+>#i', '', $str); + if ($is_trim_both) { + // tab('\t'), formfeed('\f'), vertical tab('\v'), newline('\n'), carriage return('\r') 를 제거한다. + $str = preg_replace("#[\t\f\v\n\r]#", '', $str); + } + + if ($is_remove_tags) { + $str = strip_tags($str); + } + + if ($cur_str_len) { + $str = utf8_strcut($str, $cur_str_len, ''); + } + + $str_len = strlen($str); + + $i = 0; + while ($i <= $str_len) { + $result = preg_replace('#]*+>#i', '', $str); + + if ($check_entities) { + $result = str_replace(array(':', '(', ')', ' ', ' '), '', $result); + } + + $result = preg_replace( + '#([^\p{L}]|^)(?:javascript|jar|applescript|vbscript|vbs|wscript|jscript|behavior|mocha|livescript|view-source)\s*:(?:.*?([/\\\;()\'">]|$))#ius', + '$1$2', + $result + ); + + if ((string) $result === (string) $str) + break; + + $str = $result; + $i++; + } return $str; } @@ -3033,24 +3106,71 @@ function login_password_check($mb, $pass, $hash) return check_password($pass, $hash); } - // 동일한 host url 인지 -function check_url_host($url, $msg = '', $return_url = G5_URL) +function check_url_host($url, $msg = '', $return_url = G5_URL, $is_redirect = false) { if (!$msg) $msg = 'url에 타 도메인을 지정할 수 없습니다.'; - $p = @parse_url($url); - $host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']); - - if (stripos($url, 'http:') !== false) { - if (!isset($p['scheme']) || !$p['scheme'] || !isset($p['host']) || !$p['host']) - alert('url 정보가 올바르지 않습니다.', $return_url); + if (run_replace('check_url_host_before', '', $url, $msg, $return_url, $is_redirect) === 'is_checked') { + return; } - if ((isset($p['scheme']) && $p['scheme']) || (isset($p['host']) && $p['host'])) { + // KVE-2021-1277 Open Redirect 취약점 해결 + if (preg_match('#\\\0#', $url)) { + alert('url 에 올바르지 않은 값이 포함되어 있습니다.'); + } + + while (($replace_url = preg_replace(array('/\/{2,}/', '/\\@/'), array('//', ''), urldecode($url))) != $url) { + $url = $replace_url; + } + + $p = @parse_url(trim($url)); + $host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']); + $is_host_check = false; + + // url을 urlencode 를 2번이상하면 parse_url 에서 scheme와 host 값을 가져올수 없는 취약점이 존재함 + if ($is_redirect && !isset($p['host']) && urldecode($url) != $url) { + $i = 0; + while ($i <= 3) { + $url = urldecode($url); + if (urldecode($url) == $url) + break; + $i++; + } + + if (urldecode($url) == $url) { + $p = @parse_url($url); + } else { + $is_host_check = true; + } + } + + // if(stripos($url, 'http:') !== false) { + // if(!isset($p['scheme']) || !$p['scheme'] || !isset($p['host']) || !$p['host']) + // alert('url 정보가 올바르지 않습니다.', $return_url); + // } + + //php 5.6.29 이하 버전에서는 parse_url 버그가 존재함 + //php 7.0.1 ~ 7.0.5 버전에서는 parse_url 버그가 존재함 + if ($is_redirect && (isset($p['host']) && $p['host'])) { + $bool_ch = false; + foreach (array('user', 'host') as $key) { + if (isset($p[$key]) && strpbrk($p[$key], ':/?#@')) { + $bool_ch = true; + } + } + if ($bool_ch) { + $regex = '/https?\:\/\/' . $host . '/i'; + if (!preg_match($regex, $url)) { + $is_host_check = true; + } + } + } + + if ((isset($p['scheme']) && $p['scheme']) || (isset($p['host']) && $p['host']) || $is_host_check) { //if ($p['host'].(isset($p['port']) ? ':'.$p['port'] : '') != $_SERVER['HTTP_HOST']) { - if ($p['host'] != $host) { + if (run_replace('check_same_url_host', (($p['host'] != $host) || $is_host_check), $p, $host, $is_host_check, $return_url, $is_redirect)) { echo '