728x90

파일을 업로드하는 코딩시 고려할 사항이다.


파일을 업로드시에 공격이 성공하면 바로 서버가 해킹되는 것이기 때문에 가장 리스크가 큰 취약점이다.

보안(Security)을 고려하고 실행파일이 업로드되지 않도록 해야 한다.

먼저, 파일 업로드 기능이 있는 페이지를 전부 조사해서 WebShell 같은 악의적인 파일이 업로드될 수 있는지 체크해야 한다.


1. 파일 업로드시 확장자 검사 루틴

    - 기본적으로는 Apache 환경설정에서 mine type 필터링을 설정한다.

      Apache 환경설정 http://link2me.tistory.com/426  http://link2me.tistory.com/991 참조

    <IfModule mime_module>
        TypesConfig conf/mime.types
        AddType application/x-compress .Z
        AddType application/x-gzip .gz .tgz
        AddType application/x-httpd-php .php .html
        AddType application/x-httpd-php-source .phps
    </IfModule>


   - 하지만 공격자가 Proxy-Server 등을 통해 우회할 수 있으므로 확장자 필터링을 적용한다.

     업로드가 허용된 확장자만 업로드가 가능하도록 서버 필터링을 하여야 한다.

 

2. 파일명은 치환(난수화)해서 저장한다.
    그리고 파일 접근권한을 읽기 전용모드로 등록한다. (실행권한 부여 금지)


3. 등록시 변경 파일명을 DB에 저장한다.

    - 게시판에 첨부되는 파일명인 경우, 변경 파일명을 DB 테이블에 기록하여 찾을 수 있도록 한다.


4. 가능하면 파일 업로드 장소를 물리적으로 분리한다.

    물리적으로 분리하지 않은 경우라면 해당 디렉토리가 어디인지 알수 없게 다른 곳으로 지정한다.


파일 업로드시 제한 용량은 php.ini 파일에 설정되어 있다.

업로드 용량을 많이 설정하려면 php.ini 파일을 수정하고 Apache 를 restart 해야 한다.

; PHP 가 받아들이는 POST data 최대 크기
; default 8M 로 되어 있음, upload_max_filesize 보다 크게 설정해야 함
post_max_size = 20M
memory_limit = 128M
upload_max_filesize = 19M


// 테이블 구조 예시

CREATE TABLE IF NOT EXISTS file_upload (
  uid int(11) NOT NULL AUTO_INCREMENT,
  folder varchar(10) NOT NULL DEFAULT '',
  name varchar(250) NOT NULL DEFAULT '',
  size int(11) NOT NULL DEFAULT '0',
  d_regis varchar(14) NOT NULL DEFAULT '',
  PRIMARY KEY (uid),
  KEY d_regis (d_regis)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;


//파일을 전송하는 PHP 소스 부분

파일명을 excel 로 사용했으면 받는 쪽에서도 excel 로 사용해야 한다.

보통은 userfile 이라고 많이 쓴다.

<form enctype="multipart/form-data" action="fileupload.php" method="POST">
 <input 
type="file" name="excel"  />

 <input type="submit" value="upload" />
</form>



// 파일을 전송받은 PHP 소스 부분

여러개의 확장자를 검사하려면 strstr('[csv]',$fileExt) 부분을 수정하면 된다.

strstr('[csv,php,html,htm,inc,do]',$fileExt) 와 같이 확장자 여러개를 나열해준다.


<?php
    // Edit upload location here
    $tmpname    = $_FILES['excel']['tmp_name'];
    $realname    = $_FILES['excel']['name'];
    $fileExt    = getExt($realname);  // 확장자 필터링을 위한 확장자 추출
    $destination_path='uploads/';
    $rndname = hash('sha256', $realname).date("Ymd").'.'.$fileExt;  // 파일명 hash 처리
    $readFile = $destination_path . $rndname;

    if (is_uploaded_file($tmpname)) {
        if (!strstr('[csv]',$fileExt)) {  // 확장자 필터링 검사
            echo '<script type="text/javascript">alert("csv 파일만 등록할 수 있습니다.");</script>';
            exit;
        }
        move_uploaded_file($tmpname,$readFile);
        @chmod($readFile,0404);  // 파일 권한을 읽기모드로 설정

    }

    function getExt($filename){
        $ext = substr(strrchr($filename,"."),1); // 뒤에서부터 콤마 위치로부터 가져오기
        $ext = strtolower($ext); // 소문자로 강제치환
        return $ext;
    }

    ?>



아래 코드는 업로드시 파일명을 치환하는 연습 코드이다.


<?php
//$realname = strtolower($_FILES['excel']['name']);
$realname = 'shell.asp;.jpg';
$fileExt = getExt($realname);
//$tmpname = md5($realname).date("Ymd").'.'.$fileExt;
$tmpname = hash('sha256', $realname).date("Ymd").'.'.$fileExt;

echo $tmpname;
echo '<br />';
echo strlen($tmpname);

function getExt($filename){
    $ext = substr(strrchr($filename,"."),1); // 뒤에서부터 콤마 위치로부터 가져오기
    $ext = strtolower($ext); // 소문자로 강제치환
    return $ext;
}

?>


파일을 2개 업로드하는 걸 고려한다면

<form enctype="multipart/form-data" action="fileupload.php" method="POST">

이미지 파일1 <input type="file" name="imagefile[]">

이미지 파일2 <input type="file" name="imagefile[]">

<input type="submit" value="upload" />

</form>


fileupload.php 에서 확인해 볼 사항

echo '<pre>', print_r($_FILES) ,"</pre>";

$_FILES['imagefile']['name'][0];

$_FILES['imagefile']['name'][1];

$_FILES['imagefile']['type'][0];

$_FILES['imagefile']['type'][1];

$_FILES['imagefile']['tmp_name'][0];

$_FILES['imagefile']['tmp_name'][1];

$_FILES['imagefile']['size'][0];

$_FILES['imagefile']['size'][1];

$_FILES['imagefile']['error'][0];

$_FILES['imagefile']['error'][1];


참조하면 도움되는 게시글

http://blog.habonyphp.com/entry/php-POST-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C#.V5RntaKzHpU


jQuery PHP 파일 업로드 게시글 : http://link2me.tistory.com/1142


Ajax PHP 파일 업로드 게시글 : http://link2me.tistory.com/1143

블로그 이미지

Link2Me

,