feat(security): 비밀번호 정책 강화 — 8자+영문·숫자·특수 3종 + 안내문구
- 회원가입·비밀번호 변경·관리자 회원 등록/수정에 정책 적용 - 정규식 규칙을 배열 형식으로 적용(파이프 파싱 깨짐 → is_unique 등 검증 무력화 버그 수정) - 비밀번호 입력란에 형식 안내문구 추가 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -19,14 +19,15 @@ class PasswordChange extends BaseController
|
|||||||
helper('admin');
|
helper('admin');
|
||||||
$rules = [
|
$rules = [
|
||||||
'current_password' => 'required',
|
'current_password' => 'required',
|
||||||
'new_password' => 'required|min_length[4]|max_length[255]',
|
'new_password' => ['required', 'min_length[8]', 'max_length[255]', 'regex_match[/^(?=.*[A-Za-z])(?=.*\d)(?=.*[\W_]).+$/]'],
|
||||||
'new_password_confirm' => 'required|matches[new_password]',
|
'new_password_confirm' => 'required|matches[new_password]',
|
||||||
];
|
];
|
||||||
$messages = [
|
$messages = [
|
||||||
'current_password' => ['required' => '현재 비밀번호를 입력해 주세요.'],
|
'current_password' => ['required' => '현재 비밀번호를 입력해 주세요.'],
|
||||||
'new_password' => [
|
'new_password' => [
|
||||||
'required' => '새 비밀번호를 입력해 주세요.',
|
'required' => '새 비밀번호를 입력해 주세요.',
|
||||||
'min_length' => '비밀번호는 4자 이상이어야 합니다.',
|
'min_length' => '비밀번호는 8자 이상이어야 합니다.',
|
||||||
|
'regex_match' => '비밀번호는 영문·숫자·특수문자를 모두 포함해야 합니다.',
|
||||||
],
|
],
|
||||||
'new_password_confirm' => [
|
'new_password_confirm' => [
|
||||||
'required' => '비밀번호 확인을 입력해 주세요.',
|
'required' => '비밀번호 확인을 입력해 주세요.',
|
||||||
|
|||||||
@@ -83,13 +83,13 @@ class User extends BaseController
|
|||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
'mb_id' => 'required|min_length[2]|max_length[50]|is_unique[member.mb_id]',
|
'mb_id' => 'required|min_length[2]|max_length[50]|is_unique[member.mb_id]',
|
||||||
'mb_passwd' => 'required|min_length[4]|max_length[255]',
|
'mb_passwd' => ['required', 'min_length[8]', 'max_length[255]', 'regex_match[/^(?=.*[A-Za-z])(?=.*\d)(?=.*[\W_]).+$/]'],
|
||||||
'mb_name' => 'required|max_length[50]',
|
'mb_name' => 'required|max_length[50]',
|
||||||
'mb_email' => 'permit_empty|valid_email|max_length[100]',
|
'mb_email' => 'permit_empty|valid_email|max_length[100]',
|
||||||
'mb_phone' => 'permit_empty|max_length[20]',
|
'mb_phone' => 'permit_empty|max_length[20]',
|
||||||
'mb_level' => 'required',
|
'mb_level' => 'required',
|
||||||
];
|
];
|
||||||
if (! $this->validate($rules)) {
|
if (! $this->validate($rules, ['mb_passwd' => ['min_length' => '비밀번호는 8자 이상이어야 합니다.', 'regex_match' => '비밀번호는 영문·숫자·특수문자를 모두 포함해야 합니다.']])) {
|
||||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||||
}
|
}
|
||||||
$allowedLevels = array_keys($this->getAssignableLevels());
|
$allowedLevels = array_keys($this->getAssignableLevels());
|
||||||
@@ -154,9 +154,9 @@ class User extends BaseController
|
|||||||
];
|
];
|
||||||
$passwd = $this->request->getPost('mb_passwd');
|
$passwd = $this->request->getPost('mb_passwd');
|
||||||
if ($passwd !== '') {
|
if ($passwd !== '') {
|
||||||
$rules['mb_passwd'] = 'min_length[4]|max_length[255]';
|
$rules['mb_passwd'] = ['min_length[8]', 'max_length[255]', 'regex_match[/^(?=.*[A-Za-z])(?=.*\d)(?=.*[\W_]).+$/]'];
|
||||||
}
|
}
|
||||||
if (! $this->validate($rules)) {
|
if (! $this->validate($rules, ['mb_passwd' => ['min_length' => '비밀번호는 8자 이상이어야 합니다.', 'regex_match' => '비밀번호는 영문·숫자·특수문자를 모두 포함해야 합니다.']])) {
|
||||||
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
|
||||||
}
|
}
|
||||||
$allowedLevels = array_keys($this->getAssignableLevels());
|
$allowedLevels = array_keys($this->getAssignableLevels());
|
||||||
|
|||||||
@@ -357,7 +357,7 @@ class Auth extends BaseController
|
|||||||
{
|
{
|
||||||
$rules = [
|
$rules = [
|
||||||
'mb_id' => 'required|min_length[4]|max_length[50]|is_unique[member.mb_id]',
|
'mb_id' => 'required|min_length[4]|max_length[50]|is_unique[member.mb_id]',
|
||||||
'mb_passwd' => 'required|min_length[4]|max_length[255]',
|
'mb_passwd' => ['required', 'min_length[8]', 'max_length[255]', 'regex_match[/^(?=.*[A-Za-z])(?=.*\d)(?=.*[\W_]).+$/]'],
|
||||||
'mb_passwd_confirm' => 'required|matches[mb_passwd]',
|
'mb_passwd_confirm' => 'required|matches[mb_passwd]',
|
||||||
'mb_name' => 'required|max_length[100]',
|
'mb_name' => 'required|max_length[100]',
|
||||||
'mb_email' => 'permit_empty|valid_email|max_length[100]',
|
'mb_email' => 'permit_empty|valid_email|max_length[100]',
|
||||||
@@ -374,9 +374,10 @@ class Auth extends BaseController
|
|||||||
'is_unique' => '이미 사용 중인 아이디입니다.',
|
'is_unique' => '이미 사용 중인 아이디입니다.',
|
||||||
],
|
],
|
||||||
'mb_passwd' => [
|
'mb_passwd' => [
|
||||||
'required' => '비밀번호를 입력해 주세요.',
|
'required' => '비밀번호를 입력해 주세요.',
|
||||||
'min_length' => '비밀번호는 4자 이상이어야 합니다.',
|
'min_length' => '비밀번호는 8자 이상이어야 합니다.',
|
||||||
'max_length' => '비밀번호는 255자 이하여야 합니다.',
|
'max_length' => '비밀번호는 255자 이하여야 합니다.',
|
||||||
|
'regex_match' => '비밀번호는 영문·숫자·특수문자를 모두 포함해야 합니다.',
|
||||||
],
|
],
|
||||||
'mb_passwd_confirm' => [
|
'mb_passwd_confirm' => [
|
||||||
'required' => '비밀번호 확인을 입력해 주세요.',
|
'required' => '비밀번호 확인을 입력해 주세요.',
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-32">새 비밀번호 <span class="text-red-500">*</span></label>
|
<label class="block text-sm font-bold text-gray-700 w-32">새 비밀번호 <span class="text-red-500">*</span></label>
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-60" name="new_password" type="password" required autocomplete="new-password"/>
|
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-60" name="new_password" type="password" required autocomplete="new-password"/>
|
||||||
|
<p class="w-full text-xs text-gray-500 pl-32">8자 이상, 영문·숫자·특수문자를 모두 포함해야 합니다.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-20">비밀번호 <span class="text-red-500">*</span></label>
|
<label class="block text-sm font-bold text-gray-700 w-20">비밀번호 <span class="text-red-500">*</span></label>
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-48" id="mb_passwd" name="mb_passwd" type="password" required/>
|
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-48" id="mb_passwd" name="mb_passwd" type="password" required/>
|
||||||
|
<p class="w-full text-xs text-gray-500 pl-20">8자 이상, 영문·숫자·특수문자를 모두 포함해야 합니다.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-20">이름 <span class="text-red-500">*</span></label>
|
<label class="block text-sm font-bold text-gray-700 w-20">이름 <span class="text-red-500">*</span></label>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ $editLoginLocked = $editLockUntil !== null && $editLockUntil !== '' && strtotime
|
|||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-20">비밀번호</label>
|
<label class="block text-sm font-bold text-gray-700 w-20">비밀번호</label>
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-48" id="mb_passwd" name="mb_passwd" type="password" placeholder="변경 시에만 입력"/>
|
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-48" id="mb_passwd" name="mb_passwd" type="password" placeholder="변경 시에만 입력"/>
|
||||||
|
<p class="w-full text-xs text-gray-500 pl-20">변경 시 8자 이상, 영문·숫자·특수문자를 모두 포함해야 합니다.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-20">이름 <span class="text-red-500">*</span></label>
|
<label class="block text-sm font-bold text-gray-700 w-20">이름 <span class="text-red-500">*</span></label>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd">비밀번호 <span class="text-red-500">*</span></label>
|
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd">비밀번호 <span class="text-red-500">*</span></label>
|
||||||
<input class="<?= $inputCls ?>" id="mb_passwd" name="mb_passwd" type="password" autocomplete="new-password"/>
|
<input class="<?= $inputCls ?>" id="mb_passwd" name="mb_passwd" type="password" autocomplete="new-password"/>
|
||||||
|
<p class="mt-1 text-xs text-gray-500">8자 이상, 영문·숫자·특수문자를 모두 포함해야 합니다.</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd_confirm">비밀번호 확인 <span class="text-red-500">*</span></label>
|
<label class="block text-sm font-bold text-gray-700 mb-1" for="mb_passwd_confirm">비밀번호 확인 <span class="text-red-500">*</span></label>
|
||||||
|
|||||||
Reference in New Issue
Block a user