PHP 보안 팁

웹개발/PHP 2006.09.24 07:06
register_globals = Off
아직도 많은 국내의 호스팅 업체들에서 register_globals = On 으로 놓고 서비스를 하고 있으나 Off 로 해야 옳다.
물론 이렇게 하면 제로보드처럼 On에서 코딩한 것들은 쓸 수 없게 된다. (제로보드는 쓰지 않는 것이 좋다.)
register_globals = On 으로 놓고서 코드 내에서 따로 보안을 위해 변수를 검사하는 방법도 있겠으나, 그런 이중의 수고를 막으려면 php4 이상에서는 그냥 register_globals = Off 로 하고 그에 따라 코딩해야 한다.

이를테면 $a를 받아서 $b = $a; 로 처리해야 할 때는,
$b=$_GET["a"]; (GET 방식으로넘어온 변수일경우)
$b=$_POST["a"]; (POST 방식으로넘어온 변수일경우)
$b=$_COOKIE ["a"]; (cookie에서 넘어온 값이면)
$b=$_SERVER["a"]; (서버변수일경우)
$b=$_ENV["a"]; (환경변수일 경우)
$b=$_REQUEST["a"]; (서버요청변수일 경우. - GET, POST, Cookie 방식으로 넘어오는 모든 경우에 해당되며, 보안상 권장되지 않는다.)
$b=$_SESSION["a"]; (세션변수이면)
$b=$_FILES["a"]; (file 업로드로 넘어온 변수이면)
와 같이 처리해야 한다.
위 처럼 하기 귀찮을 경우, extract($_GET); 으로 선언하면 $_GET['a']로 들어오는 $a 를 자동으로 인식한다.
♣ 단, SESSION 변수의 경우 절대 extract($_SESSION); 하면 안된다. 보안에 위배되기 때문이다. if (isset($_GET['password'])) { $password = $_GET['password']; echo $password; }
.inc 파일 등 특정 확장자 소스 못보게 하기
아파치 설정파일(httpd.conf) 안에 보면 아래와 같은 라인이 있다.

AddType application/x-httpd-php .php .php3 .html .sql .ph .inc .ins
AddType application/x-httpd-php-source .phps

위에서와 같이 inc를 등록시키면 된다.
그리고 웹브라우저에서 보아도 소스는 나오지 않는다. *.inc 등으로 작성하려거든 반드시 이렇게 해야만 한다. 혹은 *.inc.php 이런 식으로 작성한다.

PHP 보안을 위한 코딩 스타일 (파일 업로드 등)
현재(2002.3) PHP4.1.2 나 PHP4.2.dev 버전을 제외한 모든 버전은 PHP4.1.2로 패치할 것을 권고하고 있다. PHP 파일 업로딩이 RFC 1867에 의해 만들어졌는데, 웹서버를 재부팅 시킬 수도 있다고 한다. PHP4.1.2 이상의 최신 버전이 아닌 모든 버전은 파일 업로드 버그가 존재한다고 한다.

예전 스타일의 파일 업로드를 사용하지 마라; HTTP_POST_FILES 배열과 관련된 함수를 사용해라. PHP 는 특별한 이름을 갖는 어떤 임시디렉토리에 파일을 업로드함으로써 파일 업로드를 지원한다. PHP 는 그 파일 이름이 존재했던 곳을 가리키기 위해 원래 많은 변수들을 설정한다. 그러나 공격자가 변수 이름 및 그 값을 제어할 수 있기 때문에 이들을 사용해 커다란 악영향을 야기할 수 있다. 대신 업로드된 파일에 접근하기 위해서는 언제나 HTTP_POST_FILES 및 관련된 함수를 사용해라. 이 경우라도 PHP 는 공격자가 임의의 내용을 갖는 파일을 업로드할 수 있게 하며 이는 그 자체로 위험함을 주목해라.

모든 입력에 대해 다른 언어에서와 같이 받아들일 수 있는지 패턴과의 일치 여부를 검사하고 그 후 문자열이 아닌 데이타를 요구되는 타입으로 맞추기 위해 타입 캐스팅을 사용해라. (예상되는) 입력의 선택된 리스트를 쉽게 검사하고 import 하기 위해 ``helper" 함수를 개발해라. PHP 는 부정확하게 타입이 정해질 수 있는데 (loosely-typed) 이는 문제를 야기할 수 있다. 예를 들어 입력 데이타가 "000" 값을 갖는다면 이는 "0" 와 같지 않으며 또한 empty() 도 아니다. 이는 특히 결합 (associative) 배열의 경우 중요한데 이들의 인덱스가 문자열이기 때문이다; 이는 $data["000"] 과 $data["0"] 이 다르다는 것을 의미한다. 예를 들어 $bar 가 double 타입임을 확인하기 위해 (double 에 적합한 포맷을 갖는지 확인한 후) 다음과 같이 해라:
$bar = (double) $bar;

위험한 함수에 주의할 것 :
코드실행함수(require(), include(), eval(), preg_replace() 등), 명령실행함수(exec(), passthru(), backtick 연산자, system(), popen() 등), 파일오픈암수(fopen(), readfile(), file()) 등.

PHP에러출력을 방지한다. php.ini의 Error_Handling 부분에서 display_errors = Off 로 설정한다. (오류가 보여지면 apache 디렉토리 위치나 htdocs 디렉토리 위치를 노출시키게 된다.)

magic_quotes_gpc() 를 사용해라. 이는 많은 종류의 공격을 제거한다.

게시판 글올릴때 html소스는 그냥 다 막아버려라. <a>태그 외에 <a onmouse= 등의 태그도 안되고 자바스크립트도 안된다. 그냥 다 막아버리면 제일 속편하다.

phpinfo();는 설치한 후 테스트하고 바로 지워라.

쿠키보다는 세션을, 세션보다는 autu인증을 사용하라.

location.replace 인증 (이동했던 히스토리 삭제) function goto_page($url) { echo "<script> location.replace('.$url.');</script>"; }

쇼핑몰 등의 사이트는 반드시 SSL을 사용하라.

디렉토리는 755대신 711로 설정. 그리고 될수있으면 아파치 httpd.conf 에서 Indexes 지운다. (index.html 파일이 없을 경우 디렉토리 목록이 출력되는 것을 방지.)

(보안) 세션, 자료실, PHP_SELF
(출처: http://tood.net)
php.ini 에서 register_globals = Off 로 설정했다면 세션의 등록은 아래와 같이 한다. <?php session_start(); $HTTP_SESSION_VARS['foo'] = "blah blah"; // $_SESSION['foo'] = "blah blah"; // $_SESSION은 PHP4.1.0 이상이다. session_register('foo'); ?>

회원 비번은 md5()로 암호화하고 php.ini에서 세션저장장소를 /tmp가 아닌 다른 장소에 저장한다. (보안을 위해)
세션 생성 시 $userid를 생성하고, $userpass = md5($userpass); 로 생성해서, 2개 값이 있는지 비교하고 isset()등으로 비교하는게 좋다.
$userpass값은 md5()로 해싱하면 32자가 되므로 길이를 확인한다.

if((session_is_registered(username)) && (session_is_registered(user_id)))
으로 체크. <?php function check_session() { session_start(); if (session_is_registered(user_id)) { return TRUE; } else { header("Location: login.php"); exit; } } ?>

파일의 경우는 $HTTP_POST_FILES 를 따로 해야 한다. extract($HTTP_POST_FILES); foreach ($HTTP_POST_FILES as $UploadedFile ) { $UploadedFile_name = $UploadedFile['name']; $UploadedFile_size = $UploadedFile['size']; $UploadedFile_type = $UploadedFile['type']; }

특히 파일의 경우 절대로 GET으로 올리지 못하게 해야한다.
upload.php?file_name=/etc/passwd$file_type=text&file_size=30
이런 식으로 해킹할 시스템의 passwd파일을 자료실에 올려버리고 다운받는 경우가 있기 때문이다. 아예 파일명 중에 pass나 shadow등이 있을 경우 올리지 못하게 하는 방법도 있다.
또는 file_exists($file_name)를 사용하여 체크한다. 로컬 시스템에 파일이 있으면 절대 못올리게 되는 것이다.

$PHP_SELF의 경우도 바로 출력되지 않는다. $_SERVER['REQUEST_METHOD']; //GET or POST $_SERVER['REQUEST_URI']; $_SERVER['PHP_SELF'];

링크로 넘어오는 값 확인
( 출처 : http://www.nzeo.com/bbs/zboard.php?id=cgi_tip&page=2&sn1=&divpage=1&sn=off&ss=on&sc=off&keyword=링크&select_arrange=headnum&desc=asc&no=1030 ) if(!eregi(getenv("HTTP_HOST"),getenv("HTTP_REFERER"))) { $reffer = getenv("HTTP_REFERER"); echo "<script>alert('여기다 무단링크시 남길 메세지');window.location.href='http://4rum.uu.st (홈주소)';</script>"; $filename = "기록할 파일 이름"; if (!file_exists($filename)) touch ("$filename"); chmod($filename,0777); $fp = fopen($filename,"a+"); if (!trim($reffer)) $reffer = "Typing or Bookmark"; fwrite($fp,"IP : $REMOTE_ADDR , REFFER : $reffer\n"); fclose($fp); exit; }

자료실에서 무단링크, 웹상에서 실행을 막는 한 가지 방법
자료를 업로드 할 때 원래이름과 바꿀이름 2가지를 디비에 저장한다. 그리고 다운로드를 받을 때는 디비에서 원래 이름을 가져와서 헤더 함수를 이용해 파일명을 원래이름으로 바꿔서 보냅니다.. 이렇게하면 저장되어있는 파일이름을 알 수가 없기때문에 무단링크, 웹상에서 실행이 불가능 하게된다. 파일이름을 안다고 해도 웹상에서는 실행되자 않는다. (아파치가 인식할 수 없는 확장자명으로 지정했을경우) 그러니까 파일을 저장할때 파일명을 $filename = date("YmdHis").".down"; 으로 한다. 그럼 200101231203.down 이런 식으로 파일명이 된다.

PHP파일문서를 자료실에 올리는 문제 (불완전정보)
자료실에 확장자 php인 자료를 올려 해당 서버의 정보를 유출하거나 자료를 삭제하는 해킹이 있을 수 있다. 이 때는 php를 사용할 디렉토리를 정한 후 모든 php소스는 그 디렉토리 밑에 두어야 한다.

예를 들어 자신의 Document Root 디렉토리가 '/home/aaa/public_html'이라면 public_html 아래에 php란 디렉토리를 만든다. 그런 다음 아파치 웹 서버의 설정파일 httpd.conf 를 다음과 같이 수정한다.

<Directory "/home/aaa/public_html"> ... php_admin_flag engine off ... </Directory> <Directory "/home/aaa/public_html"> ... php_admin_flag engine off ... </Directory>

위와 같이 설정하고 나머지 자료 아래의 html파일은 모두 php디렉토리 밖에 놓아두면 아무런 문제없이 php를 사용할 수 있을 것이다. 또 다른 방법은 자료를 올릴 때 php 파일은 전혀 등록할 수 없게 하는 방법인데 이 부분은 좀 애매한 부분이다.

자동차보험,의료,보험,대출,미용,금융,법률,부동산,중고자동차,무료듣기,건강,돈,국민임대아파트

Posted by CodeChef
TAG ,

댓글을 달아 주세요

  1. Favicon of http://zetus.net BlogIcon zetus 2007.03.05 06:14 신고  댓글주소  수정/삭제  댓글쓰기

    잘보고 갑니다~ 퍼가요~♡