본문으로 건너뛰기

에디터 이미지 첨부 보안 강화

PHP 8 · GODO26
변경 파일 수: 7개
변경 파일 목록
총 7개
변경 파일 코드
추가삭제
Admin/share/photo_uploader.php+2-2
변경 전photo_uploader.php
<div id="pop_content2">
<input type="file" class="upload" id="uploadInputBox" name="Filedata">
 
<p class="dsc" id="info"><strong>한 장당 최대 5MB</strong>이하의 이미지 파일만 등록할 수 있습니다.<br>(JPG, GIF, PNG, BMP, JPG, TIFF, SVG)</p>
</div>
</form>
<!-- //content -->
<em class="blind">마우스로 드래그해서 이미지를 추가해주세요.</em><span id="guide_text" class="bg"></span>
</div>
<div style="display:none;" id="divImageList"></div>
<p class="dsc dsc_v1"><em>한 장당 최대 5MB</em>의 이미지 파일을<br>등록할 수 있습니다. (JPG, GIF, PNG, BMP, JPG, TIFF, SVG)</p>
</div>
<!-- //content -->
</div>
 
변경 후photo_uploader.php
<div id="pop_content2">
<input type="file" class="upload" id="uploadInputBox" name="Filedata">
 
<p class="dsc" id="info"><strong>한 장당 최대 5MB</strong>이하의 이미지 파일만 등록할 수 있습니다.<br>(JPG, GIF, PNG, BMP, JPEG, TIFF)</p>
</div>
</form>
<!-- //content -->
<em class="blind">마우스로 드래그해서 이미지를 추가해주세요.</em><span id="guide_text" class="bg"></span>
</div>
<div style="display:none;" id="divImageList"></div>
<p class="dsc dsc_v1"><em>한 장당 최대 5MB</em>의 이미지 파일을<br>등록할 수 있습니다. (JPG, GIF, PNG, BMP, JPEG, TIFF)</p>
</div>
<!-- //content -->
</div>
 
Component/Board/BoardWrite.php+37
변경 전BoardWrite.php
use Framework\Debug\Exception\RequiredLoginException;
use Framework\Utility\ArrayUtils;
use Framework\ObjectStorage\Service\ImageUploadService;
 
 
class BoardWrite extends \Component\Board\BoardFront
{
$data['writerNm'] = $memberMasking->maskingRaw('name', $data['writerNm']);
}
 
 
 
 
 
return gd_htmlspecialchars_stripslashes($data);
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/**
* 글작성시 업로드되는 tmp 파일 삭제
* @param array data
 
변경 후BoardWrite.php
use Framework\Debug\Exception\RequiredLoginException;
use Framework\Utility\ArrayUtils;
use Framework\ObjectStorage\Service\ImageUploadService;
use Origin\Service\Board\EditorUploadPermissionService;
 
class BoardWrite extends \Component\Board\BoardFront
{
$data['writerNm'] = $memberMasking->maskingRaw('name', $data['writerNm']);
}
 
if ($this->canGrantEditorUpload($data)) {
\App::getInstance(EditorUploadPermissionService::class)->grantForWriteMode($this->req['mode']);
}
 
return gd_htmlspecialchars_stripslashes($data);
}
 
/**
* @param array|null $data getData 가 만든 화면 데이터
* @return bool
*/
protected function canGrantEditorUpload($data)
{
if ($this->req['mode'] !== 'modify') {
return true;
}
 
// getModify 는 없는 글도 배열로 돌려주고 canModify 는 비로그인이면 'c' 를 주므로 sno 로 실존을 확인한다
if (empty($data['sno'])) {
return false;
}
 
if ($data['auth'] === 'y') {
return true;
}
 
if ($data['auth'] !== 'c') {
return false;
}
 
// canModify 는 board/write 비밀글에서만 비밀번호를 확인하므로 상품게시판(GET)까지 포함해 다시 확인한다
$oldPassword = \Request::request()->get('oldPassword');
if (empty($oldPassword)) {
return false;
}
 
return $this->checkPassword($data, $oldPassword);
}
 
/**
* 글작성시 업로드되는 tmp 파일 삭제
* @param array data
 
Component/Board/Editor/AbstractFileUploader.php+1-1
변경 전AbstractFileUploader.php
 
abstract class AbstractFileUploader
{
protected const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'tiff', 'png', 'bmp', 'gif', 'svg'];
 
private Request $request;
private SessionManager $session;
 
변경 후AbstractFileUploader.php
 
abstract class AbstractFileUploader
{
protected const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'tiff', 'png', 'bmp', 'gif'];
 
private Request $request;
private SessionManager $session;
 
Controller/Admin/Share/EditorFileUploaderHtml5PsController.php+1-1
변경 전EditorFileUploaderHtml5PsController.php
$_tmp = (array)explode('.', $file->name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif","svg");
if (!gd_in_array($filename_ext, $allow_file)) {
echo "NOTALLOW_" . $file->name;
 
변경 후EditorFileUploaderHtml5PsController.php
$_tmp = (array)explode('.', $file->name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif");
if (!gd_in_array($filename_ext, $allow_file)) {
echo "NOTALLOW_" . $file->name;
 
Controller/Admin/Share/EditorFileUploaderPsController.php+1-1
변경 전EditorFileUploaderPsController.php
$_tmp = (array)explode('.', $name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif","svg");
if (!gd_in_array($filename_ext, $allow_file)) {
$url .= '&errstr=' . $name;
 
변경 후EditorFileUploaderPsController.php
$_tmp = (array)explode('.', $name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif");
if (!gd_in_array($filename_ext, $allow_file)) {
$url .= '&errstr=' . $name;
 
Controller/Front/Share/EditorFileUploaderHtml5PsController.php+21-1
변경 전EditorFileUploaderHtml5PsController.php
use Component\Storage\Storage;
use Component\Validator\Validator;
 
 
use Request;
class EditorFileUploaderHtml5PsController extends \Controller\Front\Controller
{
public function index()
{
 
 
 
 
 
$sFileInfo = '';
$headers = array();
$_tmp = (array)explode('.', $file->name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif","svg");
if (!gd_in_array($filename_ext, $allow_file)) {
echo "NOTALLOW_" . $file->name;
} else {
 
 
 
 
 
 
$pathChunk = parse_url(Request::get()->get('editorUrl'));
$pathArray = explode('/', $pathChunk['path']);
$queryChunk = $pathChunk['query'];
array_shift($pathArray);
array_pop($pathArray);
$path = $pathArray[gd_count($pathArray) - 1];
 
 
 
 
if ($path == 'board') {
if(Request::get()->has('bdId')) {
$bdId = Request::get()->get('bdId');
}
if (isset($bdId)) {
 
 
 
$uploadDir = $path . "/" . $bdId . "/";
} else {
$uploadDir = $path . "/".date('ymd')."/";
 
변경 후EditorFileUploaderHtml5PsController.php
use Component\Storage\Storage;
use Component\Validator\Validator;
use Origin\Service\Board\EditorUploadValidationService;
use Origin\Service\Board\EditorUploadPermissionService;
use Request;
class EditorFileUploaderHtml5PsController extends \Controller\Front\Controller
{
public function index()
{
$permissionService = \App::getInstance(EditorUploadPermissionService::class);
if (!$permissionService->isGrantedForEditorUrl(Request::get()->get('editorUrl'))) {
exit("ERRORMSG_" . __('접근 권한이 없습니다.'));
}
$sFileInfo = '';
$headers = array();
$_tmp = (array)explode('.', $file->name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif");
if (!gd_in_array($filename_ext, $allow_file)) {
echo "NOTALLOW_" . $file->name;
} else {
// 분산 분기는 원본 서버가 같은 검사를 하지만 로컬 분기는 검사 없이 저장되므로 분기 전에 1회 검사한다
$validationService = \App::getInstance(EditorUploadValidationService::class);
if (!$validationService->isUploadableContent($file->content)) {
exit("FILE_ERROR");
}
$pathChunk = parse_url(Request::get()->get('editorUrl'));
$pathArray = explode('/', $pathChunk['path']);
$queryChunk = $pathChunk['query'];
array_shift($pathArray);
array_pop($pathArray);
$path = $pathArray[gd_count($pathArray) - 1];
// editorUrl 은 요청값이라 경로 문자가 들어오면 /data/editor 밖에 폴더가 생긴다
if (!$validationService->isValidUploadPath($path)) {
exit("ERRORMSG_" . __('잘못된 접근입니다.'));
}
if ($path == 'board') {
if(Request::get()->has('bdId')) {
$bdId = Request::get()->get('bdId');
}
if (isset($bdId)) {
if (!$validationService->isValidBdId($bdId)) {
exit("ERRORMSG_" . __('잘못된 접근입니다.'));
}
$uploadDir = $path . "/" . $bdId . "/";
} else {
$uploadDir = $path . "/".date('ymd')."/";
 
Controller/Front/Share/EditorFileUploaderPsController.php+21-1
변경 전EditorFileUploaderPsController.php
use Request;
use Component\Storage\Storage;
use Component\Validator\Validator;
 
 
class EditorFileUploaderPsController extends \Controller\Front\Controller
{
public function index()
{
 
 
 
 
 
 
// 파일 업로드 취약점 조치
$tmpName = Request::files()->get('Filedata.tmp_name');
if (Validator::validateIncludeEval($tmpName) === false) {
throw new AlertBackException('업로드 할 수 없는 파일입니다.');
}
 
 
 
 
// default redirection
$url = Request::request()->get("callback") . '?callback_func=' . Request::request()->get("callback_func");
$_tmp = (array)explode('.', $name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif","svg");
if (!gd_in_array($filename_ext, $allow_file)) {
$url .= '&errstr=' . $name;
array_shift($pathArray);
array_pop($pathArray);
$path = $pathArray[gd_count($pathArray) - 1];
 
 
 
 
 
if ($path == 'board') {
if(Request::get()->has('bdId')) {
$bdId = Request::get()->get('bdId');
}
if (isset($bdId)) {
 
 
 
$uploadCode = PATH_EDITOR_RELATIVE .'/'. $path . "/" . $bdId . "/";
} else {
$uploadCode = PATH_EDITOR_RELATIVE .'/'. $path . "/".date('ymd')."/";;
 
변경 후EditorFileUploaderPsController.php
use Request;
use Component\Storage\Storage;
use Component\Validator\Validator;
use Origin\Service\Board\EditorUploadValidationService;
use Origin\Service\Board\EditorUploadPermissionService;
class EditorFileUploaderPsController extends \Controller\Front\Controller
{
public function index()
{
// saveEditorFile 은 사용자 세션이 없는 분산 원본 서버 요청에서도 정적 호출되므로 표식 확인은 index 에서만 한다
$permissionService = \App::getInstance(EditorUploadPermissionService::class);
if (!$permissionService->isGrantedForEditorUrl(Request::post()->get('editorUrl'))) {
throw new AlertBackException(__('접근 권한이 없습니다.'));
}
// 파일 업로드 취약점 조치
$tmpName = Request::files()->get('Filedata.tmp_name');
if (Validator::validateIncludeEval($tmpName) === false) {
throw new AlertBackException('업로드 할 수 없는 파일입니다.');
}
$validationService = \App::getInstance(EditorUploadValidationService::class);
if (!$validationService->isImageFile($tmpName)) {
throw new AlertBackException('업로드 할 수 없는 파일입니다.');
}
// default redirection
$url = Request::request()->get("callback") . '?callback_func=' . Request::request()->get("callback_func");
$_tmp = (array)explode('.', $name);
$filename_ext = strtolower(array_pop($_tmp));
$allow_file = array("jpg","jpeg","tiff", "png", "bmp", "gif");
if (!gd_in_array($filename_ext, $allow_file)) {
$url .= '&errstr=' . $name;
array_shift($pathArray);
array_pop($pathArray);
$path = $pathArray[gd_count($pathArray) - 1];
// editorUrl 은 요청값이라 경로 문자가 들어오면 /data/editor 밖에 폴더가 생긴다
$validationService = \App::getInstance(EditorUploadValidationService::class);
if (!$validationService->isValidUploadPath($path)) {
throw new \Exception(__('잘못된 접근입니다.'));
}
if ($path == 'board') {
if(Request::get()->has('bdId')) {
$bdId = Request::get()->get('bdId');
}
if (isset($bdId)) {
if (!$validationService->isValidBdId($bdId)) {
throw new \Exception(__('잘못된 접근입니다.'));
}
$uploadCode = PATH_EDITOR_RELATIVE .'/'. $path . "/" . $bdId . "/";
} else {
$uploadCode = PATH_EDITOR_RELATIVE .'/'. $path . "/".date('ymd')."/";;