diff --git a/bbs/ajax.write.token.php b/bbs/ajax.write.token.php index 1fe7b8df2..3f3cb0304 100644 --- a/bbs/ajax.write.token.php +++ b/bbs/ajax.write.token.php @@ -1,10 +1,12 @@ '', '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'=>''))); diff --git a/bbs/write.php b/bbs/write.php index 39ffcbdf8..8b4843780 100644 --- a/bbs/write.php +++ b/bbs/write.php @@ -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); } } } diff --git a/bbs/write_token.php b/bbs/write_token.php index e7c9520b1..d5e94eb4d 100644 --- a/bbs/write_token.php +++ b/bbs/write_token.php @@ -1,9 +1,14 @@ '게시판 정보가 올바르지 않습니다.', 'url'=>G5_URL))); +check_request_origin(); + set_session('ss_write_'.$bo_table.'_token', ''); $token = get_write_token($bo_table); diff --git a/bbs/write_update.php b/bbs/write_update.php index 2b4defbe4..6020f283a 100644 --- a/bbs/write_update.php +++ b/bbs/write_update.php @@ -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']}' "; diff --git a/lib/common.lib.php b/lib/common.lib.php index 9ca2dc112..e3a10f52c 100644 --- a/lib/common.lib.php +++ b/lib/common.lib.php @@ -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;