[security]회원 ID/이메일 열거 공격 차단
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
include_once('./_common.php');
|
||||
include_once(G5_LIB_PATH.'/register.lib.php');
|
||||
|
||||
// 회원 ID 열거 공격 방지를 위한 Rate Limit (분당 30회)
|
||||
if (function_exists('check_rate_limit') && !check_rate_limit('ajax_mb_id_check', 30, 60)) {
|
||||
die('너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해 주세요.');
|
||||
}
|
||||
|
||||
$mb_id = isset($_POST['reg_mb_id']) ? trim($_POST['reg_mb_id']) : '';
|
||||
|
||||
set_session('ss_check_mb_id', '');
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
include_once('./_common.php');
|
||||
include_once(G5_LIB_PATH.'/register.lib.php');
|
||||
|
||||
// 회원 닉네임 열거 공격 방지를 위한 Rate Limit (분당 30회)
|
||||
if (function_exists('check_rate_limit') && !check_rate_limit('ajax_mb_nick_check', 30, 60)) {
|
||||
die('너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해 주세요.');
|
||||
}
|
||||
|
||||
$mb_nick = isset($_POST['reg_mb_nick']) ? trim($_POST['reg_mb_nick']) : '';
|
||||
$mb_id = isset($_POST['reg_mb_id']) ? trim($_POST['reg_mb_id']) : '';
|
||||
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
include_once("./_common.php");
|
||||
include_once(G5_LIB_PATH."/register.lib.php");
|
||||
|
||||
// 추천인 ID 열거 공격 방지를 위한 Rate Limit (분당 30회)
|
||||
if (function_exists('check_rate_limit') && !check_rate_limit('ajax_mb_recommend_check', 30, 60)) {
|
||||
die('너무 많은 요청이 발생했습니다. 잠시 후 다시 시도해 주세요.');
|
||||
}
|
||||
|
||||
$mb_recommend = isset($_POST["reg_mb_recommend"]) ? trim($_POST["reg_mb_recommend"]) : '';
|
||||
|
||||
if ($msg = valid_mb_id($mb_recommend)) {
|
||||
|
||||
+14
-7
@@ -16,17 +16,24 @@ $email = get_email_address(trim($_POST['mb_email']));
|
||||
if (!$email)
|
||||
alert_close('메일주소 오류입니다.');
|
||||
|
||||
// OWASP 권장: 이메일 존재 여부와 무관하게 동일한 응답 메시지 사용
|
||||
// (이메일 열거 공격 방지)
|
||||
$generic_message = $email.' 메일로 회원아이디와 비밀번호를 인증할 수 있는 메일이 발송 되었습니다.\\n\\n메일을 확인하여 주십시오.';
|
||||
|
||||
$sql = " select count(*) as cnt from {$g5['member_table']} where mb_email = '$email' ";
|
||||
$row = sql_fetch($sql);
|
||||
if ($row['cnt'] > 1)
|
||||
alert('동일한 메일주소가 2개 이상 존재합니다.\\n\\n관리자에게 문의하여 주십시오.');
|
||||
if ($row['cnt'] > 1) {
|
||||
// 시스템 데이터 무결성 이슈 - 운영자 로그에만 기록하고 사용자에겐 일반 메시지
|
||||
@error_log("[g5 password_lost2] Duplicate email detected: $email (count={$row['cnt']})");
|
||||
alert_close($generic_message);
|
||||
}
|
||||
|
||||
$sql = " select mb_no, mb_id, mb_name, mb_nick, mb_email, mb_datetime, mb_leave_date from {$g5['member_table']} where mb_email = '$email' ";
|
||||
$mb = sql_fetch($sql);
|
||||
if (empty($mb['mb_id']) || $mb['mb_leave_date']) {
|
||||
alert('존재하지 않는 회원입니다.');
|
||||
} elseif (is_admin($mb['mb_id'])) {
|
||||
alert('관리자 아이디는 접근 불가합니다.');
|
||||
|
||||
// 회원이 없거나 탈퇴했거나 관리자이면 메일 발송 없이 동일한 메시지로 응답
|
||||
if (empty($mb['mb_id']) || $mb['mb_leave_date'] || is_admin($mb['mb_id'])) {
|
||||
alert_close($generic_message);
|
||||
}
|
||||
|
||||
// 임시비밀번호 발급
|
||||
@@ -74,4 +81,4 @@ mailer($config['cf_admin_email_name'], $config['cf_admin_email'], $mb['mb_email'
|
||||
|
||||
run_event('password_lost2_after', $mb, $mb_nonce, $mb_lost_certify);
|
||||
|
||||
alert_close($email.' 메일로 회원아이디와 비밀번호를 인증할 수 있는 메일이 발송 되었습니다.\\n\\n메일을 확인하여 주십시오.');
|
||||
alert_close($generic_message);
|
||||
@@ -2531,6 +2531,34 @@ function check_token()
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 세션 기반 단순 Rate Limit. 자동화 도구의 무차별 호출을 늦추기 위한 용도.
|
||||
*
|
||||
* 같은 키에 대해 $window 초 동안 $max 회까지만 허용. 초과 시 false 반환.
|
||||
* 세션 쿠키를 무시하는 정교한 봇은 우회 가능하지만, 세션 생성 비용으로 attack rate가 떨어지고
|
||||
* 가장 흔한 form-only enumeration 시나리오는 효과적으로 차단된다.
|
||||
*
|
||||
* @param string $key 레이트 리밋 식별자 (예: 'ajax_mb_id_check')
|
||||
* @param int $max 윈도우당 최대 허용 횟수
|
||||
* @param int $window 윈도우 크기 (초)
|
||||
* @return bool true = 허용, false = 차단
|
||||
*/
|
||||
function check_rate_limit($key, $max = 30, $window = 60)
|
||||
{
|
||||
$session_key = 'ss_rate_' . $key;
|
||||
$now = time();
|
||||
|
||||
$data = get_session($session_key);
|
||||
if (!is_array($data) || !isset($data['reset']) || $data['reset'] < $now) {
|
||||
$data = array('count' => 0, 'reset' => $now + $window);
|
||||
}
|
||||
|
||||
$data['count']++;
|
||||
set_session($session_key, $data);
|
||||
|
||||
return $data['count'] <= $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* 이메일 미인증 회원의 메일주소 변경 페이지 접근 토큰을 생성한다.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user