feat: 메일 인증 링크 유효시간 설정 추가
This commit is contained in:
@@ -12,6 +12,15 @@ if ($is_admin != 'super') {
|
||||
$sql = " select * from {$g5['config_table']} limit 1";
|
||||
$config = sql_fetch($sql);
|
||||
|
||||
if (!isset($config['cf_email_certify_minutes'])) {
|
||||
sql_query(
|
||||
" ALTER TABLE `{$g5['config_table']}`
|
||||
ADD `cf_email_certify_minutes` INT(11) NOT NULL DEFAULT '60' AFTER `cf_use_email_certify` ",
|
||||
true
|
||||
);
|
||||
$config['cf_email_certify_minutes'] = 60;
|
||||
}
|
||||
|
||||
if (!isset($config['cf_add_script'])) {
|
||||
sql_query(
|
||||
" ALTER TABLE `{$g5['config_table']}`
|
||||
@@ -1189,6 +1198,13 @@ if ($config['cf_sms_use'] && $config['cf_icode_id'] && $config['cf_icode_pw']) {
|
||||
<input type="checkbox" name="cf_use_email_certify" value="1" id="cf_use_email_certify" <?php echo $config['cf_use_email_certify'] ? 'checked' : ''; ?>> 사용
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="cf_email_certify_minutes">메일인증 유효시간</label></th>
|
||||
<td>
|
||||
<?php echo help('인증메일 발송 후 링크를 사용할 수 있는 시간을 분 단위로 설정합니다. 0은 만료시간을 적용하지 않습니다.') ?>
|
||||
<input type="number" name="cf_email_certify_minutes" value="<?php echo isset($config['cf_email_certify_minutes']) ? (int) $config['cf_email_certify_minutes'] : 60; ?>" id="cf_email_certify_minutes" class="frm_input" min="0"> 분
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row"><label for="cf_formmail_is_member">폼메일 사용 여부</label></th>
|
||||
<td>
|
||||
|
||||
@@ -56,6 +56,7 @@ if (isset($_POST['cf_intercept_ip']) && $_POST['cf_intercept_ip']) {
|
||||
|
||||
$check_keys = array(
|
||||
'cf_use_email_certify' => 'int',
|
||||
'cf_email_certify_minutes' => 'int',
|
||||
'cf_use_homepage' => 'int',
|
||||
'cf_req_homepage' => 'int',
|
||||
'cf_use_tel' => 'int',
|
||||
@@ -178,6 +179,8 @@ foreach ($check_keys as $k => $v) {
|
||||
}
|
||||
}
|
||||
|
||||
$_POST['cf_email_certify_minutes'] = max(0, $_POST['cf_email_certify_minutes']);
|
||||
|
||||
// 본인확인을 사용할 경우 아이핀, 휴대폰인증 중 하나는 선택되어야 함
|
||||
if ($_POST['cf_cert_use'] && !$_POST['cf_cert_ipin'] && !$_POST['cf_cert_hp'] && !$_POST['cf_cert_simple']) {
|
||||
alert('본인확인을 위해 아이핀, 휴대폰 본인확인, KG이니시스 간편인증 서비스 중 하나 이상 선택해 주십시오.');
|
||||
@@ -226,6 +229,7 @@ $sql = " update {$g5['config_table']}
|
||||
cf_point_term = '{$_POST['cf_point_term']}',
|
||||
cf_use_copy_log = '{$_POST['cf_use_copy_log']}',
|
||||
cf_use_email_certify = '{$_POST['cf_use_email_certify']}',
|
||||
cf_email_certify_minutes = '{$_POST['cf_email_certify_minutes']}',
|
||||
cf_login_point = '{$_POST['cf_login_point']}',
|
||||
cf_cut_name = '{$_POST['cf_cut_name']}',
|
||||
cf_nick_modify = '{$_POST['cf_nick_modify']}',
|
||||
|
||||
@@ -9,6 +9,15 @@ include_once('./admin.head.php');
|
||||
|
||||
$is_check = false;
|
||||
|
||||
// 메일 인증 링크 유효시간 설정 추가
|
||||
if (!isset($config['cf_email_certify_minutes'])) {
|
||||
sql_query("ALTER TABLE `{$g5['config_table']}`
|
||||
ADD `cf_email_certify_minutes` int(11) NOT NULL DEFAULT '60' AFTER `cf_use_email_certify`
|
||||
", true);
|
||||
|
||||
$is_check = true;
|
||||
}
|
||||
|
||||
//소셜 로그인 관련 필드 및 구글 리챕챠 필드 추가
|
||||
if(!isset($config['cf_social_login_use'])) {
|
||||
sql_query("ALTER TABLE `{$g5['config_table']}`
|
||||
|
||||
+18
-7
@@ -6,8 +6,9 @@ if(function_exists('check_mail_bot')){ check_mail_bot($_SERVER['REMOTE_ADDR']);
|
||||
|
||||
$mb_id = isset($_GET['mb_id']) ? trim($_GET['mb_id']) : '';
|
||||
$mb_md5 = isset($_GET['mb_md5']) ? trim($_GET['mb_md5']) : '';
|
||||
$esc_mb_id = sql_real_escape_string($mb_id);
|
||||
|
||||
$sql = " select mb_id, mb_email_certify2, mb_leave_date, mb_intercept_date from {$g5['member_table']} where mb_id = '{$mb_id}' ";
|
||||
$sql = " select mb_id, mb_datetime, mb_email_certify2, mb_leave_date, mb_intercept_date from {$g5['member_table']} where mb_id = '{$esc_mb_id}' ";
|
||||
$row = sql_fetch($sql);
|
||||
if (!$row['mb_id'])
|
||||
alert('존재하는 회원이 아닙니다.', G5_URL);
|
||||
@@ -16,21 +17,31 @@ if ( $row['mb_leave_date'] || $row['mb_intercept_date'] ){
|
||||
alert('탈퇴 또는 차단된 회원입니다.', G5_URL);
|
||||
}
|
||||
|
||||
// 인증 링크는 한번만 처리가 되게 한다.
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '' where mb_id = '$mb_id' ");
|
||||
|
||||
if ($mb_md5)
|
||||
{
|
||||
if ($mb_md5 == $row['mb_email_certify2'])
|
||||
$valid_minutes = isset($config['cf_email_certify_minutes']) ? (int) $config['cf_email_certify_minutes'] : 60;
|
||||
|
||||
if (is_valid_email_certify_token($mb_md5, $row['mb_email_certify2'], $row['mb_datetime'], $valid_minutes))
|
||||
{
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify = '".G5_TIME_YMDHIS."' where mb_id = '{$mb_id}' ");
|
||||
// 인증 링크는 한번만 처리되도록 인증과 동시에 토큰을 폐기한다.
|
||||
$esc_mb_md5 = sql_real_escape_string($mb_md5);
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify = '".G5_TIME_YMDHIS."', mb_email_certify2 = '' where mb_id = '{$esc_mb_id}' and mb_email_certify2 = '{$esc_mb_md5}' ");
|
||||
|
||||
if (get_sql_affected_rows() <= 0) {
|
||||
alert('이미 처리되었거나 올바르지 않은 메일인증 요청입니다.', G5_URL);
|
||||
}
|
||||
|
||||
alert("메일인증 처리를 완료 하였습니다.\\n\\n지금부터 {$mb_id} 아이디로 로그인 가능합니다.", G5_URL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($mb_md5 === $row['mb_email_certify2']) {
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '' where mb_id = '{$esc_mb_id}' ");
|
||||
alert('메일인증 유효시간이 만료되었습니다. 인증메일을 다시 요청해 주십시오.', G5_URL);
|
||||
}
|
||||
|
||||
alert('메일인증 요청 정보가 올바르지 않습니다.', G5_URL);
|
||||
}
|
||||
}
|
||||
|
||||
alert('제대로 된 값이 넘어오지 않았습니다.', G5_URL);
|
||||
alert('제대로 된 값이 넘어오지 않았습니다.', G5_URL);
|
||||
|
||||
@@ -46,7 +46,7 @@ $subject = '['.$config['cf_title'].'] 인증확인 메일입니다.';
|
||||
$mb_name = $mb['mb_name'];
|
||||
|
||||
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
|
||||
$mb_md5 = get_random_token_string(16);
|
||||
$mb_md5 = get_email_certify_token();
|
||||
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '{$esc_mb_id}' ");
|
||||
|
||||
@@ -62,4 +62,4 @@ mailer($config['cf_admin_email_name'], $config['cf_admin_email'], $mb_email, $su
|
||||
$sql = " update {$g5['member_table']} set mb_email = '$mb_email' where mb_id = '{$esc_mb_id}' ";
|
||||
sql_query($sql);
|
||||
|
||||
alert("인증메일을 {$mb_email} 메일로 다시 보내 드렸습니다.\\n\\n잠시후 {$mb_email} 메일을 확인하여 주십시오.", G5_URL);
|
||||
alert("인증메일을 {$mb_email} 메일로 다시 보내 드렸습니다.\\n\\n잠시후 {$mb_email} 메일을 확인하여 주십시오.", G5_URL);
|
||||
|
||||
@@ -325,7 +325,7 @@ if ($w == '') {
|
||||
|
||||
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
|
||||
if ($config['cf_use_email_certify']) {
|
||||
$mb_md5 = get_random_token_string(16);
|
||||
$mb_md5 = get_email_certify_token();
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '$mb_id' ");
|
||||
$certify_href = G5_BBS_URL.'/email_certify.php?mb_id='.$mb_id.'&mb_md5='.$mb_md5;
|
||||
}
|
||||
@@ -609,7 +609,7 @@ if ($config['cf_use_email_certify'] && $old_email != $mb_email) {
|
||||
$subject = '['.$config['cf_title'].'] 인증확인 메일입니다.';
|
||||
|
||||
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
|
||||
$mb_md5 = get_random_token_string(16);
|
||||
$mb_md5 = get_email_certify_token();
|
||||
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '$mb_id' ");
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
<p style="margin:20px 0 0;padding:30px 30px 50px;min-height:200px;height:auto !important;height:200px;border-bottom:1px solid #eee">
|
||||
<b><?php echo $mb_name ?></b> 님의 회원가입을 진심으로 축하합니다.<br>
|
||||
회원님의 성원에 보답하고자 더욱 더 열심히 하겠습니다.<br>
|
||||
<?php if ($config['cf_use_email_certify']) { ?>아래의 <strong>메일인증</strong>을 클릭하시면 회원가입이 완료됩니다.<br><?php } ?>
|
||||
<?php if ($config['cf_use_email_certify']) { ?>아래의 <strong>메일인증</strong>을 클릭하시면 회원가입이 완료됩니다.<br>
|
||||
<?php if (!empty($config['cf_email_certify_minutes'])) { ?>인증 링크는 발송 후 <?php echo (int) $config['cf_email_certify_minutes']; ?>분 동안 유효합니다.<br><?php } ?><?php } ?>
|
||||
감사합니다.
|
||||
</p>
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가
|
||||
<?php } ?>
|
||||
|
||||
아래의 주소를 클릭하시면 인증이 완료됩니다.<br>
|
||||
<?php if (!empty($config['cf_email_certify_minutes'])) { ?>인증 링크는 발송 후 <?php echo (int) $config['cf_email_certify_minutes']; ?>분 동안 유효합니다.<br><?php } ?>
|
||||
<a href="<?php echo $certify_href ?>" target="_blank"><b><?php echo $certify_href ?></b></a><br><br>
|
||||
|
||||
회원님의 성원에 보답하고자 더욱 더 열심히 하겠습니다.<br>
|
||||
|
||||
@@ -200,6 +200,7 @@ CREATE TABLE IF NOT EXISTS `g5_config` (
|
||||
`cf_point_term` int(11) NOT NULL DEFAULT '0',
|
||||
`cf_use_copy_log` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`cf_use_email_certify` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`cf_email_certify_minutes` int(11) NOT NULL DEFAULT '60',
|
||||
`cf_login_point` int(11) NOT NULL DEFAULT '0',
|
||||
`cf_cut_name` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`cf_nick_modify` int(11) NOT NULL DEFAULT '0',
|
||||
@@ -987,4 +988,4 @@ CREATE TABLE IF NOT EXISTS `g5_menu` (
|
||||
`me_use` tinyint(4) NOT NULL DEFAULT '0',
|
||||
`me_mobile_use` tinyint(4) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`me_id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
@@ -2696,6 +2696,54 @@ function get_email_cert_key($mb_id, $mb_datetime)
|
||||
return hash_hmac('sha256', $payload, $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 발급 시각을 포함한 메일 인증용 일회용 토큰을 생성한다.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function get_email_certify_token()
|
||||
{
|
||||
return get_random_token_string(16) . '.' . G5_SERVER_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* 메일 인증 토큰의 일치 여부와 유효시간을 확인한다.
|
||||
*
|
||||
* 발급 시각이 없는 기존 토큰은 회원가입 시각을 기준으로 만료 여부를 확인한다.
|
||||
*
|
||||
* @param string $token
|
||||
* @param string $stored_token
|
||||
* @param string $mb_datetime
|
||||
* @param int $valid_minutes
|
||||
* @param int|null $now
|
||||
* @return bool
|
||||
*/
|
||||
function is_valid_email_certify_token($token, $stored_token, $mb_datetime, $valid_minutes, $now = null)
|
||||
{
|
||||
if (!$token || !$stored_token || !hash_equals((string) $stored_token, (string) $token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$valid_minutes = (int) $valid_minutes;
|
||||
if ($valid_minutes < 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (preg_match('/\.([0-9]{10})$/', $stored_token, $matches)) {
|
||||
$issued_at = (int) $matches[1];
|
||||
} else {
|
||||
$issued_at = strtotime($mb_datetime);
|
||||
}
|
||||
|
||||
if (!$issued_at) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$now = $now === null ? G5_SERVER_TIME : (int) $now;
|
||||
|
||||
return $issued_at + ($valid_minutes * 60) >= $now;
|
||||
}
|
||||
|
||||
/**
|
||||
* CSRF 방지용 Origin/Referer 검증 (OWASP 권장 패턴).
|
||||
*
|
||||
|
||||
@@ -273,7 +273,7 @@ if($result) {
|
||||
$subject = '['.$config['cf_title'].'] 인증확인 메일입니다.';
|
||||
|
||||
// 어떠한 회원정보도 포함되지 않은 일회용 난수를 생성하여 인증에 사용 (CSPRNG 사용)
|
||||
$mb_md5 = get_random_token_string(16);
|
||||
$mb_md5 = get_email_certify_token();
|
||||
|
||||
sql_query(" update {$g5['member_table']} set mb_email_certify2 = '$mb_md5' where mb_id = '$mb_id' ");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user