<C0A5C0C0BFEBC7C1B7CEB1D7B7A5B0B3B9DFBAB8BEC8B0A1C0CCB5E528C3D6C1BE292E687770>

Similar documents
다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) <% RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp");

Microsoft PowerPoint - GUI _DB연동.ppt [호환 모드]

PowerPoint Template

웹애플리케이션 취약점 대응 가이드

Windows 8에서 BioStar 1 설치하기

로거 자료실

게시판 스팸 실시간 차단 시스템

Microsoft Word - src.doc

Microsoft Word - ntasFrameBuilderInstallGuide2.5.doc

Research & Technique Apache Tomcat RCE 취약점 (CVE ) 취약점개요 지난 4월 15일전세계적으로가장많이사용되는웹애플리케이션서버인 Apache Tomcat에서 RCE 취약점이공개되었다. CVE 취약점은 W

1) 인증서만들기 ssl]# cat > // 설명 : 발급받은인증서 / 개인키파일을한파일로저장합니다. ( 저장방법 : cat [ 개인키

1) 인증서만들기 ssl]# cat > // 설명 : 발급받은인증서 / 개인키파일을한파일로저장합니다. ( 저장방법 : cat [ 개인키

untitled

API STORE 키발급및 API 사용가이드 Document Information 문서명 : API STORE 언어별 Client 사용가이드작성자 : 작성일 : 업무영역 : 버전 : 1 st Draft. 서브시스템 : 문서번호 : 단계 : Docum

PowerPoint 프레젠테이션

10.ppt

PowerPoint Template

SQL Developer Connect to TimesTen 유니원아이앤씨 DB 기술지원팀 2010 년 07 월 28 일 문서정보 프로젝트명 SQL Developer Connect to TimesTen 서브시스템명 버전 1.0 문서명 작성일 작성자

untitled

PowerPoint 프레젠테이션

Microsoft PowerPoint 세션.ppt

Microsoft PowerPoint - [Practice #1] APM InstalI.ppt

< FBFF9B0A320BEC7BCBAC4DAB5E520C0BAB4D0BBE7C0CCC6AE20C5BDC1F620B5BFC7E220BAB8B0EDBCAD283131BFF E302028C8A8C6E4C0CCC1F620BEF7B

Microsoft PowerPoint 웹 연동 기술.pptx

< 목차 > Ⅰ. 개요 3 Ⅱ. 실시간스팸차단리스트 (RBL) ( 간편설정 ) 4 1. 메일서버 (Exchange Server 2007) 설정변경 4 2. 스팸차단테스트 10

The Pocket Guide to TCP/IP Sockets: C Version

SAS9.2_SAS_Enterprise_Miner_install_guide_single_user_v2

<C0CCBCBCBFB52DC1A4B4EBBFF82DBCAEBBE7B3EDB9AE2D D382E687770>

<4D F736F F F696E74202D203130C0E52EBFA1B7AF20C3B3B8AE205BC8A3C8AF20B8F0B5E55D>

JSP 의내장객체 response 객체 - response 객체는 JSP 페이지의실행결과를웹프라우저로돌려줄때사용되는객체이다. - 이객체는주로켄텐츠타입이나문자셋등의데이터의부가정보 ( 헤더정보 ) 나쿠키 ( 다음에설명 ) 등을지정할수있다. - 이객체를사용해서출력의방향을다른

제목 레이아웃

Eclipse 와 Firefox 를이용한 Javascript 개발 발표자 : 문경대 11 년 10 월 26 일수요일

1. Windows 설치 (Client 설치 ) 원하는위치에다운받은발송클라이언트압축파일을해제합니다. Step 2. /conf/config.xml 파일수정 conf 폴더에서 config.xml 파일을텍스트에디터를이용하여 Open 합니다. config.xml 파일에서, 아

< 목차 > 1. 악성코드은닉동향요약 1 2. 홈페이지은닉형악성코드통계 2 - 유포지탐지 국가별현황 2 - 대량경유지가탐지된유포지 TOP 악성코드유형별비율 4 - 악성코드취약점유형별비율 4 - 악성코드수집및분석결과 5 - 경유지탐지 업종별비율 9 3. 악성코

var answer = confirm(" 확인이나취소를누르세요."); // 확인창은사용자의의사를묻는데사용합니다. if(answer == true){ document.write(" 확인을눌렀습니다."); else { document.write(" 취소를눌렀습니다.");

SOFTBASE XFRAME DEVELOPMENT GUIDE SERIES HTML 연동가이드 서울특별시구로구구로 3 동한신 IT 타워 1215 호 Phone Fax Co

*2008년1월호진짜

Secure Programming Lecture1 : Introduction

PHP & ASP

DBMS & SQL Server Installation Database Laboratory

슬라이드 1

Observational Determinism for Concurrent Program Security

슬라이드 1

Cookie Spoofing.hwp

< FC8A8C6E4C0CCC1F620B0B3B9DF20BAB8BEC8B0A1C0CCB5E5C3D6C1BE28C0FAC0DBB1C7BBE8C1A6292E687770>

Dialog Box 실행파일을 Web에 포함시키는 방법

쉽게 풀어쓴 C 프로그래밊

윈도우시스템프로그래밍

1. efolder 시스템구성 A. DB B. apache - mod-perl - PHP C. SphinxSearch ( 검색서비스 ) D. File Storage 2. efolder 설치순서 A. DB (MySQL) B. efolder Service - efolder

Poison null byte Excuse the ads! We need some help to keep our site up. List 1 Conditions 2 Exploit plan 2.1 chunksize(p)!= prev_size (next_chunk(p) 3

쉽게 풀어쓴 C 프로그래밍

제이쿼리 (JQuery) 정의 자바스크립트함수를쉽게사용하기위해만든자바스크립트라이브러리. 웹페이지를즉석에서변경하는기능에특화된자바스크립트라이브러리. 사용법 $( 제이쿼리객체 ) 혹은 $( 엘리먼트 ) 참고 ) $() 이기호를제이쿼리래퍼라고한다. 즉, 제이쿼리를호출하는기호

BEA_WebLogic.hwp

1. 자바프로그램기초 및개발환경 2 장 & 3 장. 자바개발도구 충남대학교 컴퓨터공학과

슬라이드 1

8 장데이터베이스 8.1 기본개념 - 데이터베이스 : 데이터를조직적으로구조화한집합 (cf. 엑셀파일 ) - 테이블 : 데이터의기록형식 (cf. 엑셀시트의첫줄 ) - 필드 : 같은종류의데이터 (cf. 엑셀시트의각칸 ) - 레코드 : 데이터내용 (cf. 엑셀시트의한줄 )


<4D F736F F F696E74202D20B5A5C0CCC5CDBAA3C0CCBDBA5F3130C1D6C2F75F31C2F7BDC32E >

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

Microsoft Word - SKINFOSEC-CHR-026- Mass SQL Injection 탐지 우회분석 보고서.doc

Webtob( 멀티도메인 ) SSL 인증서갱신설치가이드 본문서는주식회사한국기업보안에서 SSL 보안서버인증서설치를위해작성된문서로 주식회사한국기업보안의동의없이무단으로사용하실수없습니다. [ 고객센터 ] 한국기업보안. 유서트기술팀 Copyright 201

XSS Attack - Real-World XSS Attacks, Chaining XSS and Other Attacks, Payloads for XSS Attacks

2009년 상반기 사업계획

iii. Design Tab 을 Click 하여 WindowBuilder 가자동으로생성한 GUI 프로그래밍환경을확인한다.

PowerPoint Presentation

구축환경 OS : Windows 7 그외 OS 의경우교재 p26-40 참조 Windows 의다른버전은조금다르게나타날수있음 Browser : Google Chrome 다른브라우저를사용해도별차이없으나추후수업의모든과정은크롬사용 한

Microsoft Word - Windows_apahce_php_CUBRID2008

Oracle hacking 작성자 : 임동현 작성일 2008 년 10 월 11 일 ~ 2008 년 10 월 19 일 신규작성 작성내용

슬라이드 1

한국에너지기술연구원 통합정보시스템설치방법설명서 한국에너지기술연구원 지식정보실 - 1 -

HLS(HTTP Live Streaming) 이용가이드 1. HLS 소개 Apple iphone, ipad, ipod의운영체제인 ios에서사용하는표준 HTTP 기반스트리밍프로토콜입니다. 2. HLS 지원대상 - 디바이스 : iphone/ipad/ipod - 운영체제 :

대량문자API연동 (with directsend)

0. 들어가기 전

<4D F736F F F696E74202D20B8AEB4AABDBA20BFC0B7F920C3B3B8AEC7CFB1E22E BC8A3C8AF20B8F0B5E55D>

4S 1차년도 평가 발표자료

MySQL-.. 1

강의 개요

#WI DNS DDoS 공격악성코드분석

Microsoft PowerPoint - web-part03-ch20-XMLHttpRequest기본.pptx

C# Programming Guide - Types

슬라이드 1

AhnLab_template

Windows Server 2012

untitled

문서의 제목 나눔고딕B, 54pt

취약점분석보고서 Simple Web Server 2.2 rc2 Remote Buffer Overflow Exploit RedAlert Team 안상환

중간고사

InsertColumnNonNullableError(#colName) 에해당하는메시지출력 존재하지않는컬럼에값을삽입하려고할경우, InsertColumnExistenceError(#colName) 에해당하는메시지출력 실행결과가 primary key 제약에위배된다면, Ins

PowerPoint 프레젠테이션

메뉴얼41페이지-2

Microsoft PowerPoint - 11주차_Android_GoogleMap.ppt [호환 모드]

슬라이드 1

EDB 분석보고서 (04.06) ~ Exploit-DB( 에공개된별로분류한정보입니다. Directory Traversal users-x.php 4.0 -support-x.php 4.0 time-

PowerPoint Presentation

Data Sync Manager(DSM) Example Guide Data Sync Manager (DSM) Example Guide DSM Copyright 2003 Ari System, Inc. All Rights reserved. Data Sync Manager

하둡을이용한파일분산시스템 보안관리체제구현

PowerPoint 프레젠테이션

** 5 개이발생한주요소프트웨어별취약점세 EDB 번호취약점종류공격난이도공격위험도취약점이름소프트웨어이름

Transcription:

일러두기 o 행정안전부 ( 정부통합전산센터 ) 는사이버침해를방지하기위해 24 365 일쉴틈 없는보안관제와주기적인보안점검등정보보호활동을수행하고있습니다. o 하지만, 사이버침해의주요대상이되는홈페이지의웹프로토콜은기본적으로누구에게나개방되어있기때문에, 전통적인침입차단시스템을이용한방어가용이하지않으며, 이러한특성을이용한새로운위협이지속적으로발견되고있습니다. o 이러한이유로, 행정안전부 ( 정부통합전산센터 ) 에서는홈페이지에대한근본적인보안강화를위해, 국가정보원, 한국인터넷진흥원, OWASP 1) 등국내외전문기관에서정의한홈페이지개발보안고려사항을분류, 웹어플리케이션개발보안가이드 2010 을발간하게되었습니다. o 본가이드에서는 12 개보안사항에대한상세설명과함께취약여부를점검 할수있는방법및위험도, 보호대책을제공합니다. 1) OWASP : The Open Web Application Security Project (Http://www.owasp.org)

웹어플리케이션개발보안항목요약 o 국가정보원의 홈페이지보안관리매뉴얼. 에명시된홈페이지 8대취약점과한국인터넷진흥원의 홈페이지개발보안가이드 의 10대취약점, OWASP에서발표한 10대가장심각한웹어플리케이션보안취약점 에명시된 10가지취약점등 28가지취약점을정부통합전산센터의환경을고려하여, 웹어플리케이션개발시고려해야할 12가지점검항목으로재분류하였습니다. 점검항목국가정보원 KISA OWASP 1 스크립트삽입 (XSS) O O O 2 스크립트요청참조 (CSRF) O 3 악성파일실행 O O 4 SQL 구문삽입 O O O 5 URL/ 파라메터조작 O O 6 파일업로드 O O O 7 파일다운로드 O O O 8 URL강제접속 / 인증우회 O O 9 서비스메소드설정 O 10 에러처리및기타정보노출 O O 11 ID/PW 관리 O 12 환경설정보안고려사항 O O O 위항목은홈페이지개발단계에서고려하여야할보안점검항목으로보안진단항목과는다를수있음.

목 차 1. 스크립트삽입 (XSS) 1 2. 스크립트요청참조 (CSRF) 5 3. 악성파일실행 7 4. SQL 구문삽입 9 5. URL/ 파라메터조작 11 6. 파일업로드 15 7. 파일다운로드 17 8. URL강제접속 / 인증우회 19 9. 서비스메소드설정 25 10. 에러처리및기타정보노출 25 11. ID/PW 관리 25 12. 환경설정보안고려사항 25 < 별첨 > ActiveX Control 개발가이드

1. 스크립트삽입 (XSS) 개요 o 스크립트삽입 (XSS:Cross Site Script) 은악성스크립트를홈페이지게시판, 전자메일등을통해유포하여, 사용자가해당게시물또는메일을클릭하였을때악성스크립트가실행되는것이며, o 공격자는스크립트삽입을이용하여사용자의개인정보, 로그인정보, 내부자료등을탈취하여 2차적인공격을수행한다. [ 그림 1 ] 스크립트삽입 (XSS) 점검예시 o 홈페이지내게시판에글쓰기시작성자, 제목, 본문등에 XSS 스크립트를입력예시 ) 1. <script>alert("xss")</script> 2. <sc<script>ript>alert("xss")</sc</script>ript> 3. %3Cscript%3Ealert%28%22XSS%22%29%3C/script%3E 1

[ 그림 2 ] 게시물에스크립트삽입 o 취약시스템의경우게시물보기를실행하면, 아래와같이팝업이발생 [ 그림 3 ] XSS 취약시스템 공격대상 o 공격대상언어 : 다음과같은스크립트나언어가스크립트삽입공격대상이된다. JavaScript, VBScript, ActiveX, HTML, Flash o 공격시도위치 : 다음과같은입력부분에서스크립트삽입공격을시도한다. 게시판글쓰기화면 ( 제목, 글내용등데이터를입력할수있는모든필드 ) 게시판글보기화면에서댓글달기 쿠키값 데이터베이스질의문 2

피해유형 o 페이지변조 : 이미지나사운드를삽입할수있다. o 쿠키변형 : 쿠키자체를변형시켜서쿠키에악의적인코드를넣어둘수있다. o 쿠키유출 : 사용자쿠키값을획득하여, 인증우회에사용한다. o 개인정보유출 : 웹페이지내의패스워드나신용카드번호와같은민감한정보를유출시킬수있다. o 악성프로그램다운로드 : 스크립트내에악성프로그램을다운로드받는사이트를링크시키며, 사용자가모르는사이악성프로그램이 PC에설치된다. 보호대책 o 스크립트삽입공격에대한근본적인대응방법은사용자로부터입력받는모든값을서버에서검증후입력받도록하는방식을사용하는것이다. o 입력값검증의방법은사용자입력으로사용가능한문자를정해놓고, 나머지모든문자를필터링하는방법을사용하여야한다. - 검증대상입력값 : 스크립트정의어 (<script>, <object>, <applet>, <embed> 등 ) - 어플리케이션에서사용자들의모든입력값을점검, 허용된데이터만입력할수있도록구현 - 입력되는특수문자는 Entity형태로변경하여저장. o 이때, 검증은반드시서버에서이루어지도록개발하여야한다. 3

2. 스크립트요청참조 (CSRF) 개요 o 스크립트요청참조 (CSRF) 는공격자가사용자의 Cookie 값이나 Session정보를의도한사이트로보내거나특정한동작을유발하는스크립트를글에삽입하여사용자가게시물등을클릭할경우공격자가원하는동작이실행되는것이며, o 일반적으로악용되는태그들은 <Script>, <OBJECT>, <APPLET>,<EMBED>, <IMG>, <FORM> 등이있다. [ 그림 4 ] 스크립트요청참조 (CSRF) 점검방법 o 글쓰기후전송되는 URL과파라미터값을복사한다. - http://aa.co.kr/write_ok.php?cmdproc=write&name=test&passwd=test&title=test&body=test o 새로운글을작성하고, 글내용중에 <IMG> 태그를사용하여, 아래와같이복사한 URL과파라미터를붙여넣는다. - <img width=0 height=0 src="http://aa.co.kr/write_ok.php?cmdproc=write&name=test&passwd=test&title=test&body=test"> 4

[ 그림 5 ] <IMG> 태그내파라미터값삽입 o 등록된게시물열람시동일한작업이반복됨을확인할수있다. [ 그림 6 ] 동일작업반복확인 5

공격대상 o 공격대상이되는부분 : 글쓰기시 HTML 태그가허용된게시판 o 공격대상이되는태그 : <script>, <embed>, <object>, <applet>, <img> 등 피해유형 o 정보노출 : 쿠키또는세션정보노출 o 동일작업반복 : 게시물클릭시공격자가원하는동작수행 보호대책 o CSRF를예방할수있는최선의방안은모든입력값을상세히검증하는것으로헤더, 쿠키, 질의문, 폼필드, 숨겨진필드등과같은모든파라미터들을엄격한규칙에의해서검증하여 HTML을사용할경우태그내에 html,?, & 등이포함되지않도록하여야한다. o 이때, 검증은반드시서버에서이루어지도록개발하여야한다. 6

3. 악성파일실행 개요 o URL 이나파일시스템참조등외부객체참조를사용하는어플리케이션에서입력파일또는입력외부객체를검증하지않을때발생되며, PHP파일연결, OS명령어삽입, 제한되지않은파일업로드등다양한유형이존재한다. o 악성파일실행은원격코드실행, 원격루트킷설치와시스템손상등을야기한다. 점검방법 o 테스트서버에임의의파일을저장한다.( 파일명 : testfile.txt) o URL중외부객체를참조하는 URL을확인한다 - http://www.abc.com/activities_view.php?id=104&page=1&base_dir=/test o 외부객체를참조하는 URL부분을테스트서버의파일을참조하도록수정한다. - http://www.abc.com/activities_view.php?id=104&page=1&base_dir=http:// 테스터서버 /testfile.txt o 테스트서버에저장해놓은파일의내용이브라우져에보이는경우취약시스템 공격대상 o 홈페이지소스중 URL파일명함수나로컬파일을포함시기키위해사용자에게파일명선택을허용하도록개발된코드 o 특히, PHP의경우아래와같은함수가공격의대상이된다 include(), include_once(), require(), requier_once(), fopen(), imagecreatefromxxx(), file(), file_get_contents(), copy(), delete(), unlink(), upload_tmp_dir() $_FILES, move_uploaded_file() 7

피해유형 o 원격루트킷설치와전체시스템손상 : 원격시스템에악성코드등을저장후실행시키게되면악성코드가동작하면서로컬시스템에해킹프로그램설치등이가능하다. 공격자는이를통해전체시스템을파괴할수있으며, 원격코드의종류에따라중요정보노출등의위험이존재한다 보호대책 o 다른객체를참고할때에는참고대상이되는객체이름부분에 URL형태 또는 정보시스템외부의파일 이입력되지않도록구현하고, o 특히 PHP언어로웹어플리케이션을개발할때에는 - Allow_rul_fopen, allow_url_include 를비활성화 - register_global 비활성화 - 사용자입력에아래의함수를포함한입력값금지 include(), include_once(), require(), requier_once(), fopen(), imagecreatefromxxx(), file(), file_get_contents(), copy(), delete(), unlink(), upload_tmp_dir() $_FILES, move_uploaded_file() 8

4. SQL 구문삽입 개요 o SQL 구문삽입 (SQL Injection) 은 URL의파라미터값등의전송되는문자열에대해웹서버에서유효성을검증하지않아, SQL 구문이직접 DB서버로전송되어실행되는것이며, o 공격자는 SQL 구문삽입을이용하여로그인인증우회, 홈페이지변조, 내부자료유출등을시도한다 점검방법 o 정상 URL/ 파라미터에 을추가하여 SQL 오류메시지 가나타나면공격에취약함. - 정상URL : http://xxx.com/view.jsp?srch_keyword=asdf - URL조작 : http://xxx.com/view.jsp?srch_keyword=asdf' or 2=2-- o 또는, 사용자로그인창에아래와같은 SQL 구문을입력하였을때로그인이된다면공격에취약함 - ' or 1=1 -- (Oracle, Sybase), ' or 1=1#(MS-SQL), ' or 1=1;(MYSQL) [ 그림 7 ] 로그인창에 SQL 구문입력 [ 그림 8 ] 로그인성공 9

공격대상 o 대상공격삽입부분 : 다음과같은부분이공격대상이된다. 사용자로그인입력폼 웹 URL 파라미터 쿠키값 피해유형 o 데이터베이스구조노출 : 의도적으로 오류 가발생되는 SQL 쿼리문을삽입하여데이터베이스구조파악 o 데이터베이스자료유출 : 주요자료외부유출 o 데이터베이스데이터변조 : SQL 쿼리문조작을통하여홈페이지내용을변조. o 인증우회 : 타사용자로로그인성공 보호대책 o 데이터베이스와연동하는스크립트의모든파라미터들을점검하여사용자의입력값에 SQL 쿼리문이삽입되지않도록특수문자 (,, \, ;, :, %, Space, --, +, <, >, (, ), #, & 등 ) 를필터링한다. o 입력문자열대한길이를제한한다. o 데이터베이스와연동하는스크립트의모든파라미터들을점검하여사용자의입력값에 SQL 구문으로사용되는문자열 (@variable, @@variable, print, set, or, union, and, insert, openrowset 등 ) 을필터링한다. o 데이터베이스의에러메시지를사용자에게보여주지않도록수정한다. o 웹어플리케이션이사용하는데이터베이스의사용자권한을제한한다. o php.ini 설정중 magic_quotes_gpc 값을 On으로설정한다. - magic_quotes_gpc 옵션의역할은 GPC(Get, Post, Cookie) 를통해넘어오는문자열중에서 (sing-quote) 와 (double-quote), \(backslash), NULL 값의앞에자동으로백슬래쉬문자를붙여주는기능을한다. 10

; Magic quotes ; Magic quotes for incoming GET/POST/Cookie data. magic_quotes_gpc = On ; Off 에서 On 으로변경 ; Magic quotes for runtime-generated data, e.g. data from SQL, form exec(), etc. magic_quotes_runtime = Off ; Use Sybase-style magic quotes(escape ' with " instead of \'). magic_quotes_sybase = Off 11

5. URL/ 파라메터조작 개요 o 공격자는전송되는 URL 또는 URL의파라미터를조작하여전송함으로써웹서버로하여금공격자가원하는행위를하도록시도한다. 이때, 취약한시스템에서는인증우회, 관리자권환획득, 인가되지않은게시판에글쓰기등인가되지않은시도가성공한다. 점검방법 o 웹프락시도구를이용하여파라미터를조작, 실명인증을후회시도 1. 글쓰기전실명인증시도 [ 그림 9 ] 실명인증화면 2. 정상적인실명인증후글쓰기시도 3. 글쓰기후전송되는패킷을가로채어 글쓴이 이름을변경 [ 그림 10 ] 글쓴이이름변경 12

4. 글쓰기완료시변경시킨이름으로글쓰기가성공됨. [ 그림 11 ] 실명인증우회성공 o URL 의파라미터값을조작하여글쓰기, 수정등이가능한지확인 1. 글쓰기 : board.php?mode=list에서 mode값을 write, add, insert 등으로변경 2. 글수정 : board.php?mode=view&idx=1에서 mode값을 update, modify, edit 등으로변경 3. 글삭제 : board.php?mode=delete&idx=1에서 idx값을다른게시물번호로변경 공격대상 o 대상공격삽입부분 : 다음과같은부분이공격의대상이된다. 웹페이지에서게시물을조회하는페이지 웹게시판의글쓰기페이지 피해유형 o 인증우회 : 정상적인로그인이아닌파라미터조작을통하여인증우회가가능하다. 이를통해공격자는일반사용자에게는글쓰기권한이없는, 공지사항 등의게시판에게시물을게시하는등홈페이지조작이가능하다. o 게시물조작 : 다른사용자가작성한글을수정및삭제할수있다. 보호대책 o 글쓰기, 글수정, 글삭제 URL등사용자의조작에의해변경이일어날수있는페이지에대해서는정상적인사용자인지여부를확인하는인증절차를삽입한다. o 파라미터및 URL을입력받을때, 서버에서직전에응답한정보와입력되는정보가다른부분이존재하는지여부를체크하여, 실명인증우회등인증우회를방지한다. 13

6. 파일업로드 개요 o 파일첨부를할수있는게시판에일반적으로허용된파일 ( 이미지파일, 워드파일등 ) 이외에악의적인스크립트가포함된소스파일 (.jsp,.php,.asp 등 ) 을첨부할수있게되면, o 공격자는악성스크립트등재후, 서버상에서스크립트를실행시켜쉘획득, 서버변조등웹서버를장악할수있다. 점검방법 o 사전준비 - 악성스크립트파일준비 : a.php - 악성스크립트파일을복사하여확장자를이미지파일로변경 : a.jpg - 웹프락시도구실행 : Paros 등 o 게시판글쓰기실행 [ 그림 12 ] 게시물작성 14

o 첨부파일또는글편집기의파일업로드버튼을이용하여파일첨부시도 (a.jpg) [ 그림 13 ] 첨부파일첨부화면 o 전송되는패킷을웹프락시도구를이용하여가로챈후파라미터부분의 "a.jpg" 를 a.php" 로변경후전송 [ 그림 14 ] 파라미터변조 o 게시물작성완료후첨부파일의등록정보등을이용하여첨부파일의경로확인 o 악성스크립트실행 [ 그림 15 ] 스크립트실행 15

공격대상 o 대상공격부분 : 다음과같은기능이있는웹게시판이파일업로드공격의대상이된다. 파일첨부기능이있는웹게시판 게시판 Editor의이미지첨부기능이있는웹게시판 피해유형 o 서버원격제어 : 쉘프로그램을통하여웹서버를원격제어할수있다. o 홈페이지위 / 변조 : 업로드된쉘프로그램실행을통한홈페이지위 / 변조가가능하다. 보호대책 o 첨부파일이저장되는 Upload 디렉토리는실행권한을제거하여운영한다. - IIS 보안설정설정 제어판 관리도구 인터넷서비스관리자선택 해당 Upload 폴더에오른쪽클릭을하고등록정보 디렉토리 실행권한을 없음 으로설정 - Apache 설정 : 설정후 Apache 데몬 Restart 해야한다. Apache 설정파일인 httpd.conf의해당디렉토리에대한문서타입을컨트롤하기위해 Directory 세션의 AllowOverride 지시자에서 FileInfo 또는 All 추가 <Directory "/usr/local/apache"> AllowOverride FileInfo( 또는 All)...... </Directory> - 파일 Upload 디렉토리에.htaccess 파일을만들고다음과같이 AddType 지시자를이용, 현재서버에서운영되는 Server Side Script 확장자를 text/html로 MIME Type을재조정하여 Upload된파일이실행되지않도록설정하거나 FileMatch 지시자를이용하여 *.ph, *.inc, *.lib 등의 Server Side Script 파일에대해서직접 URL 호출을금지시킨다. 16

<.htaccess> <FileMatch "\.(ph inc lib)"> Order allow, deny Deny from all </FileMatch> AddType text/html.html.htm.php.php3.php4.phtml.phps.in.cgi.pl.shtml.jsp o 첨부파일의확장자필터링처리 - 웹서버의서비스환경을고려하여 office 문서, text, 이미지등업로드를허용할파일을지정한후지정된확장자이외의파일이업로드되지않도록제한한다. 이때, 확장자점검은반드시서버단에서점검하여야한다. 17

7. 파일다운로드 개요 o 웹어플리케이션에서상대경로를사용할수있도록설정되어있는경우, 상대경로표시문자열인../ 를통해허가되지않은상위경로로이동하여시스템주요파일, 소스코드등중요자료의열람이가능하며, o 공격자는이러한방법으로 /etc/passwd, /etc/shadow, /etc/host 등시스템정보가포함되어있는주요파일및웹소스파일을다운로드, 시스템계정및패스워드, DB접속정보등을획득하여시스템침투, 내부자료유출등 2차적인공격에악용할수있다. 점검방법 o 게시판의파일다운로드기능이있는게시물의이름을변경하여시스템파일열람시도 o 정상적인게시판파일다운로드 URL확인 - http://www.kkk.com/download.jsp?pfilename =07 년매출예산결산보고서 - http://www.kkk.com/download.jsp?savepath=/upload/ &filename= 보고서 &upfilename= 보고서 o 정상적인 URL을../ 이용하여조작 - http://www.kkk.com/download.jsp?pfilename=./.././../../etc/./././passwd - http://www.kkk.com/download.jsp?savepath= /etc/&filename=passwd&upfilename=passwd [ 그림 16 ] 시스템파일다운로드화면 18

공격대상 o 대상공격부분 : 다음과같은부분이공격의대상이된다. 게시판의첨부파일다운로드기능 웹 URL 피해유형 o 주요파일노출 : 패스워드파일등시스템주요파일이유출된다. o 소스파일노출 : 웹어플리케이션소스파일이유출되어공격자는 DB접속정보등내부접속정보를획득가능하다. 보호대책 o 파일다운로드시파일명을직접 URL에서사용하거나입력받지않도록하며게시판이름과게시물번호를이용하여서버측에서데이터베이스재검색을통하여해당파일을다운로드할수있도록하여야한다. o 다운로드위치는지정된데이터저장소를지정하여사용하고, 데이터저장소상위디렉토리로이동되지않도록설정한다. o PHP를사용하는경우 php.ini에서 magic_quotes_gpc를 On으로설정하여.\./ 와같은문자에대해대응도가능하도록한다. 19

8. URL 강제접속 / 인증우회 개요 o 사용자권한관리가정상적으로이루어지지않는홈페이지의관리자또는사용자인증후접속되는페이지의 URL을주소창에직접입력하거나, 쿠키를조작하는방법이며 o 공격자는이러한방법으로관리자메뉴페이지에로그인과정없이접속하여관리자페이지를조작, 회원정보열람등민감한정보를획득할수있고, 공지사항등인증이필요한글쓰기게시판에악의적인게시물을게시할수있다. 점검방법 o 로그인을하지않고, 로그인이후접속되는페이지의 URL을입력하여페이지가정상적으로표시되는지를확인한다. - 로그인페이지확인 : http://www.kkk.com/jsp/admin/admin_login.jsp - 로그인이후의페이지를유추하여강제접속 : http://www.kkk.com/jsp/admin/admin.jsp [ 그림 17 ] 관리자페이지강제접속 20

o 회원가입시실명인증또는주민등록번호유효성검증을우회하여가명의올바르지않은주민등록번호로가입가능한지확인한다. - 실명인증확인후보여지는회원가입폼화면이직접 URL 에입력하여보이는지확인한다 [ 그림 18 ] 회원가입화면 - 주민등록번호인증우회방법 1 회원가입폼화면을열기전웹프락시툴을이용하여응답되는패킷중주민등록번호유효성체크하는자바스크립트부분을삭제한다 2 회원가입폼화면에서정상적인주민등록번호입력후전송되는패킷을웹프락시툴을이용하여주민등록번호부분을수정한다 [ 그림 19 ] 주민등록번호조작화면 21

o 세션의쿠키값이평문 (Plain text) 으로되어있는지확인하고중요정보나개인정보들이포함되어있지않은지확인하여웹프락시도구를사용하여전송되는쿠키값변조를시도한다. - 홈페이지에자신의계정생성 - 로그인시웹프락시도구를사용하여전송되는정보중쿠키값에개인식별정보가포함되어있는지확인 - 로그인시웹프락시도구를사용하여, 쿠키값을변경 [ 그림 20 ] 쿠키값변경 ( 웹프락시도구사용 ) - 다른사용자의정보획득및수정이가능하다. [ 그림 21 ] 타사용자의정보획득 22

공격대상 o 대상공격부분 관리자메뉴페이지 사용자정보페이지 회원가입페이지 사용자정보 (ID, PW, 권한등 ) 가포함되어평문으로전송되는쿠키값 피해유형 o 회원전용페이지노출 : 인증처리를하지않는회원페이지에강제접속하여인증없이회원페이지를열람할수있다. o 관리자권한노출 : 인증우회를통하여홈페이지관리자권한을획득할수있다. o 임의사용자등록 : 실명인증우회를통하여익명의사용자이름과조작된주민등록번호로회원가입가능하다. o 시스템명령실행 : 웹쉘이업로드된경우쿠키조작을통해시스템명령실행이가능하다. o 게시판변조 : 쿠키값에 SQL 삽입취약점을이용하여게시판내용을변조할수있다. 보호대책 o 회원전용페이지나관리자페이지등모든페이지에접근허용금지및권한설정을하고, 인증을거쳐서접근할수있도록한다. 이때, 인증은서버에서실시하도록한다. o SSL과같은기술을사용하여로그인트랜젝션전체를암호화한다. o 인증기능사용시쿠키를이용하지않는다. 23

9. 서비스메소드설정 개요 o Method는웹어플리케이션에서기본적으로제공하는클라이언트와통신하기위한도구로 GET, POST, PUT, MOVE, DELETE 등여러가지 Method 가있으며다양한기능을수행한다. o 공격자는웹서버에허용되어있는 Method 를이용하여파일업로드, 웹서버파일삭제등웹서버를인증없이조작할수있다. 점검방법 o Command창에서명령어로 Method 활성화여부를확인한다 - telnet www.kkk.com 80으로접속 - OPTIONS * HTTP/1.0 [ 그림 22 ] PUT Method 허용여부확인 24

o PUT Method가허용되어있다하더라도, 반드시취약한것은아니며, 아래와같은테스트방법을이용, 점검하여야한다. - telnet victimhost httpport[enter] PUT / 파일이름 HTTP/1.1[enter] Host: victimhost(ip가능 )[enter] Content-Length: 컨텐츠길이 [enter] [enter] : enter를치게되면, 서버에서 content 를입력받을준비를함. 이때입력한컨텐츠가 PUT 뒤에지정한파일이름으로생성됨. ( 화면상에 HTTP/1.1 100 Continue가표시됨, 단, HTTP/1.0에서는빈화면만보임 ) 이후에생성할파일의내용 ( 컨텐츠 ) 를입력하면됨. 이때, 길이는컨텐츠길이에서지정한길이만큼이입력됨 - 공격이성공한경우, 201 Created 또는 200OK로서버는응답함. [ 그림 23 ] PUT Method 테스트 [ 그림 24 ] PUT Method 를이용한파일생성성공 25

공격대상 o 대상공격부분 : 각 Method 에는아래와같은취약점이존재한다. [ 그림 25 ] Method별취약점여부 피해유형 o 홈페이지변조 : PUT 메소드를통한웹페이지파일업로드가가능하며, 이를통해홈페이지변조가가능하다. 보호대책 o POST, GET 외에어플리케이션에서사용되지않는 HTTP 메소드들 (PUT, Delete, Mkdir, Option 등 ) 은모두제한해야한다. o 메소드제거방법은다음과같다. IIS 5.0 HTTP 메소드제한 - WebDAV 사용안함처리 1 레지스트리편집기 (Regedt32.exe) 를시작 2 레지스트리에서다음키를검색함 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC\Parameters 3 편집메뉴에서값추가를누른후다음레지스트리값을추가함값이름 : DisableWebDAV 데이터형식 : DWORD 값데이터 : 1 4 IIS를다시시작한다. 26

[ 그림 26 ] WebDAV 사용안함설정 - 웹서비스사용폴더에쓰기권한및스크립트소스엑세스권한제거 [ 그림 27 ] 웹폴더쓰기권한설정 File System(NTFS/FAT32/FAT16) 의쓰기권한이존재하면게시판혹은업로드컴포넌트 를이용한업로드경로에서도문제가발생하지않음 IIS 6.0 HTTP 메소드제한 - WebDAV 서비스를제거하면 PUT, DELETE 같은위험한메소드외의 GET, POST, TRACE, OPTIONS 메소드만존재함 27

Apache 의 httpd.conf 파일설정방법 <Directory /> [ 그림 28 ] IIS 6.0 HTTP 메소드제한 <LimitExcept GET POST> Order allow,deny deny from all </LimitExcept> </Directory> - 위와같이설정하면정상적으로 Apache 웹서버에로그인권한을가진사용자외에다른사용자는제한된 Method를사용할수없게된다. WebToB 설정방법 - WebToB는기본적으로 GET, POST, HEAD 등을지원하고있으나, PUT, DELETE 등을삭제할때는 http.m 파일내의 *NODE 절에서아래와같이설정, wscfl -i http.m 명령어를실행한후 WebToB를재기동해야한다. - Method = "-PUT, -HEAD, -DELETE, -TRACE" webmain WEBTOBDIR = "/usr/local/webtob", SHMKEY = 69000, 28

DOCROOT = "/usr/local/webto/docs", User = "nobody", Group = "nobody", IndexName = "Index.html", UserDir = public_html", DirIndex = "Index", Method = "-PUT, -DELETE, -MOVE, -OPTIONS", LanguagePrio = "kr" IPlanet 설정방법 - 불필요한메소드제거방법은 obj.conf 파일에서아래와같은방법으로제거하고자하는메소드를입력하여설정한다. <Client method = "TRACE"> AuthTrans fn = "set-variable" remove-headers = "transfer-encoding" set-headers = "content-length: -1" error = "501" </Client> <Client method = "PUT"> AuthTrans fn = "set-variable" remove-headers = "transfer-encoding" set-headers = "content-length: -1" error = "501" </Client> <Client method = "DELETE"> AuthTrans fn="set-variable" remove-headers = "transfer-encoding" set-headers = "content-length: -1" error = "501" </Client> <Client method = "MOVE"> AuthTrans fn = "set-variable" remove-headers = "transfer-encoding" set-headers = "content-length: -1" error = "501" </Client> <Client method = "MKDIR"> 29

AuthTrans fn = "set-variable" remove-headers = "transfer-encoding" set-headers = "content-length: -1" error = "501" </Client> <Client method = "RMDIR"> 5AuthTrans fn = "set-variable" remove-headers = "transfer-encoding" set-headers = "content-length: -1" error = "501" </Client> Tomcat 설정방법 - 불필요한메소드제거방법은 Tomcat 5.5\conf\web.xml 파일에서아래와같이설정되어있는메소드를지우거나주석처리하여설정한다. <security-constraint> <display-name>example Security Constraint</display-name> <web-resource-collection> <web-resource-name>protected Area</web-resource-name> <!-- Define the context-relative URL(s) to be protected --> <url-pattern>/jsp/security/protected/*</url-pattern> <!-- If you list http methods, only those methods are protected --> <http-method>delete</http-method> <http-method>get</http-method> <http-method>post</http-method> <http-method>put</http-method> </web-resource-collection> <auth-constraint> <!-- Anyone with one of the listed roles may access this area --> <role-name></role-name> </auth-constraint> </security-constraint> 30

10. 에러처리및기타정보노출 개요 o 에러페이지는사용자가웹서버에비정상적인요청을하였을때, 웹서버에서해당비정상요청에대해알려주는페이지이며, 300번대, 400번대, 500번대의숫자로표시된다. o 이중, 500번대의코드는서버내부오류를표시하는코드로, 특히 DB에잘못된요청을하였을때, DB쿼리의오류를보여주며, 이를통해 DB의구조가노출될우려가있다. o 또한, 특정시스템의취약점또는작성자의실수로인하여이름과주민등록번호, 통장계좌번호, 신용카드번호등이노출되어해당사용자의정보가직간접적으로이용될수있다. 점검방법 o URL의파라미터를변경하여내부오류를발생시킨다. - 파라미터값변경시도 : ttp://www.kkk.com/board/common.htmlapp&c=1201&page= or 1=2--' o 검색창또는 ID/PW 입력창에특수문자등을입력하여에러메시지발생여부를확인한다. [ 그림 29 ] 500 에러발생화면 31

o 사용자개인정보보기등화면에서마우스오른쪽버튼을클릭한후 소스보기 를선택하거나, 웹프락시도구를사용하여웹브라우저로부터웹서버로전송되는내용을확인하여 type=hidden 으로되어있는필드값을조작한다. o 아래화면에서 user_id 필드의 type 이 hidden 으로되어있으며, 필드값 (value) 을웹프락시도구를사용하여조작하여전송한다. 공격대상 [ 그림 30 ] 히든필드조작 o 대상공격부분 : Defult 에러페이지를통해내부서버의구조가노출될가능성이있다. 개인정보가포함된페이지 소스코드에남아있는주석문 웹서버정보 사용자정보보기화면 로그인시도화면 게시물수정화면 32

피해유형 o 시스템정보노출 : 에러페이지를통해웹서버정보등시스템정보노출가능성이있다. o DB 정보노출 : DB 접속에러메시지를통한 DB 접속정보또는테이블명, 필드명등노출가능성이있다. o 개인정보노출 : 개인정보및중요한정보들이노출될수있다. o 데이터변조 : Paros 등의웹프락시툴을이용하여히든필드로사용하는고정값 ( 예 : 금액, 코드, 아이디, 비밀번호등 ) 의조작이가능하다. o 권한획득 : 사용자의히든필드값을수정하여인증을우회할수있다. 보호대책 o 통일된메시지를출력한다. - 접근된파일이존재하지않거나거부되는경우 : access denied 출력 - 로그인시 ID나패스워드가틀린경우 : 로그인에실패했습니다 출력 - 웹어플리케이션의인수에특수문자입력시 : 특수문자입력불가 메시지출력 o 최종사용자에게스택추적정보, 경로정보와디버그정보제공을금지한다. o 에러메시지를특정 URL로리다이렉트또는예외호출을설정한다. o 히든필드값을그대로사용하지말고, 데이터베이스에서재검색하여값을새로얻어오거나히든필드로전송된값들에대한검증을하도록소스를수정한다. o 히든필드로값을넘기는것보다세션의속성을통하여변수를저장관리하는것이안전하다. 33

11. ID/PW 관리 개요 o 취약한 ID/PW 취약점은일반적으로사용자계정또는관리자계정생성시관리의편의성을위해유추하기쉬운 ID/PW를사용하는취약점이며, o 공격자는해당취약점을이용하여관리자또는사용자 ID/PW를유추하여인가되지않은페이지에접근을시도한다. 점검방법 o 로그인페이지에 ID 와비밀번호를유추하여입력한후로그인성공여부를점검한다. - test/test, admin/admin o 운영시주기적으로사용자계정테이블을점검, 유추하기쉬운 ID 등에대해수정을권고한다. 공격대상 o 대상공격부분 로그인페이지 피해유형 o 관리자권한획득및개인정보유출 : 사용자나관리자의 ID/PW 노출로인한개인정보유출및관리자권한노출이발생할수있다. 34

보호대책 o 웹서비스의회원가입정책중사용자의비밀번호길이및형태에패스워드정책을적용하여비밀번호의길이, ID 포함검사, 영문과숫자의혼합여부를체크한다. 35

12. 환경설정및보안고려사항 개요 o 위에서열거한점검항목이외에웹서버운영상보안적으로고려해야할사항들을기술한다 중요정보를보여주는페이지는캐시를사용하지못하도록설정 o 중요정보를보여주는화면에 no-cache 설정을하지않을경우, 로그아웃을한이후에도 [ 뒤로가기 ] 버튼을사용해서해당내용을볼수있는위험이존재한다. o no-cache 설정을위해서 HTML HEAD 부분에아래내용을추가한다. <meta HTTP-EQUIV="Pragma" CONTENT="no-cache"> Java Class 역컴파일문제 o Java 언어의 Byte-code 특성으로인하여 Java class는쉽게역컴파일이가능하다. 만약 Java Applet에중요정보 ( 예 : 원격지접속을위한 ID/PW, DB 쿼리문, 직접제작한암호화알고리즘, 프로그램로직등 ) 를 hard-coding 했다면, 이를발견한공격자는해당정보를악용할수있는위험성이존재한다. o Sun Microsystems에서 Java 프로그램개발시고려해야할다양한보안사항을제공한다. - Secure Code guidelines(sun Microsystems) : http://www.java.sun.com/securit/seccodeguide.html 36

ASP(Visual Basic, C++, C# 등을사용한모든 ASP에적용 ) o include 파일을보호하기위해일반적인디렉토리 (/lib, /include, /library 등 ) 를사용하지않도록한다. o include 파일들의확장자를.inc나.lib 등을사용하는경우웹페이지상에서텍스트파일로인식하지않도록.asp를붙여서사용한다.( 예 : config.inc.asp, lib.inc.asp 등 ) o ASPError 객체의 output을사용자에게전달하지않도록한다. o SQL 쿼리를 ASP에서직접생성하는것을지양하고, Stored procedure를사용하도록한다. 직접생성방식 strquery = "SELECT something FROM table WHERE foo = '" + var1 + "' AND var = '" + var2 + "'"; Stored procedure 를사용한생성방식 strquery = sp_comefunc(var1, var2) PHP o [PHP 4.0 이상 ] 환경설정 (php.ini) 내용중 register_global을 on 으로설정할경우, PHP 스크립트의변수값을임의로변경할수있는취약성이존재한다. 따라서 register_global은 off 로설정한후, $_GET, $_POST 문을사용해서사용자가전달한값을얻어야한다. o PHP스크립트오류를사용자에게보내지않기위해서 PHP 환경설정 (php.ini) 에서아래와같이설정한다. log_error = On display_errors = Off o 특정파일의내용보기방지 - 오류메시지가발생된 CGI의물리적위치와에러부분이표시되는데, 이를이용하여공격자는 /lib, /inc, /admin 등보여지지말아야할정보가노출되는위험성이존재한다. 이를제거하기위해 php.ini 내의설정중에서 display_errors 값을 Off로설정한다. 37

- 각코딩라인에 @ 를사용하여해당라인의에러메시지를출력하지않는방법을사용한다 $abc = @mysql_connect($connect, $id, $pw); @$abc = mysql_connect($connect, $id, $pw); o include 파일을보호하기위해일반적인디렉토리 (/lib, /include, /library 등 ) 를사용하지않도록한다. o include 파일들의확장자를.inc나.lib 등을사용하는경우웹페이지상에서텍스트파일로인식하지않도록.php를붙여서사용한다.( 예 : config.inc.php, lib.inc.php 등 ) MASS SQL Injection 예방을위한 IIS웹서버및 MS-SQL 설정 o 자세한오류내용표시차단 - IIS 웹서버에서는기본적으로웹서비스의오류가발생할때, 자세한오류메시지를접속자에게표시하게되어있다. 이설정을변경하여공격자가오류메시지를통해유용한정보를수집할수없도록수정해야한다. [ 그림 31 ] 스크립트오류메시지설정화면 - 일반적인 SQL Injection 공격의경우오류메시지를기반으로정보를추출하게되므로, 이설정변경만으로도방어효과를볼수있다. 다만, Blindfolded SQL Injection 이나시스템 38

명령어를수행하는 SQL Injection공격은차단할수없으므로반드시프로그램수정의보완조치로활용해야한다. o SQL 서버보안강화 - 웹페이지와 MS-SQL 서버를연동할때, 데이터베이스의관리자계정인 SA 계정을사용하게되면공격자가악용할수있으므로매우위험하다. 그러므로반드시사용자계정을사용하고최소권한만을할당하여사용해야한다. - 또한, MASS SQL Injection 스크립트의경우시스템테이블인 Syscolumns와 Sysobjects의정보를이용하고있으므로, 반드시필요하지않은경우라면사용자계정이나 public 계정에할당되어있는 SELECT 권한을제거하는것이안전하다. [ 그림 32 ] Public 계정권한제어 관리자페이지에대한접근제어 o 관리자페이지에는접근권한을가진 IP에서만접근가능하도록 ACL(Access Control List) 을설정한다. IIS 웹서버에서보호대책 - 설정 제어판 관리도구 인터넷서비스관리자선택 - 해당관리자페이지폴더에오른쪽클릭하고등록정보 디렉토리보안 IP 주소및도메인이름제한 편집버튼을클릭 - 액세스거부를선택하고추가버튼을클릭하여관리자호스트 IP 또는서브넷을등록 39

[ 그림 33 ] IIS 보호설정 Apache 웹서버에서보호대책 - Apache 웹서버의환경설정파일인 httpd.conf 파일의 Directory 세션의 AllowOverride 지시자에서 AuthConfig 또는 All을추가하여.htaccess를통하여사용자계정, 사용자패스워드를등록한사용자만접근이가능하도록하고관리자디렉토리 (admin) 에대해특정 IP에대해서만접근이가능하도록설정한다. # 먼저접근을제어하고자하는디렉토리에대한상위디렉토리정의에 #AllowOverride 부분이 All', 'AuthConfig', 'FileInfo' 등으로설정 <Directory /home/www/admin/> AllowOverride AuthConfig Order deny, allow Deny from all Allow from 10.10.100.7 10.10.2.1/24 </Directory> AccessFileName.htaccess <File ~ "^\ht"> Order allow, deny Deny from all </Files> <.htaccess> AuthName " 인증이필요한관리자페이지입니다. AuthType Basic 40

AuthUserFile /home/www/admin/.htpasswd AuthGroupFile /dev/null require valid-user Order deny, allow Deny from all Allow from 10.10.100.7 10.10.2.1/24 - 관리자페이지와같이인증이필요한디렉토리에.htaccess 파일을만들고 admin 계정의패스워드 ~apache/bin/htpasswd 를이용하여사용자정보파일 (.htpasswd) 을생성한다. <Directory /home/www/admin/> # ~apache/bin/htpasswd -c /home/www/admin/.htpasswd [ 사용자명 ] New password: ******** Re-type new password: ******** Adding password for user [ 사용자명 ] # 주의사항 - Apache 서버의경우 AllowOverride 지시자를변경시 apache restart가필요하다. - 관리자페이지의디렉토리명변경시웹프로그램에서경로명을지정하는경우수정하여야한다. - 관리자디렉토리에는일반사용자의접근이필요한파일이존재하지않아야한다. o 관리자인증후접속할수있는페이지의경우해당페이지주소를직접입력하여접속하지못하도록관리자페이지각각에대하여관리자인증을위한세션을관리한다. 디렉토리리스팅방지설정 o IIS - [ 제어판 ] [ 관리도구 ] 의 [ 인터넷서비스관리자 ]( 혹은 [ 인터넷정보서비스 ]) 메뉴의 [ 기본웹사이트 ] 에서마우스오른쪽클릭, 속성 부분을보면 기본웹사이트등록정보 에서 홈디렉토리 부분을클릭한후 디렉토리검색 (B)' 부분의체크를해지한다. 41

o Apache - 서버에서 httpd.conf 라는파일을찾음 - 파일내용중 Options 항목뒤에 Indexes라는단어를지우고파일을저장한다. 이때, Options는디렉토리별로설정할수있게되어있으므로모든디렉토리에대해서 Options 항목의 Indexes를제거후 Http 프로세스를재기동한다.... <Directory "/usr/local/www"> Options Indexes <- 제거 </Directory>... Default Page 제거 o 초기서비스설치시디폴트로설치되는컨텐츠및서비스들을 Disable 시킨다. o 패스워드변경, 경로변경등접근제한설정을한다. o 디폴트디렉토리 (/htdocs, /cgi-bin 등 ) 를삭제또는변경한다. o 디폴트페이지 (manual, sample 등 ) 를삭제또는변경한다. 웹어플리케이션별 Default Page 종류 - Web.xml 페이지 http://www.kkk.com/web-inf/web.xml - Apache Tomcat Default Page http://www.kkk.com:8080/index.jsp - Apache Tomcat 관리자페이지 http://www.kkk.com:8080/admin http://www.kkk.com:8080/manager/html 특히, 웹어플리케이션별관리자페이지는삭제하지않을경우, 이를이용, 홈페이지변조, 악성프로그램설치등심각한피해가우려되므로반드시제거하여야한다. 백업파일삭제 o 백업파일은.bak,.back,.org,.orgin,.~,.log 등웹서버의개발 / 유지보수시사용한테스트파일을삭제하지않을경우, 공격자는웹서버의소스를다운로드하여 DB접속정보, 웹서버정보등을 42

분석, 웹서버침투, 자료유출등 2차공격에악용할수있다. o 웹디렉토리와다른곳에서백업본을생성하여소스수정후소스만업로드하도록하여웹브라우저를통해보여지는디렉토리에는 html, asp, php, cgi, jsp 등만올려놓도록한다. o 불필요한파일관리를위해 httpd.conf 파일을수정한다. <FIles ~"\.bak$"> Order allow, deny Deny from all </Files> o 홈페이지서버에테스트파일과같은불필요한파일을삭제하고홈페이지서비스와관련없는디렉토리 ( 백업디렉토리등 ) 는일반사용자가접근이불가능하도록적절한권한 ( 디렉토리또는파일접근권한 ) 을설정한다. [ 그림 34 ] 백업파일예 43

< 별첨 1> ActiveX Control 개발가이드 ActiveX Control은웹을통해다양한기능과미려한디자인을제공하기위해사용하는프로그램으로인터넷뱅킹, 포털, 게임, 쇼핑몰등대부분의웹사이트에서사용하고있다 이러한 ActiveX Control은보안의관점에서웹페이지나전자메일에포함된스크립트에의해사용자 PC 내부의파일엑세스, 레지스트리수정등잠재적악용가능성이있어, ActiveX Control을사용하도록개발된홈페이지는개발시특별한주의가요구된다 [ 출처 : ActiveX Control 개발보안가이드라인 (2008.11, 국가사이버안전센터 ) ] ActiveX Control 개발가이드 o 문자열입력값에대한크기검증 - ActiveX Control은보통인터넷익스플로러웹브라우저에서스크립트를통해실행된다. HTML 상에서 <param> 태그를통하여 ActiveX Control이초기화될때의파라미터를설정할수있고, <script> 태그를통하여변수를사용하듯이프로퍼티 (property) 를설정할수있고, 함수를사용하듯이메소드를호출할수있다. - 문자열입력값에대한크기검증이란파라미터, 프로퍼티, 메소드를통해 ActiveX Control에입력되는문자열이미리할당된메모리의크기보다클때입력값을필터링하는행위를말한다.. - 즉, 반드시미리허용된길이의문자열만을입력받고, 이후문자열을처리하는과정에서도할당한버퍼보다더긴문자열을복사하지않도록프로그램을제작하여야한다. - 미리할당된메모리보다큰문자열이입력으로들어왔을때는오류를리턴하고, 문자열을복사할때는미리할당된버퍼크기보다문자열이크진않은지항상확인하며, strcpy 함수대신에 strncpy_s 함수를, memcpy 함수대신에 memcpy_s 함수를사용하는등문자열복사에보다안전한함수를사용하여프로그램을구현하는것이바람직하다. 44

o 임의의프로세스를실행할수있는기능금지 - 임의의프로세스를실행할수있는기능이란 ActiveX Control이 HTML의 <param> 태그나스크립트상에서프로퍼티, 메소드인자를통하여사용자시스템에있는임의의실행파일에대한경로, 이름및실행인자를입력으로받고해당파일을실행하는기능을의미한다. 일반적으로임의의프로세스를실행하는기능은보안상매우위험하므로 ActiveX Control의메소드형태로구현하지말아야하지만, 보안을고려하지않는개발자들이쉽게범할수있는실수이고, 또한자주발견되고있는취약점이다. - 프로세스실행취약점을방지하기위해서는해당 ActiveX Control의실행에꼭필요한파일에대해서만프로세스실행기능을제공하도록프로그램을개발하여야한다. HTML 또는스크립트상에서실행파일의경로와이름또는실행인자를입력받지않도록프로그램소스상에고정하는방법이가장안전하다. - 불가피하게 HTML 또는스크립트상의입력값을통한프로세스실행기능이필요하다면, 입력값을개인키로암호화하여변조될수없게보호하거나, 경로나이름으로필터링하여기능을제한하여야한다. 또한, 실행인자를입력받는경우에는실행인자에대한크기를검증하고특수문자를사용한경우지정된범위를벗어나지않도록구현에주의가필요하다. o 임의의파일내용에대한읽기기능금지 - 임의의파일내용에대한읽기기능이란 ActiveX Control이 HTML의 <param> 태그나스크립트상에서메소드인자, 프로퍼티를통하여사용자시스템에있는임의의파일에대한경로와이름을입력받고해당파일의내용을메소드의리턴값이나프로퍼티로출력하는기능을의미한다. - 임의의파일내용에대한읽기기능은범용으로사용될수있다는장점때문에 ActiveX Control 개발자들이일반적으로구현하게되는대표적인취약점유형중하나이다. - 파일의내용을읽어서출력하는기능이제한되어있지않고임의의파일을읽을수있게설계되어있다면공격자는취약한해당 ActiveX Control 을악용하여사용자시스템의중요파일의내용을유출시킬수있다. - 파일읽기취약점을방지하기위해서는해당 ActiveX Control의실행에꼭필요한파일에대해서만파일읽기기능을제공하도록프로그램을작성하여야한다. HTML 또는스크립트 45

상에서파일경로및이름을입력받지않도록프로그램소스상에파일경로및이름을고정하는방법이가장안전하다. - 불가피하게 HTML 또는스크립트상의입력값을통한파일읽기기능이필요하다면, 입력값을개인키로암호화하여변조될수없게보호하거나, 폴더이름, 파일이름, 확장자등으로필터링기능을제한하여야한다. o 임의의레지스트리내용읽기기능금지 - 임의의레지스트리내용읽기기능이란 ActiveX Control이 HTML의 <param> 태그나스크립트상에서메소드인자, 프로퍼티를통하여사용자시스템에있는임의의레지스트리에대한경로및이름을입력받고해당레지스트리의내용을메소드의리턴값이나프로퍼티로출력하는기능을의미한다. - 임의의레지스트리내용에대한읽기기능은범용으로사용될수있다는장점때문에 ActiveX Control 개발자들이일반적으로구현하게되는또하나의대표적인보안취약점유형중하나이다. - 레지스트리의내용을읽어서출력하는기능이제한되어있지않고임의의레지스트리내용을읽을수있게설계되어있다면레지스트리읽기취약점이발생하게된다. 레지스트리읽기취약점이발생하면, 공격자는취약한해당 ActiveX Control을악용하여사용자시스템의중요레지스트리의내용을외부로유출시킬수있다. - 레지스트리읽기취약점을방지하기위해서는해당 ActiveX Control의실행에꼭필요한레지스트리에대해서만레지스트리읽기기능을제공하도록프로그램을수정하여야한다. - HTML 또는스크립트상에서레지스트리경로및이름을입력받지않도록프로그램소스상에레지스트리경로및이름을고정하는방법이가장안전하다. 불가피하게 HTML 또는스크립트상의입력값을통한레지스트리읽기기능이필요하다면, 입력값을개인키로암호화하여변조될수없게보호하거나, 경로나이름으로필터링을가하여기능을제한하여야한다. 필터링을구현할때는레지스트리의경로가.. 으로우회되지않도록구현에주의가필요하다. o 업데이트파일에대한신뢰성검증 - 최근 ActiveX Control 들은대부분자동업데이트기능을포함하고있으며, 이러한업데이트 46

기능은 HTML의 <param> 태그나스크립트상에서메소드인자, 프로퍼티를통하여업데이트서버의 URL이나설치파일등의업데이트정보를입력받아서동작하는것이일반적이다. - 만약업데이트정보 ( 업데이트서버의 URL, 설치파일, 업데이트되는파일등 ) 를공격자가변조할수있다면, 정상적인업데이트기능을악용하여악성코드를설치하는것이가능하다. - ActiveX Control 프로그램의업데이트를공격자로부터보호하기위해서는업데이트파일에대한신뢰성검증이필요하며, 이를위한방법으로는서명값을검증하는방법이가장바람직하다. - 서명값검증이란해당 ActiveX Control 개발업체에서공개키 / 개인키쌍을발급받고, 업데이트파일에대해서는개인키로서명한값을추가하여전달하고, 사용자시스템인클라이언트측에서는전달된업데이트파일에대하여서명값이올바른지공개키로검증하는방법을의미한다. 즉, 업데이트파일에디지털서명을하여업데이트파일에대한신뢰성을보장받는것이다. - 서명값검증방법을구현하기어려운경우에는업데이트 URL을 HTML이나스크립트상에서입력받지아니하고프로그램소스상에서고정하여사용하는방법이한가지대안이될수있다. o 관리자권한의폴더에 ActiveX Control 프로그램설치 - ActiveX Control은설치된웹사이트에서실행될뿐만아니라웹게시물이나이메일의열람을통해서도손쉽게실행이가능하다. 또한, ActiveX Control 을개발하는목적은인터넷익스플로러가접근하지못하는사용자시스템의자원을다루기위해서가대부분이다. - 만약이러한 ActiveX Control이공격자에의해변조되어악성코드로변해있다면사용자시스템에치명적인위협이될것이자명하다. - 불행히도일부 ActiveX Control 개발자들은이러한위협에대하여고려하지않은채업데이트나사용상의편의를위해인터넷익스플로러에서도접근이가능한낮은권한의폴더에프로그램을설치하기도한다. 하지만, 낮은권한의폴더에있는파일은쉽게수정이가능하기때문에잠재적으로변조될위험성이크다할수있다. ActiveX Control 프로그램을공격자의변조공격으로부터보호하기위해서는 ActiveX Control 프로그램을관리자권한의폴더에설치하는것이중요하다. - 이때 ActiveX Control 프로그램이란실행코드인 exe, dll, ocx 등의파일을의미하고, 관리자권한의폴더란 C:\Windows\ 의하위폴더또는 C:\Program Files\ 의하위폴더를의미한다. 47

o 실행가능한웹사이트의제한 - 대부분의 ActiveX Control은설치된웹사이트에서만필요하며그외의웹사이트에서는실행될필요가없다. 하지만, ActiveX Control은설치된웹사이트에서뿐만아니라다른모든웹사이트나이메일을통해서도손쉽게실행이가능하다. 문제는특정 ActiveX Control이보안취약점을가지는경우해당 ActiveX Control을설치하고사용했던웹사이트뿐만이아니라모든웹사이트와이메일을통해서도공격이가능해진다는점이다. - 따라서 ActiveX Control 의악용을방지하기위해서는 ActiveX Control 의실행가능한웹사이트를제한하여야만한다. 실행가능한웹사이트의제한은 ActiveX Control의보안취약점을제거해줄수는없지만, 공격자의공격을효과적으로방어해줄수있다. 왜냐하면 ActiveX Control의악용은해당 ActiveX Control이설치되고사용되는사이트와는관계가없는공격자의웹서버또는이메일을통해서대부분이루어지기때문이다. - ActiveX Control의실행가능한웹사이트를제한하기위해서는 ActiveX Control이실행되는시점에웹사이트 URL에대한필터링을구현하여야하며, 이를위해 SiteLock Template을활용할것을적극권장한다. - SiteLock Template이란 ActiveX Control이실행되는도메인을제한해주기위해 Microsoft 사에서제공하는 ATL 템플릿으로써실행가능한웹사이트리스트의제한뿐만아니라, 추가적으로실행가능한인터넷영역의제한및실행가능한유효기간설정등의기능을제공해준다. - SiteLock Template을활용하지않고직접웹사이트 URL에대한필터링을구현할수있겠으나사용이간편하고안정적이며 URL이우회될수있는실수를방지해주기때문에 SiteLock Template 을이용하는편이바람직하다. SiteLock Template 을설치할수있는 URL은아래와같다 ( 또는 MSDN 사이트에서 SiteLock Template 을검색하면찾을수있다 ). *SiteLock Template 설치 URL - http://www.microsoft.com/downloads/details.aspx? FamilyID=43cd7e1e-5719-45c0-88d9-ec9ea7fefbcb&displaylang=en o 신뢰할수있는사이트추가 남용금지 - 윈도우 Vista의강화된보안정책으로 ActiveX Control의설치및실행에제한을받게되자개발자들은대대적인수정작업에들어가야했다. 불행히도일부개발자들은윈도우 Vista용 ActiveX Control을수정하는대신자신의 ActiveX Control이설치되거나실행되는 48

사이트를신뢰할수있는사이트로추가하였다. 신뢰할수있는사이트에서는윈도우 Vista에서추가된보안기능들이대부분해제되어기존의 ActiveX Control들도대부분정상적으로동작하기때문이다. - 인터넷익스플로러는웹사이트를보안수준에따라인터넷영역, 로컬인트라넷영역, 신뢰할수있는사이트영역, 제한된사이트영역의 4가지영역으로나누고있다. 대부분의사이트는인터넷영역에서실행되며, 인터넷영역에서는높은보안수준이제공된다. - 신뢰할수있는사이트는사용자스스로해당사이트가안전하다고특별히지정하는사이트로써, 인터넷영역보다보안설정이낮아지며특히윈도우 Vista에서는보호모드가해제된다. 보호모드가해제되면윈도우 Vista에서추가된대부분의보안정책이무력화된다. - 따라서이문제를해결하기위해서는보안설정을낮추는방식이아니라, 신뢰할수있는사이트가아니더라도 ActiveX Control의정상적인실행이가능하도록 ActiveX Control을수정하여야한다. o 권한상승창에대한우회금지 - 윈도우 Vista의보호모드하에서인터넷익스플로러는낮은 Integrity의사용자권한으로실행되며, ActiveX Control 또한낮은 Integrity의사용자권한을가진다. 이로인하여, ActiveX Control이 Program Files 하위의파일이나 HKEY_LOCAL_MACHINE 하위의레지스트리와같은높은권한을가지는로컬자원을다루기위해서는권한상승이필요하다. - 일반적인사용자입장에서빈번하게팝업되는권한상승창은번거로운것이사실이다. 따라서개발자는사용자편의성을위해권한상승창이팝업되는수가최소화되도록 ActiveX Control을설계하고싶어하며, 이런의미에서자동권한상승은매력적이다. 하지만, ActiveX Control의암시적권한상승은보안적인관점에서보았을때위험하다. - 왜냐하면, 보통의경우 ActiveX Control이보안취약점을가지고있다할지라도보호모드때문에높은권한으로동작하는것이제한되는반면, 암시적인자동권한상승을사용하는 ActiveX Control이보안취약점을가지는경우는사용자동의없이도높은권한으로악성행위를수행하게할수있기때문이다. 따라서 ActiveX Control 개발시이러한암시적인권한상승의위험성을반드시고려해야할것이다. 49

o ActiveX Control 의남용금지 - 불필요한 ActiveX Control의개발을줄이고대체기술로전환하는것이바람직하다. ActiveX Control 은사용자시스템의자원을접근해야하고다른대체수단이없는경우에만선택되어야하며, 그외에는 Ajax, Flash/FLEX, SilverLight 등의더나은대체기술로전환되어야옳다. 그리고부득이하게 ActiveX Control을개발할때에는개발초기부터보안을염두에두고설계및구현해야한다. 안전한 ActiveX Control의개발을위해서는개발자와보안책임자스스로보안의식과책임감을가지는것이무엇보다도필요하다. o Windows Vista 에서안전한 ActiveX Control 개발체크리스트 내용 세부점검항목 비고 HTML에서 <param> 태그를통해파라미터로문자열을입력으로 받아처리하는경우프로그램에서할당한크기를넘지않는지 확인하는루틴이항상포함되어있는가? 문자열입력값에대한크기검증임의의프로세스실행기능금지임의의파일읽기기능금지 스크립트에서프로퍼티 (property) 가문자열을입력으로받아처리하는경우프로그램에서할당한크기를넘지않는지확인하는루틴이항상포함되어있는가? 스크립트에서메소드 (method) 가인자로문자열을입력으로받아처리하는경우프로그램에서할당한크기를넘지않는지확인하는루틴이항상포함되어있는가? 임의의프로세스실행기능을제한하고있는가? HTML의 <param> 태그나스크립트상에서메소드, 프로퍼티를통하여사용자시스템에있는임의의실행파일에대한경로및이름, 실행인자를입력으로받고해당실행파일을실행하는기능 특정경로내의실행파일에대하여프로세스실행기능을제공하는경우입력값에.. 을사용할수없도록제한하고있는가? HTML 의 <param> 태그나스크립트상에서메소드, 프로퍼티를통하여실행파일에대한경로및이름, 실행인자를입력으로받고해당실행파일을실행하는기능 임의의파일읽기기능을제한하고있는가? HTML의 <param> 태그나스크립트상에서메소드, 프로퍼티를통하여사용자시스템에있는임의의파일에대한경로및 50

이름을입력으로받고해당파일의내용을메소드의리턴값이나프로퍼티로출력하는기능 특정폴더내의파일에대하여읽기기능을제공하는경우입력값에.. 을사용할수없도록제한하고있는가? HTML의 <param> 태그나스크립트상에서메소드, 프로퍼티를통하여파일에대한경로및이름을입력으로받고해당파일의내용을메소드의리턴값이나프로퍼티로출력하는기능 임의의레지스트리읽기기능금지업데이트파일에대한신뢰성검증 임의의레지스트리읽기기능을제한하고있는가? HTML의 <param> 태그나스크립트상에서메소드, 프로퍼티를통하여사용자시스템에있는임의의레지스트리에대한경로및이름을입력으로받고해당레지스트리의내용을메소드의리턴값이나프로퍼티로출력하는기능 특정경로내의레지스트리에대하여레지스트리읽기기능을제공하는경우입력값에.. 을사용할수없도록제한하고있는가? HTML의 <param> 태그나스크립트상에서메소드, 프로퍼티를통하여레지스트리에대한경로및이름을입력으로받고해당레지스트리의내용을메소드의리턴값이나프로퍼티로출력하는기능 HTML의 <param> 태그나스크립트상에서메소드인자, 프로퍼티를통하여업데이트 URL 정보를입력받는경우, 디지털서명을이용하여업데이트파일의신뢰성을확보하였는가? 관리자권한의폴더에프로그램설치실행가능한웹사이트제한 ActiveX Control 프로그램 (exe, dll, ocx 등의파일 ) 은관리자권한의폴더 (C:\Windows\ 의하위폴더또는 C:\Program Files\ 의하위폴더 ) 에설치되도록제한하였는가? Microsoft의 SiteLock Template를활용하여 ActiveX Control이실행가능한웹사이트를제한하였는가? ActiveX Control의설치및실행을위해서해당웹사이트를신뢰할수있는사이트에추가하는기능을제한하고있는가? 신뢰할수있는사이트추가남용금지권한상승창우회금지 ActiveX Control 의설치를위해서보안설정을낮출필요가있는경우설치후에반드시보안설정을원래대로복구하고있는가? ActiveX Control 의실행을위해서보안설정을낮출필요가있는경우보안설정을낮추는방법대신권한상승창을통해 ActiveX Control의권한을높이는방법으로구현하고있는가? 권한상승창을통해사용자동의없이 ActiveX Control이 Medium Integrity의사용자권한을가지는프로세스 (.exe) 를 51

실행할수있도록 Elevation Policy 레지스트리키를사용하지않았음을확인하였는가? Medium Integrity 이상의권한을가진대리자프로세스 (.exe) 를사용자시스템에상주하게하여, ActiveX Control 이사용자동의없이높은권한이필요한일을처리하도록개발하지않았음을확인하였는가? 불필요한 A c t i v e X Control 남용금지 개발되는 ActiveX Control이사용자시스템의자원을이용할필요가명확히있고, 다른대체수단이없는것을확인하였는가? ActiveX Control 은정상적인사용자뿐만아니라악의적인공격자또한이용할수있음을염두하고, 해당기능이악용될소지는없는지충분히고려하였는가? 52

< 별첨 2> 보안코딩소스코드 1 스크립트삽입 (XSS), 스크립트요청참조 (CSRF) o ASP - Server.HTMLEncode() 함수를사용하여, 특정문자열에대한 HTML encoding 을수행 - 적용가능한 IIS : IIS 5.0이상 - 사용법 : <%= Server.HTMLEncode(" 입력값 ") %> - 개발코드예시 If use_html Then 'HTML tag를사용하게할경우부분허용 memo = Server.HTMLEncode(memo) 'HTML encoding 수행 memo = replace(memo, "<p>", "<p>") memo = replace(memo, "<P>", "<P>") memo = replace(memo, "<br>", "<br>") memo = replace(memo, "<BR>", "<BR>") Else 'HTML tag 를사용하지못하게할경우 memo = Server.HTMLEncode(memo) 'HTML encoding 수행 memo = replace(memo, "<", "<") memo = replace(memo, ">", ">") End If Response.write " 게시물내용 -" & memo & "<BR>" o PHP - htmlspecialchars() 함수를이용하여특정문자열에대한 HTML encoding을수행. - strip_tags() 함수를이용하여문자열로부터 HTML tag와 PHP tag를제거 - 개발코드예시 $use_tag = "img, font, p, br"; // 허용할 HTML tag if($use_html == 1) // HTML tag를사용하게할경우부분허용 $memo = str_replace("<", "<", $memo); // HTML tag를모두제거 $tag = explode(",", $use_tag); for($i=0; $i<count($tag); $i++) // 허용할 tag만사용가능하게변경 53

$memo = eregi_replace("<".$tag[$i]." ", "<".$tag[$i]." ", $memo); $memo = eregi_replace("<".$tag[$i].">", "<".$tag[$i].">", $memo); $memo = eregi_replace("</".$tag[$i], "</".$tag[$i], $memo); else // HTML tag를사용하지못하게할경우 // $memo = htmlspecialchars($memo); // htmlspecialchars() 사용시일부한글이깨어지는현상이발생할수있음 $memo = str_replace("<", "<", $memo); $memo = str_replace(">", ">", $memo); echo " 게시물내용-". $memo. "<BR>\n"; o JSP - 개발코드예시 if(use_html) // HTML tag를사용하게할경우부분허용 memo = memo.replaceall("<","<"); //HTML tag를모두제거 memo = memo.replaceall(">",">"); // 허용할 HTML tag만변경 memo = memo.replaceall("<p>", "<p>"); memo = memo.replaceall("<p>", "<P>"); memo = memo.replaceall("<br>", "<br>"); memo = memo.replaceall("<br>", "<BR>"); else // HTML tag를사용하지못하게할경우 memo = memo.replaceall("<","<"); memo = memo.replaceall(">",">"); out.print(" 게시물내용-" + memo + "<BR>"); 2. SQL 구문삽입 o ASP prodid = Request.QueryString("productId") prodid = replace(prodid, "'", "''") ' 특수문자제거 prodid = replace(prodid, ";", "") 54

prodid = replace(prodid, "--", "") prodid = replace(prodid, "+", "") prodid = replace(prodid, "%", "") prodid = replace(prodid, "<", "<") prodid = replace(prodid, ">", ">") prodid = replace(prodid, "(", "(") prodid = replace(prodid, ")", ")") prodid = replace(prodid, "#", "#") prodid = replace(prodid, "&", "&") prodid = replace(lcase(prodid), "@@variable", "") prodid = replace(lcase(prodid), "@variable", "") prodid = replace(lcase(prodid), "print", "") prodid = replace(lcase(prodid), "set", "") prodid = replace(lcase(prodid), "or", "") prodid = replace(lcase(prodid), "union", "") prodid = replace(lcase(prodid), "and", "") prodid = replace(lcase(prodid), "insert", "") prodid = replace(lcase(prodid), "openrowset", "") set conn = server.createobject("adodb.connection") set rs = server.createobject("adodb.recordset") query = "select prodname from products where id = " & prodid conn.open "Provider = SQLOLEDB; Data Source = (local); Initial Catalog = productdb; User Id = dbid; Password = " rs.activeconnection = conn rs.open query If not rs.eof Then response.write " 제품명 & rs.fields("prodname").value Else response.write " 제품이없습니다 End If o PHP $query = sprintf("select id, password, username FROM user_table WHERE id = '%s';", addslashes($id)); // id 변수를문자형으로받고, id 변수의특수문자를일반문자로변환 // @ 로 php 에러메시지를막는다. $result = @OCIParse($conn, $query); if(!@ociexecute($result)) error("sql 구문에러 ); exit; @OCIFetchInto($result, &$rows); 55

o JSP String sql = "SELECT * FROM user_table" + " WHERE id =?" + " AND password =?"; ResultSet rs = null; PreparedStatement pstmt = null; try conn = DBManager.getConnection(); pstmt = conn.preparestatement(sql); pstmt.setstring(1, request.getparameter("id")); pstmt.setstring(2, request.getparameter("password")); rs = pstmt.executequery(); 6. 파일업로드 o ASP Set Up = Server.CreateObject("SiteGalaxyUpload.Form") Path1 = server.mappath(".") & "\upload\" Fname = Up("file1") if Fname <> "" then ' 파일첨부가되었으면 if Up("file1").Size > 10240 then ' 용량제한 Response.Write " 용량초과 " Response.End end if if Up("file1").MimeType <> "image" then ' 이미지만업로드허용 Response.Write " 이미지파일이아닙니다." Response.End end if Filename=Mid(Fname,InstrRev(Fname,"\")+1) ' 파일이름부분추출 ' 중복시에파일이름부분을변경하기위해분리 Farry=split(Filename,".") '. 을기준으로분리 prefname=farry(0) ' 파일이름앞부분 extfname=farry(1) ' 파일의확장자 ' 저장할전체 path를만듦, 파일이름을구함 Path2 = Path1 & Filename savefname=prefname & "." & extfname 56

Set fso = CreateObject("Scripting.FileSystemObject") countno = 0 ' 파일중복될경우세팅값 fexist=0 ' 같은이름의파일존재체크 Do until fexist = 1 If(fso.FileExists(Path2)) Then countno = countno + 1 Path2 = Path1 & prefname & countno & "." & extfname savefname=prefname & countno & "." & extfname else fexist=1 End If Loop Up("file1").SaveAs(Path2) response.write(savefname & " 저장완료 ") else response.write("error") end if Set Up = nothing o PHP $uploaddir = '/var/www/uploads/'; // 파일사이즈가 0byte 보다작거나최대업로드사이즈보다크면업로드를금지시킴 if($_files['userfile']['name']) if($_files['userfile']['size'] <= 0) // 최대업로드사이즈체크삽입 print " 파일업로드에러 "; exit; // 파일이름의특수문자가있을경우업로드를금지시킴 if (eregi("[^a-z0-9\._\-]",$_files['userfile']['name'])) print " 파일이름의특수문자체크 "; exit; // 파일확장자중업로드를허용할확장자를정의 $full_filename = explode(".", $_FILES['userfile']['name']); $extension = $full_filename[sizeof($full_filename)-1]; /* PHP의경우확장자체크를할때 strcmp( 확장자,"php3"); 로체크를하게되면 php3 이나 php3는구별을하지못하게되므로 strcasecmp처럼대소문자구별을하지않고비교하는함수를사용. 또한. 를기준으로하여확장자가하나로간주하고 57

프로그램을할경우 file.zip.php3 이라고올린다면 zip파일로인식하고그냥첨부가되므로아래와같이제일끝에존재하는확장자를기준으로점검하도록함 */ $extension= strtolower($extension); if (!( ereg($extension","hwp") ereg($extension","pdf") ereg($extension","jpg")) ) print " 업로드금지파일입니다 "; exit; $uploadfile = $uploaddir. $_FILES['userfile']['name']; if (move_uploaded_file($_files['userfile']['tmp_name'], $uploadfile)) print " 파일이존재하고, 성공적으로업로드되었습니다."; print_r($_files); else print " 파일업로드공격의가능성이있습니다! 디버깅정보입니다 :\n"; print_r($_files); o JSP <%@ page contenttype = "text/html; charset=euc-kr" %> <%@ page import="com.oreilly.servlet.multipartrequest,com.oreilly.servlet.multipart. DefaultFileRenamePolicy, java.util.*" %> <% String savepath = "/var/www/uploads"; // 업로드디렉토리 int sizelimit = 5 * 1024 * 1024; // 업로드파일사이즈제한 try MultipartRequest multi = new MultipartRequest(request, savepath, sizelimit, "euc-kr", new DefaultFileRenamePolicy()); Enumeration formnames = multi.getfilenames(); // 폼의이름반환 String formname = (String)formNames.nextElement(); String filename = multi.getfilesystemname(formname); // 파일의이름얻기 String file_ext = filename.substring(filename.lastindexof('.') + 1); if(!( file_ext.equalsignorecase("hwp") file_ext.equalsignorecase("pdf") file_ext.equalsignorecase("jpg")) ) out.print(" 업로드금지파일 "); if(filename == null) out.print(" 파일업로드실패 "); 58

else filename = new String(fileName.getBytes("8859_1"),"euc-kr"); // 한글인코딩 out.print("file Name : " + filename); catch(exception e) %> 7. 파일다운로드 o ASP file = Request.Form ("file") ' 파일이름 Response.ContentType = "application/unknown" 'ContentType 선언 Response.AddHeader "Content-Disposition","attachment; filename=" & file Set objstream = Server.CreateObject("ADODB.Stream") 'Stream 이용 strfile = Server.MapPath("./upfiles/") & "\" & file ' 서버절대경로 strfname = Mid(Fname,InstrRev(file,"\")+1) ' 파일이름추출,..\ 등의하위경로탐색은제거됨 strfpath = Server.MapPath("./upfiles/") & "\" & strfname ' 웹서버의파일다운로드절대경로 If strfile = strfpath Then ' 사용자가다운받는파일과웹서버의파일다운로드경로가맞는지비교 objstream.open objstream.type = 1 objstream.loadfromfile strfile download = objstream.read Response.BinaryWrite download End If Set objstream = nothing ' 객체초기화 o PHP if (preg_match("/[^a-z0-9_-]/i",$up_dir)) print " 디렉토리에특수문자체크 "; exit; if (preg_match("/[^\xa1-\xfea-z0-9._-] \.\./i",urldecode($dn_file_name))) print " 파일이름에특수문자체크 "; 59

exit; $dn_path = "/var/www/data/$up_dir/$dn_file_name"; if (!file_exists($dn_path)) print " 파일이존재여부체크 "; exit; // 파일전송루틴 header("content-type: doesn/matter"); header("content-length: ".filesize("$dn_path")); header("content-disposition: filename = ".$dn_file_name]); header("content-transfer-encoding: binary\r\n"); header("pragma: no-cache"); header("expires: 0"); o JSP String UPLOAD_PATH = "/var/www/upload/"; String filename = response.getparameter("filename"); String filepathname = UPLOAD_PATH + filename; if(filename.equalsignorecase("..") filename.equalsignorecase("/")) // 파일이름체크 return 0; // 파일전송루틴 response.setcontenttype("application/unknown; charset = euc-kr"); response.setheader("content-disposition","attachment;filename = " + filename + ";"); response.setheader("content-transfer-encoding:", "base64"); try BufferedInputStream in = new BufferedInputStream(new FileInputStream(filepathname));... catch(exception e) // 에러체크 [ 파일존재유무등 ] 60

8. URL 강제접속 / 인증우회 ( 로그인 ) o ASP <html> <head> <title> Login </title> <script> function check_submit() if(!login.user_id.value) alert(" 아이디를입력하세요 "); login.user_id.focus(); return false; if(!login.password.value) alert(" 아이디를입력하세요 "); login.password.focus(); return false; return true; </script> </head> <body> <form method=post action=login.asp onsubmit="return check_submit();" name=login> <TABLE border=0> <TR> <TD> 아이디 </TD> <TD><input type=text name="user_id" value="" maxlength=12 size=19></td> </TR> <TR> <TD> 패스워드 </TD> <TD><input type=password name="password" value="" maxlength=12 size=19><input type=submit value="login"></td> </TR> </TABLE> </form> </body> </html> 61

<% Option Explicit %> <% Dim user_id, password user_id = Request.Form("user_id") ' 사용자로부터입력받은아이디 password = Request.Form("password") ' 사용자로부터입력받은패스워드 If UserAuth(user_id, password) <> 1 Then Response.redirect("/login.html") ' 인증실패시인증페이지로 Redirect Else If Session("logged_in") <> 1 Then ' 인증된사용자인지체크 Session("logged_in") = 1 ' 인증에성공했을경우 logged_in 에 1의값을세팅 Session("user_id") = user_id ' 사용자 ID 저장 Session("user_ip") = Request.Servervariables("REMOTE_ADDR") 'IP 저장 End If Response.redirect("/main.asp") ' 인증성공시 Main 페이지로 Redirect End If %> <% Function stripquotes(strwords) stripquotes = replace(strwords, "'", "''") ' 특수문자제거 End Function Function UserAuth(user_id, user_pwd) ' 사용자인증 Dim objconn, objrs Dim strconnection, strquery Set objconn = Server.CreateObject("ADODB.Connection") Set objrs = Server.CreateObject("ADODB.RecordSet") 'DB 연결정보, 별도의헤더파일로관리하여 INCLUDE strconnection = "DSN = MEMBER; uid = DBUSER; pwd = DBPASSWD" On Error Resume Next ' 에러가생길경우 objconn.open strconnection objrs.activeconnection = objconn strquery = "SELECT * FROM user_tbl WHERE user_id= '" &_ stripquotes(user_id) & "' AND password='" &_ stripquotes(user_pwd) & "'" objrs.open strquery If objrs.bof or objrs.eof Then' 올바른사용자를찾지못했을경우 UserAuth = 0 Else 62

UserAuth = 1 End If objrs.close ' DB 연결해제 Set objrs = Nothing objconn.close Set objconn = Nothing End Function %> <% If Session("user_ip") = Request.Servervariables("REMOTE_ADDR") AND Session("logged_in") = 1 Then Response.Write Session("user_id") & " 님은 " & Session("user_ip") & " 에서접속하셨습니다." ' 인증에성공한 IP와사용자 IP를비교, 인증여부비교 '... 중략... Else Response.write " 허가되지않은사용자입니다." End If %> o PHP <html> <head> <title> Login </title> <script> function check_submit() if(!login.user_id.value) alert(" 아이디를입력하세요 "); login.user_id.focus(); return false; if(!login.password.value) alert(" 아이디를입력하세요 "); login.password.focus(); 63

return false; return true; </script> </head> <body> <form method=post action=login.php onsubmit="return check_submit();" name=login> <TABLE border=0> <TR> <TD> 아이디 </TD> <TD><input type=text name="user_id" value="" maxlength=12 size=19></td> </TR> <TR> <TD> 패스워드 </TD> <TD><input type=password name="password" value="" maxlength=12 size=19><input type=submit value="login"></td> </TR> </TABLE> </form> </body> </html> <?PHP @session_cache_limiter('nocache'); @session_start(); // 세션데이터를초기화 // form 에서사용자 id와사용자 password를아래변수로전달 if(!userauth($_post['user_id'],$_post['password'])) //DB 에서사용자인증처리하는부분 header("location: login.html"); exit; // 인증실패시종료 // 인증에성공한경우처리해야되는부분 if (!session_is_registered("logged_in")) $logged_in = 1; // 인증에성공했을경우 logged_in 에 1의값을세팅 $user_id = $_POST["user_id"]; 64

$user_ip = $_SERVER["REMOTE_ADDR"]; session_register("logged_in"); // 인증결과저장 session_register("user_id"); // 사용자 ID를저장 session_register("user_ip"); // 사용자 IP를저장 header("location: main.php");?> <?PHP function UserAuth($userid, $userpwd) $connect = mysql_connect("localhost","dbuser","dbpasswd"); mysql_select_db("member"); $strquery = "SELECT * FROM user_tbl WHERE user_id ='". addslashes($userid). "' AND password='". addslashes($userpwd). "'"; $result = @mysql_query($strquery); if($result) if(mysql_num_rows($result)) $data = mysql_fetch_array($result); $userlevel = $data["level"]; @mysql_free_result($result); @mysql_close($connect); return 1; return 0; @mysql_close($connect); return 0;?> <?PHP @session_start(); if(strcmp($_session['user_ip'], $_SERVER['REMOTE_ADDR']) == 0 && session_is_registered('logged_in')) // 인증에성공한 IP와사용자 IP를비교, 인증여부비교 //... 중략... echo $_SESSION['user_id']. " 님은 ". $_SESSION['user_ip']. " 에서접속하셨습니다."; else echo " 허가되지않은사용자입니다."; exit;?> 65

o JSP <html> <head> <title> Login </title> <script> function check_submit() if(!login.user_id.value) alert(" 아이디를입력하세요 "); login.user_id.focus(); return false; if(!login.password.value) alert(" 아이디를입력하세요 "); login.password.focus(); return false; return true; </script> </head> <body> <form method=post action=login.jsp onsubmit="return check_submit();" name=login> <TABLE border=0> <TR> <TD> 아이디 </TD> <TD><input type=text name="user_id" value="" maxlength=12 size=19></td> </TR> <TR> <TD> 패스워드 </TD> <TD><input type=password name="password" value="" maxlength=12 size=19><input type=submit value="login"></td> </TR> </TABLE> </form> </body> </html> 66

<%@ page contenttype="text/html;charset=euc-kr" %> <%@ page import="java.util.*" %> <%@ page import="java.sql.* " %> <% String DB_URL = "jdbc:mysql://127.0.0.1/member"; //DB 연결정보, 별도의헤더파일로관리하여 INCLUDE String DB_USER = "DBUSER"; String DB_PASSWORD= "DBPASSWD"; //HttpSession session = request.getsession(true); //Servlet의경우만추가 String user_ip = request.getremoteaddr(); // 연결된사용자의 IP 획득 String user_id = null; Connection conn; PreparedStatement pstmt = null; ResultSet rs = null; try Class.forName("org.gjt.mm.mysql.Driver"); // 드라이버등록 conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD); //DB연결 String query = "SELECT * FROM user_tbl WHERE user_id =? AND password =?"; pstmt = conn.preparestatement(query); pstmt.setstring(1, request.getparameter("user_id")); // 사용자입력값전달 pstmt.setstring(2, request.getparameter("password")); rs = pstmt.executequery(); if(rs.next()) user_id = rs.getstring(1); //DB에서사용자정보획득 if(user_id!= null) if(session.getvalue("logged_in")!= "1") // 인증된사용자인지체크 session.putvalue("logged_in", "1"); // 세션에사용자정보기록 session.putvalue("user_id", user_id); session.putvalue("user_ip", user_ip); //LogSave(user_id, user_ip); // 인증에성공한사용자정보기록 response.sendredirect("/main.jsp"); // 인증성공시 Main 페이지로 Redirect else response.sendredirect("/login.html"); // 인증실패시인증페이지로 Redirect catch(exception ex) // 에러처리 out.println(ex); finally //DB연결종료 67

if(rs!= null) try rs.close(); catch(sqlexception ex) if(pstmt!= null) try pstmt.close(); catch(sqlexception ex) %> <%@ page contenttype="text/html;charset=euc-kr" %> <%@ page import="java.util.*" %> <% //HttpSession session = request.getsession(true); if(session.getvalue("user_ip") == request.getremoteaddr() && session.getvalue("logged_in") == "1") // 인증에성공한 IP와사용자 IP를비교, 인증여부비교 //... out.println(session.getvalue("user_id") + " 님은 " + session.getvalue("user_ip") + " 에서접속하셨습니다."); //... 중략... else response.sendredirect("/login.html"); // 인증실패시인증페이지로 Redirect %> 8. URL 강제접속 / 인증우회 ( 쿠키사용방지 ) o ASP <% 'form 에서사용자 id와사용자 password를아래변수로전달 If myfunc_userauth(userid, userpw) <> 1 Then 'DB 에서사용자인증을처리하는부분 Response.write " 인증실패 " Else ' 인증에성공한경우처리해야되는부분 If Session("logged_in") <> 1 Then 68

Session("logged_in") = 1 ' 인증에성공했을경우 logged_in 에 1의값을세팅 Session("userid") = userid Session("user_ip") = Request.Servervariables("REMOTE_ADDR") End If End If... %> <% IF Session("user_ip) = Request.Servervariables("REMOTE_ADDR") AND Session("logged_in") = 1 Then ' 인증에성공한 IP와사용자 IP를비교, 인증여부비교 '... Else Response.write " 허가되지않은사용자입니다." End If %> o PHP <?PHP @session_start(); // 세션데이터를초기화 // form 에서사용자 id와사용자 password를아래변수로전달 if(!myfunc_userauth($userid,$userpw)) //DB 에서사용자인증을처리하는부분 print " 인증실패 "; exit; // 인증실패시종료 // 인증에성공한경우처리해야되는부분 if (!session_is_registered("logged_in")) $logged_in = 1; // 인증에성공했을경우 logged_in 에 1의값을세팅 $user_ip = $_SERVER["REMOTE_ADDR"]; session_register("logged_in"); // 인증결과저장 session_register("userid"); // 사용자 ID를저장 69

session_register("user_ip"); // 사용자 IP를저장...?> <?PHP session_start(); if(strcmp($_session['user_ip'], $_SERVER['REMOTE_ADDR']) == 0 && session_is_registered('logged_in')) // 인증에성공한 IP와사용자 IP를비교, 인증여부비교 //... else print " 허가되지않은사용자입니다."; exit;?> o JSP <%@ page contenttype="text/html;charset=euc-kr" %> <%@ page import="java.util.*" %> <%@ page import="java.sql.* " %> <% //HttpSession session = request.getsession(true); // form 에서사용자 id와사용자 password를아래변수로전달 if(!myfunc_userauth(userid, userpw)) //DB 에서사용자인증을처리하는부분 out.println " 인증실패 "; else // 인증에성공한경우처리해야되는부분 session.putvalue('logged_in',"1"); session.putvalue('userid',userid); session.putvalue('user_ip',request.getremoteaddr());... %> 70

<%@ page contenttype="text/html;charset=euc-kr" %> <%@ page import="java.util.*" %> <%@ page import="java.sql.* " %> <% //HttpSession session = request.getsession(true); String user_ip = session.getvalue("user_ip"); if(user_ip.equals(request.getremoteaddr()) && logged_in.equals("1")) // 인증에성공한 IP와사용자 IP를비교, 인증여부비교 //... else out.println " 허가되지않은사용자처리."; %> 12. 환경설정및보안고려사항 o ASP <% If myfunc_userauth(userid, userpw) <> 1 Then 'DB에서사용자인증을처리 Response.write " 인증실패 " Else If Request.ServerVariables("REMOTE_ADDR") <> "10.10.1.1" Then ' 관리자 IP 확인 Response.write " 관리자 IP가아닙니다." Response.write " 인증실패 LogSave(userid, user_ip, 0) ' 접속에실패한 ID 및 IP 기록 Else Session("logged_in") = 1 ' 인증에성공했을경우 logged_in 에 1의값을세팅 Session("userid") = userid Session("user_ip") = Request.ServerVariables("REMOTE_ADDR") LogSave($userid, $user_ip) ' 접속에사용한 ID 및 IP 기록... 중략... End If End If %> 71

o PHP <?PHP @session_start(); // 세션데이터를초기화 if(!myfunc_userauth($userid, $userpw) $_SERVER["REMOTE_ADDR']!= "10.10.1.1") //DB 에서사용자인증을처리, 관리자 IP인지확인 print " 인증실패 "; LogSave(userid, user_ip, 0) ' 접속에실패한 ID 및 IP 기록 exit; // 인증실패시종료 // 인증에성공한경우처리해야되는부분 if (!session_is_registered("logged_in")) $logged_in = 1; // 인증에성공했을경우 logged_in 에 1의값을세팅 $user_ip = $_SERVER["REMOTE_ADDR"]; session_register("logged_in"); // 인증결과저장 session_register("userid"); // 사용자 ID를저장 session_register("user_ip"); // 사용자 IP를저장 LogSave($userid, $user_ip); // 접속한사용자 ID 및 IP 기록... 중략...?> o JSP <%@ page contenttype = "text/html; charset = euc-kr" %> <%@ page import="java.util.* " %> <%@ page import="java.sql.* " %> <% //HttpSession session = request.getsession(true); String user_ip = request.getremoteaddr(); // form 에서사용자 id와사용자 password를아래변수로전달 if(!myfunc_userauth(userid, userpw)!user_ip.equals("10.10.1.1")) //DB 에서사용자인증을처리, 관리자 IP인지확인 out.println " 인증실패 "; LogSave(userid, user_ip, 0) ' 접속에실패한 ID 및 IP 기록 else // 인증에성공한경우처리해야되는부분 session.putvalue("logged_in","logok"); session.putvalue("userid",userid); 72

session.putvalue("user_ip", user_ip); LogSave(userid, user_ip); // 접속한사용자 ID 및 IP기록 %> 73

웹응용프로그램개발보안가이드 2010 발행일자 : 2010년 1월 1일발행기관 : 행정안전부홈페이지 : 행정안전부 (http://www.mopas.go.kr) 정부통합전산센터 (http://www.ncia.go.kr) 전자우편 : nciacert@mopas.go.kr 전화번호 : 042-250 -5770~3 본가이드는행정안전부에서작성되었으며, 무단복제 / 열람을금함