O’reilly & 한빛미디어에서 출판된 “PHP 보안: 몇 줄의 코드로 안전하게” 도서를 바탕으로 PHP 프로그래밍에 있어서 보안을 고려해야할 요소를 포스팅 남긴다. 이미 PHP 프로그래밍에 능숙하다는 전제 하에, 리마인드 용으로 간략히 정리해보았다.

 

PHP-secure

 

목차

1. 소개

2. 폼과 URL

3. 데이터베이스와 SQL

4. 세션과 쿠기

5. 인클루드

6. 파일과 명령

7. 인증과 권한 부여

8. 공유 호스팅

Appendix A. 설정 지시문

Appendix B. 함수

Appendix C. 암호학

 

 

1. 소개

  • PHP의 보안 이슈는 언어 자체의 결함이 아니라, 어플리케이션 개발에 있음
  • 전역 변수 : 되도록 사용 안하지 않고, 사용하는 환경이라면 항상 초기화 필수 (대신, 수퍼 전역변수 숙지 및 사용)
  • 오류 보고 : display_errors는 Off, log_errors는 On하여 관리자만 에러 확인, error_reporting은 E_ALL이상으로 하여 높은 수준 유지 (php.ini, httpd.conf, .htaccess)
  • 원칙
    • 심층 방어 : 최대한 적게 믿고, 여러겹 보호 수단 마련 (동시에 비용 및 가치 고려)
    • 권한 : 작업 수행에 필요한 최소 권한만 제공
    • 단순한 것이 아름답다 : 불필요한 복잡성은 불필요한 위험성과 같음
    • 정보 노출의 최소화 : 화면에 보이는 노출 최소화 및 통신시 오가는 데이터 암호화
  • 지침
    • 위험과 사용성의 균형 : 위험과 사용성은 반비례관계 (정말 그럴까?)
    • 데이터 추적 : 모든 데이터가 추적 가능하게
    • 입력 필터링 : 입력 구분 -> 입력 필터링 -> 필터링 데이터와 오염 데이터 구별
      • ctype_alnum함수 또는 정규식
    • 출력 이스케이프 : 출력 구분 -> 출력 이스케이프 -> 이스케이프된 데이터와 안된 데이터 구별 (입력 필터링이 된 데이터만 이스케이프 함)
      • 웹브라우저 : htmlentities함수, htmlspecialchars함수
      • 데이터베이스(MySQL) : mysql_real_escape_string함수, addslashes함수

 

 

 

2. 폼과 URL

  • 폼과 데이터
    • 필터링된 데이터 vs. 오염된 데이터의 확실한 구분
    • GET과 POST 차이 이해
  • URL 공격 : GET으로 받은 데이터는 변조가 가능함을 숙지
  • 파일 업로드 공격 : 업로드 메타 정보 조작 공격 가능성
    • 예방 : is_uploaded_file함수, move_uploaded_file함수
  • 크로스 사이트 스크립팅(XSS) : 입력 폼에 악의적 스크립트가 사용자의 정보를 공격자에게 보냄
  • 크로스 사이트 리퀘스트 위조(CSRF) : 사용자로 하여금 임의의 HTTP요청을 하게 하여, 의도치 않은 공격을 유발함
    • 예방1 : 서버의 처리를 수행하는 요청은 POST로 수행
    • 예방2 : 암호화된 토큰을 세션에 저장
      • $_SESSION[‘token’] = md5(unique(rand함수, TRUE)); // POST로 넘긴 데이터와 동일한지 확인
      • $_SESSION[‘token_time’] = time함수; // 현재 시간과 비교하여 시간 제한 가능
  • 폼 제출 스푸핑, HTTP 요청 스푸핑
    • 입력 필터링이 중요!

 

 

 

3. 데이터베이스와 SQL

  • 데이터베이스도 외부 입출력 요소로 봐야하고, select문도 데이터베이스로 보내는 출력문임을 숙지
    • 필터링 및 이스케이프 필요
  • 액세스 인증 정보 유출 : 인증 정보가 저장된 파일은 루트에 바깥에 보관
  • SQL 삽입 공격
    • 예방 : 입력 필터링과 출력 이스케이프
    • MD5함수를 사용하려면, 최소한 키값(salt)을 더해서 사용
  • 데이터 유출 : 중요 데이터의 암호화와 키의 안전한 보관

 

 

 

4. 세션과 쿠키

  • HTTP의 무상태(stateless)를 극복하기 위해 만든 것이 쿠키와 세션
  • 쿠키 훔치기
  • 세션 데이터 노출 : 클라이언트와 서버 사이 전송에 SSL 사용
  • 세션 고정
  • 세션 하이재킹

 

 

 

5. 인클루드

  • 소스 코드 유출
    • 인클루드 확장자가 .inc파일
    • 웹서버 루트에 인클루드 저장
    • 아파치에서 .inc파일에 대한 리소스 타입 지정
    • 아파치의 DefaultType이 text/plain
  • 백도어 URL
    • 웹서버 루트 안과 밖의 차이
  • 파일 이름 조작 : /, ./, ../ 등의 입력을 넣어 디렉토리 조작
    • basename함수. realpath함수
  • 코드 삽입 공격
    • 넘겨 받은 입력은 모두 오염된 데이터로 간주하고 필터링!

 

 

 

6. 파일과 명령 : 파일 시스템과 셀 관련 기능

  • 파일 시스템 트래버스 : 오염된 데이터를 파일 이름의 일부로 사용할 때
    • /, ./, ../ 를 포함한 파일 및 디렉토리 위, 변조 가능
    • %00을 전달하여 NULL 문자를 포함 가능
  • 원격 파일 위험
    • PHP 설정에 allow_url_fopen이 기본이며, file_get_contents함수로 원격 리소스를 받아오도록 동작하게 할 수 있음
    • 결론은 입력 필터링 + 출력 이스케이프
  • 명령 삽입 공격
    • exec함수, passthru함수, popen함수, shell_exec함수, system함수 등 유의

 

 

 

7. 인증과 권한 부여

  • 인증(Authentication)이란 사용자의 신원을 증명하기 위해 사용되는 과정, 권한 부여(Authorization)란 리소스에 대한 접근을 보호하는 방법
  • 무차별 공격 (Brute Force Attack)
    • 예방 : 시간 지연(throttling)방법으로 재시도할 수 있는 시간을 둠
  • 패스워드 스니핑
    • 예방 : SSL 사용 (POST방식 사용) 전송 및 폼도 SSL로 보호
  • 리플레이 공격 : 정상적인 사용자가 보내는 액세스 데이터를 캡처하여 재전송하는 공격
    • ‘접근이 제한된 리소스’에 대한 액세스를 기억하는 데이터 사용을 피하고, 임시 액세스 데이터 이용
    • ‘접근이 제한된 리소스’에 대한 액세스를 제공하는 데이터(임시 포함)의 유출 피하기
  • 로그인 정보 기억
    • 2차 식별자(사용자 아이디 대신), 토큰(사용자 비밀번호 대신), 로그인 유지시간을 추가로 사용(DB)
      • $identifier = md5($salt . md5($username . $salt));
      • $token = md5(uniqid(rand함수, TRUE));
      • $timeout = time함수 + 60 * 60 * 24 * 7;
      • setcookie(‘auth’, “$identifier:$token”, $timeout);
    • 로그인 쿠키 저장 사용 유의점
      • 쿠키는 1주일 또는 그 이하의 기간 안에 만료
      • 쿠키는 오직 한 번의 인증에 대해서만 유효하고, 이후 토큰 재생성 및 쿠키 재생성
      • 기간 만료는 서버에서 강제 수행되어야함
        • setcookie(‘auth’, ‘DELETE!’, time함수)
      • 쿠키로 자동 로그인이 되었더라도 중요한 처리는 비밀번호 인증을 요구

 

 

 

8. 공유 호스팅

  •  공유 호스팅 환경은 웹서버 루트 밖에 존재하는 파일도 공개되었다고 봐야함
  • 소스 코드 유출
    • 모든 데이터를 데이터베이스에 저장
    • 데이터베이스 접근 정보는 root만 읽을 수 있는 파일(db.conf)에 아래와 같이 저장하고, $_SERVER 수퍼 전역변수로 참조
      • SetEnv DB_USER “myuser”
      • SetEnv DB_PASS “mypass”
      • 아파치 설정에 Include “/path/to/db.conf” 추가해야함
  • 세션 데이터 유출
    • 기본적으로 세션 데이터는 /tmp에 저장되므로 스크립트로 참조 가능 (웹 서버가 소유권을 갖고 있으므로)
    • 데이터베이스에 세션 데이터를 저장하는 방법 사용
      • 데이터베이스에 세션을 저장할 테이블 생성
      • PHP 고유의 세션 처리 방식 변경
        • sesstion_set_save_handler(‘_open’,’_close’,’_read’,’_write’,’_destroy’,’_clean’); // 인자 각각은 함수명
  • 세션 삽입 공격
    • 마찬가지로 세션 데이터를 데이터베이스에 보관하는 것 추천
  • 파일 시스템 브라우징 : 파일 시스템을 탐색하는 스크립트
  • 안전 모드
    • PHP 설정의 safe_mode 지시문 : 읽어드린 파일이 실행되는 스크림트의 소유자와 동일해야만 동작하지만, 웹 서버 소유의 경우 문제해결이 되지 않음

 

 

 

Appendix A. 설정 지시문 – php.ini 파일

  • allow_url_fopen : 필요없다면, url fopen을 사용하지 않기
  • disable_functions : 특정 함수 사용 못하게 하기
  • display_errors : 개발 중에만 사용하고, 운영 중엔 사용하지 않기 (정보공개 제한)
  • enable_dl : PHP 확장을 런타임에 로딩할일이 없다면 사용하지 않기
  • error_reporting : 최소 E_ALL 설정 사용하기
  • file_uploads : 파일 업로드할 필요가 없다면 사용하지 않기
  • log_errors : 에러 로그 파일을 기록하도록 사용하기
  • magic_quotes_gpc : 이거 사용하지 말고, 데이터베이스 고유의 이스케이프 함수 사용하기
  • memory_limit : 잘못된 스크립트가 모든 메모리를 잡아먹는 것을 막도록 사용하기 (보통 8M)
  • open_basedir : PHP가 특정 디렉토리에서만 파일을 열 수 있게 제한하도록 사용하기
    • open_basedir = /path/to/
  • register_globals : 사용하지 말고, 수퍼 전역변수 사용하기
  • safe_mode : PHP가 읽어들이는 파일이 실행되는 스크립트의 소유자와 동일한지 검사하지만, 우회 공격이 존재하기 때문에 사용하지 않기

 

 

 

Appendix B. 함수

  • eval함수 : 오염된 데이터에는 절대 사용하면 안되고, 되도록 사용하지 않기
  • exec함수, shell_exec함수, proc_open함수, popen함수, passthru함수 : 쉘 명령을 구성하는데 오염된 데이터를 사용하지 않기
  • file함수, system함수, readfile함수, fopen함수, file_get_contents함수 : 파일 이름을 구성하는데 오염된 데이터 사용하지 않기
  • include, require : 필터링된 데이터만 사용하기
  • phpinfo함수 : 중요한 정보를 담고 있기때문에, 접근 제한이 필요함
  • preg_replace함수 : 치환 매개변수를 PHP 코드 취급하므로, 패턴 구성을 오염된 데이터로 사용하지 않기

 

 

 

Appendix C. 암호학

  • 암호학 유형
    • 대칭형 암호
    • 비대칭형(공개키) 암호
    • 암호화된 해시 함수 (메시지 다이제스트)
    • 메시지 인증 코드 (MAC)
  • 비밀번호 저장 : 해시로 저장하며, salt를 사용하기
    • $password_hash = md5($salt . md5($password . $salt));
  • mcrypt Extension 사용하기 : 표준 PHP Extension 암호 알고리즘 (대칭형 암호)
    • mcrypt_list_algorithms함수 : 현재 플랫폼에서 지원하는 암호 알고리즘 리스트
    • mcrypt_encrypt($algorithm, $key, $cleartext, $mode, $iv)
      • $algorithm : 알고리즘 지정, mcrypt_list_algorithms함수로 확인
      • $key : 안전하게 보관해야할 키값
      • $cleartext
      • $mode : 모드 지정, mcrypt_list_modes함수로 확인
      • $iv : 초기화 벡터, mcrypt_create_iv함수로 생성
    • mcrypt_decrypt($algorithm, $key, $cleartext, $mode, $iv)
  • 신용카드 번호 저장하기 : 꼭 저장해두어야 하는가?!, 암호화하여 자장하고 가져와서 복호화
    • 키를 잘 숨기는 것이 핵심
  • 세션 데이터 암호화 : 추천하지는 않음
    • session_set_save_handler함수를 사용하여, 세션을 DB에 저장할 때 암호화와 복호화를 추가

 

 

 

PHP 보안 프로그래밍의 핵심은 입력 필터링과 출력 이스케이프란 결론이군요. 출력 이스케이프는 데이터베이스에서 제공하는 함수를 사용하면 쉽지만, 입력 필터링에서 한글 적용이나, 특정 상황에 맞는 정규식 표현을 확보하고 있는 것도 제산이겠군요.

댓글

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

*

로그인하세요.

계정 내용을 잊으셨나요 ?