security: KVE-2026-2330 비회원 게시물 수정 인증과 토큰 발급 검증 강화
기존 비밀번호 확인 이력을 게시판·게시물·비밀번호에 결합하고 저장 전 검증한다. 인증은 30분 후 만료되며 저장 후 폐기한다. 일반 쓰기 토큰과 답변 세션으로 수정 인증을 대체할 수 없도록 한다. 1:1문의 토큰 발급을 로그인 회원의 해당 용도로 제한하고 게시판 토큰의 요청 경로와 대상을 확인한다. 최고관리자의 그누보드4 자료 이전은 유지한다. 검증: 비인증 수정 차단, 정상 비밀번호 변경 및 인증 폐기, 토큰 발급 엔드포인트 격리 검증과 PHP 문법 검사 통과.
This commit is contained in:
1 parent
fcc749bde3
commit
65875b7f35
5 files changed
+77
-37
No files matched your search
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
include_once('./_common.php');
|
||||
|
||||
$token_case = isset($_POST['token_case']) ? preg_replace('/[^0-9a-z_]/i', '', $_POST['token_case']) : '';
|
||||
|
||||
if( $token_case ){
|
||||
$token = _token();
|
||||
set_session('ss_'.$token_case.'_token', $token);
|
||||
die(json_encode(array('error'=>'', 'token'=>$token, 'url'=>'')));
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !$is_member ||
|
||||
!isset($_POST['token_case']) || $_POST['token_case'] !== 'qa_write') {
|
||||
die(json_encode(array('error'=>'올바른 방법으로 이용해 주십시오.', 'token'=>'', 'url'=>'')));
|
||||
}
|
||||
|
||||
check_request_origin();
|
||||
$token = _token();
|
||||
set_session('ss_qa_write_token', $token);
|
||||
die(json_encode(array('error'=>'', 'token'=>$token, 'url'=>'')));
|
||||
@@ -309,12 +309,15 @@ if ($w == '') {
|
||||
$password_required = 'required';
|
||||
} else if ($w == 'u') {
|
||||
$password_required = '';
|
||||
set_session(g5_write_edit_auth_key($bo_table, $wr_id), '');
|
||||
|
||||
if (!$is_admin) {
|
||||
if (!($is_member && $member['mb_id'] === $write['mb_id'])) {
|
||||
if (!check_password($wr_password, $write['wr_password'])) {
|
||||
$is_wrong = run_replace('invalid_password', false, 'write', $write);
|
||||
if(!$is_wrong) alert('비밀번호가 틀립니다.');
|
||||
} else if (empty($write['mb_id'])) {
|
||||
g5_grant_write_edit_auth($bo_table, $write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -1,9 +1,14 @@
|
||||
<?php
|
||||
include_once('./_common.php');
|
||||
|
||||
if(!$bo_table)
|
||||
// 그누보드4 자료 이전은 최고관리자에게만 허용되는 별도 용도이다.
|
||||
$is_import_token = $bo_table === 'g4_import' && $is_admin === 'super';
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !$bo_table ||
|
||||
(!$is_import_token && (empty($board['bo_table']) || $board['bo_table'] !== $bo_table)))
|
||||
die(json_encode(array('error'=>'게시판 정보가 올바르지 않습니다.', 'url'=>G5_URL)));
|
||||
|
||||
check_request_origin();
|
||||
|
||||
set_session('ss_write_'.$bo_table.'_token', '');
|
||||
|
||||
$token = get_write_token($bo_table);
|
||||
|
||||
+35
-28
@@ -96,6 +96,39 @@ if ($w == 'u' || $w == 'r') {
|
||||
}
|
||||
}
|
||||
|
||||
// 수정 권한은 스킨 및 저장 처리 전에 검증한다.
|
||||
if ($w == 'u') {
|
||||
if (($is_member || $is_admin) && (get_session('ss_bo_table') != $bo_table || get_session('ss_wr_id') != $wr_id)) {
|
||||
alert('올바른 방법으로 수정하여 주십시오.', get_pretty_url($bo_table));
|
||||
}
|
||||
|
||||
$return_url = get_pretty_url($bo_table, $wr_id);
|
||||
|
||||
if ($is_admin == 'super') // 최고관리자 통과
|
||||
;
|
||||
else if ($is_admin == 'group') { // 그룹관리자
|
||||
$mb = get_member($wr['mb_id']);
|
||||
if ($member['mb_id'] != $group['gr_admin']) // 자신이 관리하는 그룹인가?
|
||||
alert('자신이 관리하는 그룹의 게시판이 아니므로 수정할 수 없습니다.', $return_url);
|
||||
else if ($member['mb_level'] < $mb['mb_level']) // 자신의 레벨이 크거나 같다면 통과
|
||||
alert('자신의 권한보다 높은 권한의 회원이 작성한 글은 수정할 수 없습니다.', $return_url);
|
||||
} else if ($is_admin == 'board') { // 게시판관리자이면
|
||||
$mb = get_member($wr['mb_id']);
|
||||
if ($member['mb_id'] != $board['bo_admin']) // 자신이 관리하는 게시판인가?
|
||||
alert('자신이 관리하는 게시판이 아니므로 수정할 수 없습니다.', $return_url);
|
||||
else if ($member['mb_level'] < $mb['mb_level']) // 자신의 레벨이 크거나 같다면 통과
|
||||
alert('자신의 권한보다 높은 권한의 회원이 작성한 글은 수정할 수 없습니다.', $return_url);
|
||||
} else if ($member['mb_id']) {
|
||||
if ($member['mb_id'] != $wr['mb_id'])
|
||||
alert('자신의 글이 아니므로 수정할 수 없습니다.', $return_url);
|
||||
} else {
|
||||
if (!g5_has_write_edit_auth($bo_table, $wr))
|
||||
alert('비밀번호 확인 후 다시 수정하여 주십시오.', $return_url);
|
||||
if ($wr['mb_id'])
|
||||
alert('로그인 후 수정하세요.', G5_BBS_URL.'/login.php?url='.urlencode($return_url));
|
||||
}
|
||||
}
|
||||
|
||||
// 외부에서 글을 등록할 수 있는 버그가 존재하므로 비밀글은 사용일 경우에만 가능해야 함
|
||||
if (!$is_admin && !$board['bo_use_secret'] && (stripos($_POST['html'], 'secret') !== false || stripos($_POST['secret'], 'secret') !== false || stripos($_POST['mail'], 'secret') !== false)) {
|
||||
alert('비밀글 미사용 게시판 이므로 비밀글로 등록할 수 없습니다.');
|
||||
@@ -335,34 +368,6 @@ if ($w == '' || $w == 'r') {
|
||||
insert_point($member['mb_id'], $board['bo_comment_point'], "{$board['bo_subject']} {$wr_id} 글답변", $bo_table, $wr_id, '쓰기');
|
||||
}
|
||||
} else if ($w == 'u') {
|
||||
if (get_session('ss_bo_table') != $_POST['bo_table'] || get_session('ss_wr_id') != $_POST['wr_id']) {
|
||||
alert('올바른 방법으로 수정하여 주십시오.', get_pretty_url($bo_table));
|
||||
}
|
||||
|
||||
$return_url = get_pretty_url($bo_table, $wr_id);
|
||||
|
||||
if ($is_admin == 'super') // 최고관리자 통과
|
||||
;
|
||||
else if ($is_admin == 'group') { // 그룹관리자
|
||||
$mb = get_member($write['mb_id']);
|
||||
if ($member['mb_id'] != $group['gr_admin']) // 자신이 관리하는 그룹인가?
|
||||
alert('자신이 관리하는 그룹의 게시판이 아니므로 수정할 수 없습니다.', $return_url);
|
||||
else if ($member['mb_level'] < $mb['mb_level']) // 자신의 레벨이 크거나 같다면 통과
|
||||
alert('자신의 권한보다 높은 권한의 회원이 작성한 글은 수정할 수 없습니다.', $return_url);
|
||||
} else if ($is_admin == 'board') { // 게시판관리자이면
|
||||
$mb = get_member($write['mb_id']);
|
||||
if ($member['mb_id'] != $board['bo_admin']) // 자신이 관리하는 게시판인가?
|
||||
alert('자신이 관리하는 게시판이 아니므로 수정할 수 없습니다.', $return_url);
|
||||
else if ($member['mb_level'] < $mb['mb_level']) // 자신의 레벨이 크거나 같다면 통과
|
||||
alert('자신의 권한보다 높은 권한의 회원이 작성한 글은 수정할 수 없습니다.', $return_url);
|
||||
} else if ($member['mb_id']) {
|
||||
if ($member['mb_id'] != $write['mb_id'])
|
||||
alert('자신의 글이 아니므로 수정할 수 없습니다.', $return_url);
|
||||
} else {
|
||||
if ($write['mb_id'])
|
||||
alert('로그인 후 수정하세요.', G5_BBS_URL.'/login.php?url='.urlencode($return_url));
|
||||
}
|
||||
|
||||
if ($member['mb_id']) {
|
||||
// 자신의 글이라면
|
||||
if ($member['mb_id'] === $wr['mb_id']) {
|
||||
@@ -428,6 +433,8 @@ if ($w == '' || $w == 'r') {
|
||||
where wr_id = '{$wr['wr_id']}' ";
|
||||
sql_query($sql);
|
||||
|
||||
set_session(g5_write_edit_auth_key($bo_table, $wr_id), '');
|
||||
|
||||
// 분류가 수정되는 경우 해당되는 코멘트의 분류명도 모두 수정함
|
||||
// 코멘트의 분류를 수정하지 않으면 검색이 제대로 되지 않음
|
||||
$sql = " update {$write_table} set ca_name = '{$ca_name}' where wr_parent = '{$wr['wr_id']}' ";
|
||||
|
||||
+25
-2
@@ -4691,7 +4691,29 @@ function get_sql_affected_rows($link=null)
|
||||
}
|
||||
}
|
||||
|
||||
// 불법접근을 막도록 토큰을 생성하면서 토큰값을 리턴
|
||||
// 비회원의 기존 비밀번호 확인 이력을 게시판과 게시물에 결합한다.
|
||||
function g5_write_edit_auth_key($bo_table, $wr_id)
|
||||
{
|
||||
return 'ss_write_edit_'.hash('sha256', $bo_table.':'.(int)$wr_id);
|
||||
}
|
||||
|
||||
function g5_grant_write_edit_auth($bo_table, $write)
|
||||
{
|
||||
set_session(g5_write_edit_auth_key($bo_table, $write['wr_id']), array(
|
||||
'expires' => G5_SERVER_TIME + 1800,
|
||||
'password' => hash('sha256', $write['wr_password'])
|
||||
));
|
||||
}
|
||||
|
||||
function g5_has_write_edit_auth($bo_table, $write)
|
||||
{
|
||||
$auth = get_session(g5_write_edit_auth_key($bo_table, $write['wr_id']));
|
||||
return empty($write['mb_id']) && is_array($auth) && isset($auth['expires'], $auth['password'])
|
||||
&& $auth['expires'] >= G5_SERVER_TIME
|
||||
&& slow_equals(hash('sha256', $write['wr_password']), $auth['password']);
|
||||
}
|
||||
|
||||
// 글쓰기 요청의 CSRF 토큰을 발급한다. 수정 권한은 별도로 확인한다.
|
||||
function get_write_token($bo_table)
|
||||
{
|
||||
$token = get_random_token_string(16);
|
||||
@@ -4710,7 +4732,8 @@ function check_write_token($bo_table)
|
||||
$token = get_session('ss_write_'.$bo_table.'_token');
|
||||
set_session('ss_write_'.$bo_table.'_token', '');
|
||||
|
||||
if(!$token || !$_REQUEST['token'] || $token != $_REQUEST['token'])
|
||||
if (!is_string($token) || !$token || !isset($_POST['token']) || !is_string($_POST['token'])
|
||||
|| !slow_equals($token, $_POST['token']))
|
||||
alert('올바른 방법으로 이용해 주십시오.', G5_URL);
|
||||
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user