Issue 1816 Defence infinite loop of ID/Password insertion test.

git-svn-id: http://xe-core.googlecode.com/svn/branches/1.5.0@10793 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
misol 2012-06-25 14:49:18 +00:00
parent 19a7be5b1f
commit f8ae6f9885
7 changed files with 200 additions and 38 deletions

View file

@ -155,6 +155,10 @@
<value xml:lang="tr"><![CDATA[Hesap etkinleştirilmemiş.]]></value>
<value xml:lang="vi"><![CDATA[Tài khoản đăng nhập không đúng.]]></value>
</item>
<item name="invalid_email_address">
<value xml:lang="ko"><![CDATA[이메일 주소와 일치하는 회원이 없습니다.]]></value>
<value xml:lang="en"><![CDATA[You have entered an invalid email address. There is no member who has the email, entered.]]></value>
</item>
<item name="invalid_user_id">
<value xml:lang="ko"><![CDATA[존재하지 않는 회원 아이디입니다.]]></value>
<value xml:lang="en"><![CDATA[You have entered an invalid ID.]]></value>
@ -2234,6 +2238,22 @@ Bạn có thể quản lý thành viên bằng cách tạo những nhóm mới,
<value xml:lang="zh-TW"><![CDATA[可設定密碼更新週期,將會定期通知更換密碼。 (設為零則不使用)]]></value>
<value xml:lang="tr"><![CDATA[Eğer buna bir değer biçerseniz, şifrenizi belirli aralıklarla değiştirmeniz konusunda bildirim alacaksanız (eğer 0 olarak ayarlandıysa, devredışıdır)]]></value>
</item>
<item name="login_trial_limit1">
<value xml:lang="ko"><![CDATA[로그인 시도 횟수 제한 횟수]]></value>
<value xml:lang="en"><![CDATA[Sign in trial limit]]></value>
</item>
<item name="login_trial_limit2">
<value xml:lang="ko"><![CDATA[로그인 시도 횟수 제한 시간]]></value>
<value xml:lang="en"><![CDATA[Sign in trial limit]]></value>
</item>
<item name="about_login_trial_limit1">
<value xml:lang="ko"><![CDATA[정해진 시간 안에 허용되는 로그인 횟수를 입력하십시오. 짧은 시간 동안 하나의 아이피(IP)에서 시도할 수 있는 로그인 횟수에 제한을 둡니다.]]></value>
<value xml:lang="en"><![CDATA[Set the number of trial limit. Limit the number of trial to sign in from a IP address.]]></value>
</item>
<item name="about_login_trial_limit2">
<value xml:lang="ko"><![CDATA[지정된 횟수의 로그인을 허용하는 시간을 정하십시오. 짧은 시간 동안 하나의 아이피(IP)에서 시도할 수 있는 로그인 횟수에 제한을 둡니다.]]></value>
<value xml:lang="en"><![CDATA[Set the time limit to try the written times of sign in. Limit the number of trial to sign in during the span of time, from a IP address.]]></value>
</item>
<item name="msg_kr_address">
<value xml:lang="ko"><![CDATA[읍, 면, 동 이름으로 검색하세요.]]></value>
<value xml:lang="en"><![CDATA[Search for the name of eup, myeon or dong of your address.]]></value>
@ -2467,9 +2487,22 @@ Bạn có thể quản lý thành viên bằng cách tạo những nhóm mới,
<value xml:lang="ko"><![CDATA[이메일 주소가 정상적으로 변경되었습니다. 변경된 이메일 주소로 로그인 가능합니다.]]></value>
</item>
<item name="group">
<value xml:lang="en"><![CDATA[그룹]]></value>
<value xml:lang="en"><![CDATA[Group]]></value>
</item>
<item name="retrieve_password">
<value xml:lang="en"><![CDATA[Retrieve password]]></value>
</item>
<item name="excess_ip_access_count">
<value xml:lang="ko"><![CDATA[로그인 가능 횟수를 초과하셨습니다. %s 간 로그인 하실 수 없습니다.]]></value>
<value xml:lang="en"><![CDATA[There was too much sign in trial from your devices in a short time. You can not sign in for %s.]]></value>
</item>
<item name="login_fail_report">
<value xml:lang="ko"><![CDATA[로그인 실패 기록 보고 입니다.]]></value>
<value xml:lang="en"><![CDATA[Sign in failure report.]]></value>
</item>
<item name="login_fail_report_contents">
<value xml:lang="ko"><![CDATA[<h2>확인하지 않은 로그인 실패 기록이 있습니다.</h2><div>%1$s</div><p>* 이 알림은 한번만 보입니다.<br />* 이 메시지는 쪽지와 이메일로 발송됩니다.<br />* 이 메시지는 로그인이 성공한 순간, 로그인 성공 이전 실패 기록을 모아서 발송합니다.<br />발송 시각: %2$s</p>]]></value>
<value xml:lang="en"><![CDATA[<h2>There is unfolded sign in failure report</h2><div>%1$s</div><p>* This notification is shown once.<br />* This message will be send to your email and message.<br />* This message contains sign in failure records, before a ID sign in success.<br />Sending: %2$s</p>]]></value>
</item>
</lang>

View file

@ -133,6 +133,7 @@
'webmaster_email',
'limit_day',
'change_password_date',
'max_error_count','max_error_count_time',
'agreement',
'after_login_url',
'after_logout_url',

View file

@ -337,5 +337,56 @@
$store = new Auth_OpenID_XEStore();
$store->reset();
}
}
/**
* @brief Record login error and return the error, about IPaddress.
**/
function recordLoginError($error = 0, $message = 'success')
{
if($error == 0) return new Object($error, $message);
$args->ipaddress = $_SERVER['REMOTE_ADDR'];
$output = executeQuery('member.getLoginCountByIp', $args);
if($output->data && $output->data->count)
{
//update
$args->count = $output->data->count + 1;
$output = executeQuery('member.updateLoginCountByIp', $args);
}
else
{
//insert
$args->count = 1;
$output = executeQuery('member.insertLoginCountByIp', $args);
}
return new Object($error, $message);
}
/**
* @brief Record login error and return the error, about MemberSrl.
**/
function recordMemberLoginError($error = 0, $message = 'success', $args = NULL)
{
if($error == 0 || !$args->member_srl) return new Object($error, $message);
$output = executeQuery('member.getLoginCountHistoryByMemberSrl', $args);
if($output->data && $output->data->content)
{
//update
$content = unserialize($output->data->content);
$content[] = array($_SERVER['REMOTE_ADDR'],Context::getLang($message),time());
$args->content = serialize($content);
$output = executeQuery('member.updateLoginCountHistoryByMemberSrl', $args);
}
else
{
//insert
$content[0] = array($_SERVER['REMOTE_ADDR'],Context::getLang($message),time());
$args->content = serialize($content);
$output = executeQuery('member.insertLoginCountHistoryByMemberSrl', $args);
}
return $this->recordLoginError($error, $message);
}
}
?>

View file

@ -1516,47 +1516,111 @@
}
}
/**
* @brief Log-in
**/
function doLogin($user_id, $password = '', $keep_signed = false) {
$user_id = strtolower($user_id);
// Call a trigger before log-in (before)
$trigger_obj->user_id = $user_id;
$trigger_obj->password = $password;
$trigger_output = ModuleHandler::triggerCall('member.doLogin', 'before', $trigger_obj);
if(!$trigger_output->toBool()) return $trigger_output;
// Create a member model object
$oMemberModel = &getModel('member');
/**
* @brief Log-in
**/
function doLogin($user_id, $password = '', $keep_signed = false) {
$user_id = strtolower($user_id);
if(!$user_id) return new Object(-1, 'null_user_id');
// Call a trigger before log-in (before)
$trigger_obj->user_id = $user_id;
$trigger_obj->password = $password;
$trigger_output = ModuleHandler::triggerCall('member.doLogin', 'before', $trigger_obj);
if(!$trigger_output->toBool()) return $trigger_output;
// Create a member model object
$oMemberModel = &getModel('member');
// check identifier
$config = $oMemberModel->getMemberConfig();
if ($config->identifier == 'email_address'){
// Get user_id information
$this->memberInfo = $oMemberModel->getMemberInfoByEmailAddress($user_id);
// Set an invalid user if no value returned
if(!$user_id || strtolower($this->memberInfo->email_address) != strtolower($user_id)) return new Object(-1, 'invalid_email_address');
// check IP access count.
$config = $oMemberModel->getMemberConfig();
$args->ipaddress = $_SERVER['REMOTE_ADDR'];
$output = executeQuery('member.getLoginCountByIp', $args);
$count = (int)$output->data->count;
if($config->max_error_count < $count)
{
$last_update = $output->data->last_update;
$year = substr($last_update,0,4);
$month = substr($last_update,4,2);
$day = substr($last_update,6,2);
$hour = substr($last_update,8,2);
$min = substr($last_update,10,2);
$sec = substr($last_update,12,2);
$last_update = mktime($hour,$min,$sec,$month,$day,$year);
$term = intval(time()-$last_update);
if($term < $config->max_error_count_time)
{
$term = $config->max_error_count_time - $term;
if($term < 60) $term = intval($term).Context::getLang('unit_sec');
elseif(60 <= $term && $term < 3600) $term = intval($term/60).Context::getLang('unit_min');
elseif(3600 <= $term && $term < 86400) $term = intval($term/3600).Context::getLang('unit_hour');
else $term = intval($term/86400).Context::getLang('unit_day');
return new Object(-1, sprintf(Context::getLang('excess_ip_access_count'),$term));
}
else
{
$args->ipaddress = $_SERVER['REMOTE_ADDR'];
$output = executeQuery('member.deleteLoginCountByIp', $args);
}
}
}else{
// Get user_id information
$this->memberInfo = $oMemberModel->getMemberInfoByUserID($user_id);
// Set an invalid user if no value returned
if(!$user_id || strtolower($this->memberInfo->user_id) != strtolower($user_id)) return new Object(-1, 'invalid_user_id');
}
// Password Check
if($password && !$oMemberModel->isValidPassword($this->memberInfo->password, $password, $this->memberInfo->member_srl)) return new Object(-1, 'invalid_password');
// If denied == 'Y', notify
if($this->memberInfo->denied == 'Y') {
$args->member_srl = $this->memberInfo->member_srl;
$output = executeQuery('member.chkAuthMail', $args);
if ($output->toBool() && $output->data->count != '0') return new Object(-1,'msg_user_not_confirmed');
return new Object(-1,'msg_user_denied');
}
// Notify if denied_date is less than the current time
if($this->memberInfo->limit_date && substr($this->memberInfo->limit_date,0,8) >= date("Ymd")) return new Object(-1,sprintf(Context::getLang('msg_user_limited'),zdate($this->memberInfo->limit_date,"Y-m-d")));
// check identifier
if ($config->identifier == 'email_address'){
// Get user_id information
$this->memberInfo = $oMemberModel->getMemberInfoByEmailAddress($user_id);
// Set an invalid user if no value returned
if(!$user_id || strtolower($this->memberInfo->email_address) != strtolower($user_id)) return $this->recordLoginError(-1, 'invalid_email_address');
}else{
// Get user_id information
$this->memberInfo = $oMemberModel->getMemberInfoByUserID($user_id);
// Set an invalid user if no value returned
if(!$user_id || strtolower($this->memberInfo->user_id) != strtolower($user_id)) return $this->recordLoginError(-1, 'invalid_user_id');
}
// Password Check
if($password && !$oMemberModel->isValidPassword($this->memberInfo->password, $password, $this->memberInfo->member_srl)) return $this->recordMemberLoginError(-1, 'invalid_password',$this->memberInfo);
// If denied == 'Y', notify
if($this->memberInfo->denied == 'Y') {
$args->member_srl = $this->memberInfo->member_srl;
$output = executeQuery('member.chkAuthMail', $args);
if ($output->toBool() && $output->data->count != '0') return new Object(-1,'msg_user_not_confirmed');
return new Object(-1,'msg_user_denied');
}
// Notify if denied_date is less than the current time
if($this->memberInfo->limit_date && substr($this->memberInfo->limit_date,0,8) >= date("Ymd")) return new Object(-1,sprintf(Context::getLang('msg_user_limited'),zdate($this->memberInfo->limit_date,"Y-m-d")));
// Update the latest login time
$args->member_srl = $this->memberInfo->member_srl;
$output = executeQuery('member.updateLastLogin', $args);
// check if there is login fail records.
$output = executeQuery('member.getLoginCountHistoryByMemberSrl', $args);
if($output->data && $output->data->content)
{
$title = Context::getLang('login_fail_report');
$message = '<ul>';
$content = unserialize($output->data->content);
foreach($content as $val)
{
$message .= '<li>'.date('Y-m-d H:i:s P',$val[2]).'<br /> Access IP: '.$val[0].'<br /> Message: '.$val[1].'</li>';
}
$message .= '</ul>';
$content = sprintf(Context::getLang('login_fail_report_contents'),$message,date('Y-m-d H:i:s P'));
//send message
$oCommunicationController = &getController('communication');
$oCommunicationController->sendMessage($args->member_srl, $args->member_srl, $title, $content, true);
if($this->memberInfo->email_address && $this->memberInfo->allow_mailing == 'Y')
{
$view_url = Context::getRequestUri();
$title = sprintf("%s @ %s",$title,$view_url);
$content = sprintf("%s<hr /><p>From: <a href=\"%s\" target=\"_blank\">%s</a><br />To: %s(%s)</p>",$content, $view_url, $view_url, $this->memberInfo->nick_name, $this->memberInfo->email_id);
$oMail = new Mail();
$oMail->setTitle($title);
$oMail->setContent($content);
$oMail->setSender($this->memberInfo->email_id.'('.$this->memberInfo->nick_name.')', $this->memberInfo->email_address);
$oMail->setReceiptor($this->memberInfo->email_id.'('.$this->memberInfo->nick_name.')', $this->memberInfo->email_address);
$oMail->send();
}
$output = executeQuery('member.deleteLoginCountHistoryByMemberSrl', $args);
}
// Call a trigger after successfully log-in (after)
$trigger_output = ModuleHandler::triggerCall('member.doLogin', 'after', $this->memberInfo);
if(!$trigger_output->toBool()) return $trigger_output;
@ -1567,7 +1631,7 @@
$autologin_args->member_srl = $this->memberInfo->member_srl;
executeQuery('member.deleteAutologin', $autologin_args);
$autologin_output = executeQuery('member.insertAutologin', $autologin_args);
if($autologin_output->toBool()) setCookie('xeak',$autologin_args->autologin_key, time()+60*60*24*365, '/');
if($autologin_output->toBool()) setCookie('xeak',$autologin_args->autologin_key, time()+31536000, '/');
}
if($this->memberInfo->is_admin == 'Y') {
$oMemberAdminModel = &getAdminModel('member');

View file

@ -51,6 +51,9 @@
if (!$config->identifier) $config->identifier = 'user_id';
if (!$config->max_error_count) $config->max_error_count = 10;
if (!$config->max_error_count_time) $config->max_error_count_time = 300;
return $config;
}

View file

@ -5,5 +5,7 @@
<fields>
<field name="webmaster_name" required="true" length="2:40" />
<field name="webmaster_email" length="1:200" rule="email" />
<field name="max_error_count" length="1:20" rule="number" />
<field name="max_error_count_time" length="1:20" rule="number" />
</fields>
</ruleset>

View file

@ -51,6 +51,14 @@
<p class="q"><label for="change_password_date">{$lang->change_password_date}</label></p>
<p class="a"><input type="text" id="change_password_date" name="change_password_date" value="{$config->change_password_date}" style="width:30px" /><span class="desc">{$lang->unit_day}({$lang->about_change_password_date})</span></p>
</li>
<li>
<p class="q"><label for="max_error_count">{$lang->login_trial_limit1}</label></p>
<p class="a"><input type="text" id="max_error_count" name="max_error_count" value="{$config->max_error_count}" style="width:30px" /><span class="desc">{$lang->about_login_trial_limit1}</span></p>
</li>
<li>
<p class="q"><label for="max_error_count_time">{$lang->login_trial_limit2}</label></p>
<input type="text" id="max_error_count_time" name="max_error_count_time" value="{$config->max_error_count_time}" style="width:30px" /><span class="desc">{$lang->unit_sec}({$lang->about_login_trial_limit2})</span></p>
</li>
<li>
<p class="q"><label for="agreement">{$lang->agreement}</label></p>
<p class="a">{$editor}</p>