http://www.owasp.or.kr 에서배포 코리아챕터 OWASP 코드리뷰가이드 영문판 2008 V1.1 한글판 2015 V1.1 프로젝트후원사 : 엔시큐어 2011-2015 OWASP 재단 /OWASP 코리아챕터 이문서는 Creative Commons Attribution Share Alike 3.0 라이선스에따라승인되었습니다. 본한글문서를 활용시에는반드시 OWASP 코드리뷰가이드또는 OWASP 코리아챕터결과물인것을밝혀야합니다.
목차 OWASP 의장제프윌리엄스서문... 5 OWASP 코리아챕터서문... 7 OWASP 코드리뷰가이드 1.1 환영사... 8 OWASP 소개... 11 코드리뷰가이드역사... 13 소개... 14 준비... 16 SDLC 에서보안코드리뷰... 20 보안코드리뷰범위... 22 애플리케이션위협모델링... 26 코드리뷰메트릭스... 52 코드크롤링... 56 J2EE/Java 에서코드검색... 65 클래식 ASP 에서코드검색... 70 자바스트립트 / Web 2.0 키워드와포인터... 73 코드리뷰와 PCI DSS... 74 기술통제검토 : 인증... 76 기술통제검토 : 인가... 82 기술적인통제사항검토 : 세션관리... 87 기술통제검토 : 입력값검증... 91 2
기술통제검토 : 오류처리... 93 기술통제검토 : 안전한애플리케이션배치... 105 기술통제검토 : 암호제어... 110 버퍼오퍼런과오버플로우를위한코드리뷰... 124 OS 인젝션을위한코드리뷰... 130 SQL 인젝션을위한코드리뷰... 135 데이터유효성검증을위한코드리뷰... 141 크로스사이트스크립팅을위한코드리뷰... 157 CSRF 를위한코드리뷰... 165 로깅을위한코드리뷰... 170 세션무결성을위한코드리뷰... 176 경쟁상태를위한코드리뷰... 179 추가적인보안고려사항... 182 자바의지저분한것들... 183 자바개발시주요보안사례... 190 클래식 ASP 개발시주요보안사례... 193 PHP 개발시주요보안사례... 198 문자열과정수... 201 MYSQL 개발시주요보안사례... 205 플래쉬개발시보안사례... 209 웹서비스개발보안... 212 코드리뷰결과보고서작성법... 215 3
자동화코드리뷰... 218 도구적용모델... 219 OWASP 의 ORIZON 프레임워크... 220 OWASP 코드리뷰 TOP 9... 235 참고문헌... 244 4
OWASP 의장제프윌리엄스서문 많은조직에서개발된코드가자신들이생각하는것만큼안전하지않다는것을깨닫게되었다. 이제조직에서는애플리케이션의보안성을확인해야하는힘든일을시작하고있다. 소프트웨어, 응용프로그램의보안을분석하기위해자동스캔, 수동침투시험, 정적분석및수동코드리뷰등기본적인 4 가지기법이있다. OWASP 가이드는 4 가지기법에대해서최신내용에중점을두고있다. 물론이러한기법들은모두나름의강점, 약점, 최적의접점및사각지대를가지고있다. 가장적합한기술이무엇인지논쟁하는것은집을지을때톱과망치가더중요한지논쟁하는것과같다. 만약당신이망치로만집을지으려한다면, 당신은끔찍한일을하는것이다. 아마도도구보다더중요한것은망치를들고있는사람일것이다. OWASP 가이드는이기술들을사용하는방법을교육하기위해만들어졌다. 그러나각각의기법이분리되어있지만, 반드시분리되어사용되는것은아니다. 개발가이드는프로젝트에대해서안전한응용을설계하고, 개발하는방법을가르쳐주고, 코드리뷰가이드는소스코드가안전한지검증하는방법을알려주며, 테스팅가이드는애플리케이션이안전성에대해검증하는방법을보여준다. 보안공격기법은급변하고있어전통적인책이유용하지않을수있다. 그러나 OWASP 는협업환경으로인해최신의상태를유지할수있다. OWASP 가이드는수백명의공헌자들이있으며, 매월이러한자료에대한수천개이상의새로운업데이트결과물을만들어내고있다. OWASP 는모든사람들이사용할수있는수준높은애플리케이션보안자료를만들어내고있다. 이방법은 OWASP 가소프트웨어커뮤니티로서애플리케이션보안에대한실질적인발전을할수있는유일한방법이다. 왜코드리뷰가중요한가? 필자는타업무를병행하며보안코드리뷰를 1998 년부터진행해왔으며, 수천개의심각한취약점을찾았다. 경험적으로봤을때, 문서디자인, 코드주석, 그리고심지어개발자들스스로가가끔실수하는경우도있다. 코드는거짓말을하지않는다. 실제로코드는해커로부터방어할수있는오직개발자만이가지는이점이다. 이러한이점을포기하지말고외부에서하는침투시험을이용해야한다. 코드를사용하라. 코드리뷰는비용이너무많이발생하거나시간이소요된다는주장이많음에도불구하고, 코드리뷰는많은보안문제를발견하고진단할수있는가장빠르고정확한방법이라는것에는이의가없다. 코드리뷰이외의다른방법으로는쉽게찾을수없는심각한보안취약점도많이있다. 보안코드리뷰의비용대비효과성에대해서강조하지않을수없다. 애플리케이션에서중요한보안문제를식별할수있는접근방법을고려해야하는데, 코드를검토하는것이가장빠르고정확한선택이다. 모든애플리케이션은다르기때문에개개인에게가장비용효과적인기법을사용하여보안성을검증하도록하는것이매우중요하다. 한가지일반적인방법은보안코드리뷰를사용하여문제점을찾고, 침투시험을통해악용이가능한지증명하는것이다. 다른방법은침투시험으로잠재적인문제를찾고, 코드를검사하여문제를확인하는것이다. 애플리케이션보안을위해서는 통합적인 " 접근법이최선의선택이다. 5
시작하기 코드가어떤것을만드는데사용할수있는풍부하게표현할수있는언어라는것을인식하는것은중요하다. 임의의코드를분석하는것은여러가지문맥적일것을요구하는어려운일이다. 그것은법적인계약에허점이있는지검색하는것과같다. 그래서자동화된도구로간단히보안취약점을찾는것이매력적으로보이지만이러한도구는맞춤법검사기또는문법검사기와같다는것을아는것이중요하다. 중요한것은, 그도구들은문맥을이해하지못하고, 여러중요한보안문제를놓칠수도있다. 하지만도구를실행하면코드리뷰를위해데이터를수집하는데사용할수있는좋은방법이다. 작업을시작하기위해서는, 모든소프트웨어기준선, 현대적인 IDE( 통합개발환경 ) 및보안취약점들이만들어지는것에대해생각하는능력이다. 당신이어떤코드를보기전에당신은가장중요한것이무엇인지를심사숙고할것을강력히권장한다. 그렇게한다면보안메커니즘이존재하는지, 결함이없는지, 정상적으로사용되었는지확인하게된다. 당신은무엇이잘못진행되고있는지를애플리케이션의제어및데이터흐름을통해추적할수있다. 실행요구 소프트웨어를개발하고있다면, 먼저이문서의보안지침에대해잘알아야한다. 오류를발견하면토론문서에메모를추가하거나직접수정해서작성하기를바란다. 이가이드를사용하는다른수천명을도울수있다. 우리가이코드리뷰가이드등의자료와 OWASP 의다른프로젝트를계속지속할수있도록개인또는기업회원으로참여하기를바란다. 이가이드의모든과거와미래의기부자에게감사하고, 당신의작업이전세계응용을좀더안전하게만드는데도움이될것이다. -- OWASP 의장제프윌리엄스, 2007 년 10 월 17 일 6
OWASP 코리아챕터서문 소프트웨어가인터넷과결합되면서혁신적인서비스가계속출시되고있다. 혁신적인 IT 서비스개발자들은인터넷과소프트웨어를결합하여그동안경험하지못한새로운비즈니스모델, 서비스및새로운플랫폼을제공하고있다. 이런방향은앞으로사물인터넷 (IoT) 에까지확대되면서더큰영향을미칠것으로기대한다. 하지만동시에해커들은소프프웨어개발자들이간과한실수를놓치지않고, 취약점을공격하여국가인프라, 개별조직과개인에게피해를입히는뿐만아니라해커그룹으로금전적인이익을챙기는사례도증가하고있다. 최근에는항공기제어소프트웨어결함으로인해항공기가추락하고조종사사망하는사건까지발생하면서소프트웨어안전성의더욱더중요성이커지고있다. 이러한소프트웨어중요성및기술발전추세에맞춰우리나라관련정부부처, 연구소, 기업및민간단체등에서도다양한방법으로소프트웨어취약점과보안에대한대책과도구를제시하고있다. 하지만현장에서는개발자들과보안코드검토자들이쉽게참고할수있는가이드가부족한실정이어서, 그동안웹애플리케이션취약점을방어하는데현장의어려움이존재하였다. OWASP 코드리뷰 (Code Review) 는이러한문제를해결하기위해 2008 년에버전 1.1 이출간되어, 애플리케이션취약점을방어할수있는표준가이드를제공하였다. OWASP 코리아커뮤니티에서는현장의요구에따라코드리뷰를 2013 년부터전문가 10 여명이회사일을하면서약 2 년간의연구, 번역및감수를통해서 2015 년 6 월에마무리가되었다 ( 이작업을하는동안에 OWASP 코드리뷰 2.0 버전이출간되기도하였다. 2.0 문서는모바일기기플랫폼및새로운프로그램언어사례가포함되는등개발자들이더많이사용할수있도록업그레이드되었으며, 코리아챕터커뮤니티의차기중요과제가될것으로예상한다.) 본문서는국내에서웹애플리케이션취약점및위험으로많이알려진 OWASP Top 10 취약점을효과적으로방어할수있는실질적인대책을담고있다..NET, 자바, ASP 등다양한개발언어에대해서 SQL 인젝션, 크로스사이트스크립팅 (XSS) 등 OWASP 애플리케이션취약점에대한상세코드리뷰방법뿐만아니라, 로그기록관리, 플래쉬, 버퍼오버플러우와같은다른중요취약점에제거하기위한상세샘플코드도포함하고있다. 애플리케이션을개발하는개발자또는조직의품질관리부서에서는애플리케이션을개발시활용도가클것으로기대한다. 소프트웨어개발자및검토자들은만려무실 ( 萬慮無失 ) 의자세로본문서를참고하면서안전하게또한새로운서비스를사용할수있는환경을개발해줄것을권고드린다. 마지막으로본문서를번역하고감수에참여한 OWASP 한국회원여러분께감사을말을전한다. 기타본문서의내용에오류가있으면, 언제든지연락주시기바랍니다. -- OWASP 코리아챕터리더성윤기, 2015 년 6 월 30 일 7
OWASP 코드리뷰가이드 1.1 환영사 아들아! 인터넷에문제가생기면우리가해결할수있을까? ( My Children, the internet is broken, can we fix this mess?) -- Eoin Keary, OWASP 코드리뷰가이드주저자 & 편집자 OWASP 는오늘날이가이드가있게한저자, 검토자, 그리고편집자들의노력에감사드린다. 당신에게코드리뷰 가이드에대한의견이나제안이있으면코드리뷰가이드메일링리스트에이메일을보내주기바란다. https://lists.owasp.org/mailman/listinfo/owasp-codereview 저작권및라이선스 영문판저작권 (c) 2008 The OWASP Foundation. 한글판저작권 (c) 2015 The OWASP 코리아챕터. 이문서는 Creative Commons Attribution Share Alike 3.0 라이선스에따라배포되었다. 라이선스와저작권 약관을참고하시기바란다. 영문판개정내역 코드리뷰가이드는 2006 년시작되었고, 테스팅가이드에서파생된프로젝트이다. 2005 년 Eoin Keary 에의해 제안되고, 위키로변환되었다. 2007 년 9 월 30 일 "OWASP Code Review Guide", Version 1.0 (RC1) 2007 년 12 월 22 일 "OWASP Code Review Guide", Version 1.0 (RC2) 2008 년 11 월 1 일 "OWASP Code Review Guide", Version 1.1 (Release) 편집자 Eoin Keary: OWASP Code Review Guide 2005 - Present 8
저자 Andrew van der Stock David Lowery David Rook Dinis Cruz Eoin Keary Jeff Williams Jenelle Chapman Marco M. Morana Paulo Prego 검토자 Jeff Williams P.Satish Kumar Rahim Jina 한글본편집자 성윤기최용식이효상 한글본번역자 김태균 김휘영 이상신 이진영 서완석 이숙정 장상민 전영재 정진 진수희 최훈진 최만균 한글본감수자 박양환서영덕송보영이인상임성현 트레이드마크 Java 자바, Java EE 자바 EE, Java Web Server, and JSP 는 SUN 마이크로시스템의등록된 트레이드마크이다. 마이크로소프트 Microsoft 는마이크로소프트사의등록된트레이드마크이다. OWASP 는 OWASP 재단의등록된트레이드마크입니다. 다른모든제품및회사이름은각소유자의트레이드마크이다. 이문서에서사용하는용어는어떤 트레이드마크나서비스마크의유효성에영향을주지않는다. SUMMER OF CODE 2008 OWASP Summer of code (SoC) 2008 은코드리뷰가이드를후원한다. 자세한내용은 https://www.owasp.org/index.php/owasp_summer_of_code_2008 를참조하기바란다. 9
프로젝트공헌자 OWASP 코드리뷰프로젝트는 OWASP 아일랜드챕터설립자인 Eoin Keary 와챕터에의해시작되었다. OWASP 는새로운웹기술등장에따라신규분야를늘려나갈인재를적극적으로찾고있다. 여러분이프로젝트를위한자원봉사에관심이있거나, 또는의견, 질문또는제안이있다면, 이메일을보내기바란다. mailto:eoin.keary@owasp.org OWASP 코리아챕터의다양한프로젝트에참여하고자하는분은아래로연락주시기바랍니다. mailto: yune.sung@owasp.org mailto: yongsik.choi@owasp.org 코드리뷰팀에참여해주십시오 모든 OWASP 가이드는지속적으로변경하는위협과보안환경의변화들속에서살아있는문서이다. 우리는코드리뷰가이드프로젝트에참여하여이문서를향상시키도록도움을주는모든분들을환영한다. 이러한일을시작하는가장좋은방법은아래의링크를따라메일링리스트에가입하는것이다. 자신을소개하고, 함께하는데도움이될만한뭔가가있는지문의하기바란다. 우리는항상새로운공헌자를찾고있다. 당신이기여하고자하는주제나연구가있다면, 우리에게알려주기바란다! http://lists.owasp.org/mailman/listinfo/owasp-codereview 10
OWASP 소개 오픈웹애플리케이션보안프로젝트 (OWASP) 는공개커뮤니티로기관이신뢰할수있는애플리케이션개발, 구입, 유지할수있도록공헌하고있다. OWASP 의도구, 문서, 포럼, 지부에관련된모든정보는애플리케이션보안성향상에관심있는모든사람에게무료로제공된다. 애플리케이션보안을위한가장효과적인접근방법은사람, 프로세스, 기술적사항을개선하는것이기때문에 OWASP 는위 3 가지접근법을강력히권장한다. OWASP 는 http://www.owasp.org 에서찾을수있다. OWASP 는새로운형태의조직이다. OWASP 는영리적압력으로부터자유롭기때문에애플리케이션보안에대한공정하고, 실질적이고, 비용효과적인정보를제공할수있다. OWASP 는잘알려진상업적보안기술을사용도록지원하지만, 어떠한기술기업과도연계되어있지않다. 많은오픈소스소프트웨어프로젝트와마찬가지로, OWASP 도협업과공개된방식으로여러가지자료를만든다. OWASP 재단은프로젝트의장기적인성공을보장하기위한비영리기구이다. 더많은정보에대해서는페이지아래의목록을참조하기바란다. 연락처 OWASP 와의연락정보 공헌 OWASP 에기여하기위한자세한방법 광고 OWASP 사이트에광고를원하는경우 OWASP 업무방법 OWASP 프로젝트및관리에대한자세한정보 OWASP 브랜드사용규칙 OWASP 브랜드사용관련한정보 OWASP 한국챕터에대한정보는 www.owasp.or.kr 을방문하길바란다. 체계 OWASP 재단은 OWASP 커뮤니티를위해인프라를제공하는비영리 (501c3) 기구이다. 재단에서는전세계 프로젝트, 지부및컨퍼런스를지원하고, 서버와대역폭을관리한다. 라이선스 OWASP 코드리뷰가이드는 Creative Commons Share-Alike 3.0 Attribution 라이선스에따라사용된다. 이라이선스는공헌과저작권을명시하고자유롭게이용하고공개할수있도록허용한다. 모든 OWASP 자료는승인된오픈소스라이선스에따라사용된다. 여러분이 OWASP 회원기관이될경우, 여러분은또한상용라이선스를사용하여, 단일라이선스에따라모든 OWASP 자료를사용, 수정및배포할수있다. 더많은정보는 OWASP 라이선스페이지를참조하기바란다. 11
참여및회원 OWASP 는누구나포럼, 프로젝트, 챕터, 컨퍼런스등에참여하는것을환영한다. OWASP 는애플리케이션보안을배우거나, 네트워킹, 심지어당신의전문가로서평판을세울수있는최고의장소이다. 만약당신이 OWASP 문서가소중하다는것을알게된다면, OWASP 회원이되어서 OWASP 지원을고려해주기바란다. 추가적인정보는, Membership 페이지를참고하기바란다. 프로젝트 OWASP 의프로젝트에는애플리케이션보안의다양한측면을포함하고있다. 우리는기관들이보안코드능력을 향상하는데도움이되는문서, 도구, 교육환경, 가이드라인, 체크리스트및다른자료를제작한다. 모든 OWASP 프로젝트들에대한자세한정보는 OWASP 프로젝트페이지를참고하기바란다. OWASP 프라이버시정책 애플리케이션보안을통해조직을돕는것이 OWASP 의미션이기때문에, 우리의회원들에관해수집된개인정보를보호할권리가있다. 일반적으로우리는우리사이트를방문한방문자들의개인정보를묻거나인증을요구하지않는다. 우리는웹사이트방문자통계를계산하기위해서오직방문자인터넷주소를수집하고이메일주소는수집하지않는다. 우리는 OWASP 결과물을다운로드받을때개인으로부터이름과이메일정보를포함한확실한개인정보를요구할것이다. 이정보는어떠한서드파티에게도공개되지않으며, 다음의목적으로만사용된다. OWASP 결과물에대한긴급한수정에대한통보 OWASP 내용에대하여조언을구하거나피드백을구하기위함 OWASP 의합의과정이나 AppSec 컨퍼런스초청시 OWASP 는회원조직목록과개개인의회원목록을발간하고있다. 목록화는순전히자발적으로이루어지며선택적으로목록에서제외하도록요청할수있다. 팩스나메일을통해보내주신여러분과여러분의기관에대한모든정보는물리적으로보호된다. 만약우리개인보호정책에대하여문의사항이나우려사항이있을경우 owasp@owasp.org 로연락주기바란다. 12
코드리뷰가이드역사 코드리뷰가이드는초기테스팅가이드노력의산물이다. 초기에는코드리뷰와테스팅을하나의동일한가이드로만들기로하였다. 당시에는이방법이좋은생각으로보였지만, 보안코드리뷰라는주제는너무커져버렸고그래서하나의독립된가이드로점차발전되었다. 코드리뷰가이드는 2006 년에시작되었다. 코드리뷰팀은구성원은적었지만, 재능있고자주참여하는지원자그룹으로구성되었다. 코드리뷰팀은소프트웨어개발생명주기 (SDLC) 에통합된적절한코드리뷰기능을가진조직이보안관점에서훨신더좋은코드를만들어냈다는것을알았다. 이러한생각으로인해많은보안취약점들이다른기술을사용하는것보다코드에서더쉽게찾아지는것과같이시행착오끝에탄생되었다. 불가피하게도, 이가이드는모든언어를포괄하고있지않다. 본문서는주로.NET 과 Java, 그리고약간의 C/C++ 와 PHP 에관점을두고있다. 그러나, 책속의기법은쉽게거의모든코드환경에적용될수있다. 다행이도웹응용의보안결함은여러프로그램언어들과확실하게일치한다. 13
소개 코드리뷰는아마보안결점을찾아내는가장효과적인한방법일것이다. 자동화된도구와수동침투시험과함께사용한다면코드리뷰를통해애플리케이션보안을보증하기위한상당한비용효과를누릴수있다. 이문서는보안코드리뷰를수행하는프로세스를다루기보다특정한취약점에대응하는코드를살펴보는메커니즘에초점을맞추고어떻게구조화시켜처리해야하는지에대해제한적인가이드를제공한다. 수동적인보안코드리뷰는안전하지않은코드와관련된 실제위험 에대한통찰력을제공한다. 수동적인접근방식으로얻는가장가치있는일이다. 코딩점검을사람이직접하면특정한코딩관습의컨텍스트를이해하고공격가능성과사업영향도를설명할수있는심각한위험을추정할수있다. 코드에취약점이있는이유는? MITRE 는 CWE 프로젝트에서대략 700 여가지종류의소프트웨어결함을분류했다. 여기에는개발자가보안위협을야기하는실수를모두포함한것이다. 모든결함은미묘하고대부분아주교묘하다. 소프트웨어개발자는학교에서이런결함에대해배우지않으며대다수직장에서도관련문제에관해훈련을받지않는다. 보안문제는최근장비간의연결성이엄청난속도로증가하고여러기술과프로토콜을추가하면서매우중요해졌다. 새로운기술을만들어내는능력은안전하게만드는능력을훨씬능가한다. 오늘날사용되는많은기술들은대부분간단한보안점검조차받지않고있다. 사업측면에서보안에적절한시간을소요하지않는이유는다양하다. 결국이런이유가소프트웨어시장의잠재되어있는문제의근원이다. 소프트웨어는최종적으로블랙박스이기때문에안전한코드와그렇지못한코드사이의차이점에대해말하기란극히어렵다. 코드리뷰는비가시성이있기때문에구매자는안전한코드에더지불하지않으려할것이고, 벤더역시안전한코드를작성하는데추가적인노력을하지않으려할것이다. 이프로젝트의목표는소프트웨어구매자가소프트웨어보안을볼수있는안목을가지고소프트웨어시장에서변화를모색하자는데있다. 보안코드리뷰를지지하고있지만그럼에도불구하고다시제자리로돌아온다. 보안에노력을하지않으면서도듣게되는 ( 별로정당성이없는 ) 몇가지변명을보자. 우리는 ( 내가알고있는한 ) 해킹을당한적이없기때문에보안이필요없다. 우리는애플리케이션을보호하는방화벽을가지고있다 우리는애플리케이션을공격하지않을것이라고직원들을믿는다. 14
지난 10 년간 OWASP 코드리뷰프로젝트를진행한팀은수천개의애플리케이션을점검했고개별애플리케이션에심각한취약점이있다는것을발견했다. 보안결함을찾기위하여코드리뷰를하지않는다면, 애플리케이션에문제가생길가능성은실제로 100% 다. 여전히많은조직은코드보안성을외면하고있다. 이런사람들에게우리가실제로알고있는럼스펠드 (Rumsfeld) 의숨겨진사실을설명해줄수있다. 회사에서위험을감수하는결정을해야한다면우리는당신을완전히지지한다. 하지만위험감수가무엇인지모른다면주주나고객모두에게책임을지지않고있는것이다. "... 우리는알려져있는사실들이있다는것을알고있다. 우리가알고있는것이있다. 우리는알려져있지만모르는것이있다는것을알고있다. 다시말해우리가모르는무언가가존재한고있다는것을알고있다. 하지만알려지지않은모르는것이존재한다. 우리가알지못한다는사실도모르는것이다. " - 도널드럼스펠드보안코드리뷰란? 보안코드리뷰는애플리케이션에적절한보안통제가존재하고, 원하는방식대로동작하며, 적절한곳에서처리되는것을보증하는감사프로세스다. 코드리뷰는애플리케이션이주어진환경에서 자체방어 를할수있도록개발되었는지보증하는방식이다. 보안코드리뷰는안전한애플리케이션개발자가안전한개발기법을따르는지보증하는방법이다. 가장최우선일반규칙은애플리케이션이적절한보안코드리뷰를받은후개발된코드에관련해침투테스트에서추가적인애플리케이션취약성이발견되지않는것이다. 모든보안코드리뷰는사람의노력과기술지원이함께진행된다. 한쪽범위는능숙하지못한사람이문자편집기를사용할때이며다른반대쪽범위는보안전문가가고급정적분석도구를사용할때라고볼수있다. 불행히도애플리케이션보안도구를효율적으로사용하려면상당히전문적인수준의지식을요구한다. 이작업을수행할수있는도구를사용할수있지만항상사람의검증이필요하다. 도구는문맥을이해하지못하는데이것이바로보안코드리뷰의핵심이다. 도구는많은양의코드를평가하여가능한문제점을찾아내는데능하지만, 사람은그게진짜문제인지실제공격가능한지모든결과에대해검증하고조직에위험으로작용하는지산출할필요가있다. 직접점검을통해자동화된도구가간단히알아낼수없는주요사각지대도확인해야한다. 15
준비 기본점검사항 코드리뷰기준을효과적으로점검하기위해서점검팀이애플리케이션의사업적용도와주요사업영향을이해하는것이매우중요하다. 이를통해심각한취약점을찾아내는방법을안내할것이다. 팀은서로다른위협에이전트, 동기, 그리고애플리케이션에잠재적으로어떻게공격할수있는지식별해야만한다. 모든정보는애플리케이션보안에관련된모든정보를나타내는상위수준의위협모델로합쳐질수있다. 점검자의목표는주요위험이적절히동작하는보안통제에의해적절히명시되어적절한장소에서사용되는지검증하는일이다. 점검자는애플리케이션설계단계에개입하는것이이상적이지만이런경우는거의없다. 대부분점검팀은거대한코드를보고잘정리해가용한시간내가장잘이용해야한다. 코드리뷰를수행하는것을감사하는것과같은같은느낌일수있는데개발자는감사받는일을싫어한다. 한가지접근방법은점검자, 개발팀, 사업대표, 그리고기존이해관계자사이에서협력하는분위기를만들어내는것이다. 개발팀에서잘협조받고싶다면경찰이아닌조언자이미지로비춰지는것이매우중요하다. 개발팀과성공적으로신뢰를구축한보안코드리뷰팀이신뢰받는조언자가될수있다. 대부분의경우보안인력이라이프사이클초기에개입되어이끌어야보안비용을현저히낮출수있다. 시작하기전 : 검토자는다음사항에익숙해야한다. 1. 코드 : 사용한개발언어, 기능과보안관점에서언어의이슈사항, 경계해야할문제점과보안및성능관점에서모범사례 2. 컨텍스트 : 애플리케이션의동작여부및환경을검토해야한다. 모든보안은보호하려는컨텍스트안에있다. 사과판매용애플리케이션에군사기준의보안메커니즘을추천하는건과하다고볼수있으며목적을벗어난것이다. 어떤유형의데이터를조작하고처리하며해당데이터가유출될경우회사의피해가어느정도인지확인해야한다. 컨텍스트는안전한코드리뷰와위험평가의 성배 (Holy Grail) 다. 추후좀더살펴보자. 3. 사용자 : 애플리케이션의의도된사용자, 외부에노출되는지 신뢰된 사용자내부에서사용되는가? 애플리케이션이다른시스템 ( 장비 / 서비스 ) 와연결되는가? 사람이애플리케이션을이용하는가? 4. 중요성 : 애플리케이션의이용성또한중요하다. 애플리케이션이 정상작동하지않거나 상당한또는짧은시간동안중지된다면조직에얼마나큰영향을미치는지? 16
발견 : 정보수집 점검팀은효율성을높이기위해애플리케이션에관한정보를수집해야한다. 정보는점검순위에사용해위협모델로통합해야한다. 이정보는빈번히설계문서, 사업요구사항, 기능명세, 테스트결과와같은문서에서알수있다. 하지만대부분실제프로젝트에서문서는유효기간이없고변경이되지않기때문에거의대부분의보안정보는적합하지않다. 따라서정확한최신정보를얻기위해서는개발자와애플리케이션설계담당자와얘기하는일이다. 개발팀입장에서주요보안고려사항과통제수단에대한기본정보를공유하는것으로충분하므로긴시간의회의를가질필요가없다. 실제동작중인애플리케이션을살펴볼수있으면애플리케이션이의도한대로작동중인지알수있으므로점검팀에매우도움이될것이다. 또한사용하는코드와라이브러리구조에대한개괄적인내용을파악하면점검팀이시작하는데도움이된다. 애플리케이션에관한정보를어떤형태로든얻지못한다면팀은코드를시험해애플리케이션이어떻게동작하는지에대해확인하고정보를공유하는데시간을할애해야할것이다. 컨텍스트, 컨텍스트, 컨텍스트 보안코드리뷰는코드를단순히검토하는일이아니다. 중요한사실은코드리뷰를하는이유가정확히돈, 지적자산, 영업비밀, 생명또는데이터와같은위탁정보와자산을보호하고있는지보증하는데있다는사실을기억하는것이다. 애플리케이션이의도한대로동작하는컨텍스트는잠재위험을설정하는데매우중요한문제이다. 점검자가비즈니스상의컨텍스트를이해하지못하면가장중요한위험을발견하지못할수도있고업무에별로중요치않은문제에만초점을맞출수도있다. 보안코드리뷰준비시에관련정보를포함한상위수준의위협모델을준비해야한다. 이후장에서전체적으로 설명하겠으나여기서주요영역을간단히살펴보자. 위협요소 공격접점 ( 외부및백엔드인터페이스 ) 가능한공격 보안통제필수요구사항 ( 공격가능성을막고회사정책준수 ) 잠재적인기술영향 주요사업영향 컨텍스트를정의하면다음정보를알수있다. 애플리케이션의사업중요성수립 애플리케이션컨텍스트범위설정 개체간신뢰관계수립 17
잠재적인위협과가능한통제수립 점검팀은다음과같이개발팀에서정보를얻기위한간단한질문을이용할수있다. 애플리케이션에어떤유형의 / 얼마나민감한정보 / 자산이있습니까? 애플리케이션에서보안과위험을평가하는핵심이다. 정보가얼만큼중요한가? 어떤방식이든정보를유실할경우사업에어떤영향을받게되는가? 애플리케이션이내부용입니까아니면외부로통합니까?, 누가애플리케이션을이용하며그들은신뢰하는사용자입니까? 내부 / 신뢰된사용자에의한공격은알려진것보다보안상잘못된인식을가질수있다. 이말은애플리케이션이식별된사용자숫자에제한되어사용하는지여부이지이사용자가모두적절한방식으로행위를한다는의미는아니다. 애플리케이션호스트위치가어디입니까? 사용자는인증없이 DMZ 를통해 LAN 구간으로진입하지못하게되어있다. 내부사용자역시인증이필요하다. 비인증은비추적성과같은말이며감사추적에약점이생긴다. 내외부사용자가있다면보안관점에서차이점은무엇인가? 내부사용자를외부사용자와어떻게구별할것인가? 인가는어떤방식으로운영되고있는가? 이애플리케이션이사업에얼마만큼중요합니까? 18
애플리케이션중요도가낮은지, 기업에핵심적인 A 계층 / 매우중요한애플리케이션인가? 좋은웹애플리케이션개발정책에따라추가적인요구사항이있으며또한다른사업의다른애플리케이션에 추가적인요구사항이있다. 코드관점에서도해당정책을따르고있는지판단하는건분석가의몫이다. 유용한 접근방식은팀이체크리스트를가지고임의의웹애플리케이션과관련된문항을점검하는것이다. 체크리스트 체크리스트가컨텍스트를제공하기위해올바른문항을가지고있다면개발팀이작성하는일반적인체크리스트 정의는매우가치가크다. 체크리스트는개발자가시도하거나생각하는보안수준의좋은척도다. 체크리스트는 다음과같은가장중요한보안통제와취약점분야를포함해야한다. 데이터유효성인증세션관리인가암호오류처리로깅보안구성네트워크아키텍쳐 19
SDLC 에서보안코드리뷰 보안코드리뷰는정형화수준에따라매우다양하다. 검토방법은동료를초대하여취약점을발견하도록것과같이비정형적일수도있고, 역할과책임, 그리고정형적인수치와품질측정프로그램을정의하여훈련된팀과함께하는정형적으로소프트웨어를점검할수도있다. 칼위그너 (Karl Wiegers) 는소프트웨어상호점검에가장비정형적인방식에서가장정형적인방식까지다음과같이 7 개점검프로세스항목을만들었다. 1. 애드혹 (Ad hoc) 리뷰 2. 패스어라운드 (Passaround) 3. 페어프로그래밍 (Pair programming) 4. 워크스루 (Walkthrough) 5. 팀리뷰 6. 인스펙션 (Inspection) SDLC 전과정에서애플리케이션보안컨설턴트가개입해야한다. 생명주기전체에서보안을수행하는일은 설계우선 보안노력이나단일화된사전소프트웨어보안검토보다훨씬더효과적이다. 일정간격으로개입하는이유는잠재적인문제점이개발생명주기에서일찍탐지되어비용이적게들기때문이다. 시스템개발생명주기 (SDLC) 와보안코드리뷰를결합하면전반적으로개발되는코드품질은굉장히향샹되는결과를가져온다. 보안코드리뷰는특효약은아니지만건전한애플리케이션개발습관의일부다. 애플리케이션프로그램보안에대한다층방어 (defense-in-depth) 접근방식의한단계로서고려해야한다. 보안코드리뷰는안전한소프트웨어개발접근의초석이기도하다. SDLC 에이단계를통합하면복잡하고비용이추가되는것으로보이지만, 장기적인시각으로보면오늘날사이버공간에서효과적이고신뢰를쌓으면서비즈니스를할수있는최고의방법이다. 폭포수 SDLC 예제 1. 요구사항정의 1. 애플리케이션보안요구사항 2. 아키텍쳐와설계 1. 애플리케이션보안아키텍쳐와위협모델 3. 개발 1. 보안코딩사례 2. 보안테스팅 3. 보안코딩점검 20
4. 테스트 1. 침투테스팅 5. 구현 1. 안전한설정관리 2. 안전한구현 6. 유지보수 애자일보안방법론예제 1. 계획 1. 보안이해관계자내용파악 2. 보안통제파악 3. 보안테스트사례파악 2. 스프린트 1. 안전한코딩 2. 보안테스트사례 3. 상호보안점검 3. 개발 1. 보안성입증 ( 침투시험과보안코드리뷰 ) 21
보안코드리뷰범위 공격접점의이해 모든입력값은그반대편에서동등한 ( 잘정렬된 ) 출력값을갖는다 보안코드리뷰의주된부분은공격접점을분석하는것이다. 애플리케이션은입력값을받아서어떤종류의출력값을만들어낸다. 애플리케이션을공격하는것은입력값흐름을이용하는것이고, 애플리케이션이예상치못한방향으로실행되면서발생한다. 따라서우선적으로코드의모든입력값을검증하는것이필요하다. 입력값의예는다음과같다. 브라우저입력값쿠키속성파일외부프로세스데이터입력서비스응답플랫파일 (Flat files) 커맨드라인파라미터환경변수 22
공격접점조사시동적및정적데이터흐름을분석한다. 매개변수, 메소드호출및데이터교환매커니즘에요구되는보안을수행한다면, 워크플로우전체를통틀어언제어디에변수가설정되고그변수가어떻게사용되는지, 객체와매개변수의속성이프로그램내의다른데이터에어떻게영향을미치는지를정의한다. 애플리케이션내의모든트랜잭션들은각각을호출하는적절한보안기능에따라식별되고분석되어야한다. 트랜잭션분석이수행되는동안분석되는대상영역은다음과같다. 모든신뢰되지않은출처로부터의데이터 / 입력값검증 인증 세션관리 인가 암호 ( 미사용데이터및전송데이터 ) 오류처리 / 정보누출 감사기록 보안코드환경 리뷰대상에대한이해 : 현재대부분의애플리케이션은프레임워크를이용해서개발된다. 이러한프레임워크는잡다한많은일을대신할수있어개발자의일을줄여준다. 따라서개발팀에서개발한객체는프레임워크의기능을확장시킨것이다. 여기서무엇보다도중요한것은주어진프레임워크와애플리케이션에대한지식으로해당프레임워크와애플리케이션이실행된다는것이다. 많은트랜잭션기능은개발자코드에서는잘보이지않고부모클래스에서다뤄질것이다. 분석가는눈앞에놓인프레임워크를인지하고해당프레임워크에대해능숙해야한다. 예제 : 자바 : 스트럿츠에서 struts-config.xml 파일과 web.xml 파일은애플리케이션의트랜잭션기능을검토하기위한 핵심포인트이다. <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.0//EN" "http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd"> <struts-config> 23
<form-beans> <form-bean name="login" type="test.struts.loginform" /> </form-beans> <global-forwards> </global-forwards> <action-mappings> <action path="/login" type="test.struts.loginaction" > <forward name="valid" path="/jsp/mainmenu.jsp" /> <forward name="invalid" path="/jsp/loginview.jsp" /> </action> </action-mappings> <plug-in classname="org.apache.struts.validator.validatorplugin"> <set-property property="pathnames" value="/test/web-inf/validator-rules.xml, /WEB-INF/validation.xml"/> </plug-in> </struts-config> struts-config.xml 파일은각각 HTTP 요청에대한행위매핑 (action mapping) 이있는반면, web.xml 파일은 배치설명서 (DD, deployment descriptor) 를포함하고있다. 예 : 스트럿츠프레임워크는입력데이터를검증하기위하여정규표현식을이용하는검증엔진을보유하고있다. 검증엔진의장점은코드에서각각의폼빈 (form bean) 에입력될필요가없다는것이다. ( 폼빈은 HTTP 요청으로부터데이터를받는자바객체이다.) 검증엔진은스트럿츠내에서기본으로활성화되어있지않다. 활성화하려면, struts-config.xml 의빨간색으로표시된 <plug-in> 절에반드시 plug-in 이정의되어야한다. 정의된속성 (property) 은스트럿츠프레임워크는사용자정의검증규측이정의되었으며 (validation.xml), 이에해당하는실제규칙이정의되었다는것을 (validation-rules.xml) 알려준다. 스트럿츠프레임워크를이해하지못해도자바코드에대한간단한감사를통해어떤검증절차도없는경우와 정의된규칙과자바기능사이의관계가없는경우를걸러낼수있다. 위코드에서파란색으로표시된부분의행위매핑은요청을받아들이는애플리케이션이취하는행위를 정의한다. 여기서 URL 이 /login 을포함할때 LoginAction 쉘이호출되는것을확인할수있다. 행위 매핑으로부터외부입력값을받았을때해당애플리케이션이실행할트랜잭션을볼수있다..NET: 24
ASP.NET/ IIS 애플리케이션은애플리케이션설정상태를유지하기위하여 web.config 라는이름의 XML기반설정파일을갖고있다. 이는인증, 인가, 오류페이지, HTTP 설정, 디버그설정, 웹서비스설정등의문제를설정할수있다. 이러한파일에대한지식없이트랜잭션분석은어렵고, 부정확할수있다. web.config 파일을웹애플리케이션가상디렉토리의최상위경로에위치시킬수있다. 설정파일이없다면, 기본설정은 machine.config 파일이설정에사용된다. 설정파일이있으면, web.config 파일의어떤설정에 관계없이기본설정을오버라이드할것이다. web.config 파일예시 : <authentication mode="forms"> <forms name="name" loginurl="url" protection="encryption" timeout="30" path="/" > requiressl="true " slidingexpiration="false"> <credentials passwordformat="clear"> <user name="username" password="password"/> </credentials> </forms> <passport redirecturl="internal"/> </authentication> 이설정파일예제의내용은다음과같다 : authentication mode: 기본인증모드는 ASP.NET 폼기반의인증을사용한다. loginurl: 유효한인증쿠키가없을때, 로그온을위해 HTTP요청이리다이렉트되는 URL을지정한다. protection: 쿠키가 3DES 혹은 DES를사용해암호화되도록지정한다. 하지만쿠키에서 DV가수행되지는않는다. 평문공격에주의해야한다. timeout: 쿠키가만료되는시간 ( 분 ) 여기에서중요한점은대부분의중요보안설정이코드에는없으며, 프레임워크설정파일내에서가능하다. 그래서프레임워크기반의애플리케이션을리뷰할때프레임워크에대한지식은무엇보다도중요하다. 25
애플리케이션위협모델링 소개 위협모델링은애플리케이션보안분석을위한하나의방법이다. 이는애플리케이션과관련보안위헙을식별, 정량화가가능한가능한구조화된접근법이다. 위협모델링은코드리뷰를위한방법이아니라보안코드리뷰절차를보완한다. SDLC 내위협모델링을포함하면애플리케이션이초기부터보안을고려해서개발되었는지확인할수있다. 이는위협모델링과정의일부분으로써생성된문서로검토자에게해당시스템을전반적으로이해할수있도록도와준다. 이는검토자가애플리케이션의입력지점이어디해위치해있는지, 또각입력지점과관련된위협들은어떤것이있는지알수있도록한다. 위협모델링은이제는새로운개념이아니지만수년간에걸쳐위협모델리에대한인식이변하였다. 현재위협모델링은시스템을방어하는입장과반대로, 잠재적공격자의관점에서시스템을바라보고있다. 마이크로소프트는지난몇년간이프로세스에대해강력하게지지해왔다. 마이크로소프트는위협모델링을자사제품의보안성향상을위한 SDLC 의핵심요소로만들어왔다. 기존의애플리케이션과같은 SDLC 외부에서소스코드를분석할때, 위협모델링을통해깊이있는분석과폭 넓은분석을수행하여소스코드분석의복잡도를줄일수있다. 동등한관점으로모든소스코드를리뷰하는 대신에, 고위험군에속한위협모델링의구성요소에대해서는우선적으로보안코드리뷰를할수있다. 위협모델링절차는 3 단계로나뉜다. 1 단계 : 애플리케이션분리. 위협모델링의첫단계는애플리케이션이외부개체와어떻게반응하는지및애플리케이션에대한이해를얻는것과관련이있다. 이는잠재적인공격자관점에서애플리케이션과어떻게상호작용하는지를확인하기위한입력지점을확인하는것과, 공격자가관심있게볼만한항목이나영역, 애플리케이션이외부개체에대해접근을허용할신뢰도수준을확인하는것에대해해당애플리케이션이어떻게사용되는지이해하기위한사용자케이스생성을포함한다. 이정보는위협모델 (Threat Model) 문서에명세되어있으며, 해당애플리케이션에대한데이터플로우다이어그램 (Data Flow Diagrams, DFDs) 을제작하는데에도사용된다. DFD 는시스템전체의다양한경로를우선순위영역을하이라이트하여보여준다. 2 단계 : 위협결정및순위화. 위협범주화방법론을이용하여위협을확인하는것이중요하다. STRIDE 와같은위협범주가사용될수있고, 혹은감사, 인증, 인가, 설정관리, 통신및스토리지내의데이터보호, 데이터검증, 에외관리와같이위협을정의하는애플리케이션보안프레임 (Application Security Frame; ASF) 를사용할수있다. 위협범주화의목표는공격자로부터의위협과 (STRIDE) 방어하는관점모두에서위협을확인할수있다. 1 단계에서도출된 DFD 는데이터소스, 프로세스, 데이터플로우, 사용자와의상호작용과같은공격자의관점에서의잠재적인위협대상을확인하는데도움이된다. 이러한위협은위협대상에대한위협트리의최상위에서확인할수있다. 위협을목표로하는하나의트리가있다. 방어하는관점에서, ASF 범주화는각종 26
위협과같은보안관제의취약성을확인하는데도움이된다. 예시로제시된공통적인위협목록은이러한위협을확인하는데도움이된다. 적절한사용과오용사례들은현존하는보안장치들이어떻게우회될수있는지, 또는이러한보안이적용되었을때결함이어디에존재하는지분명히보여줄수있다. 각위협에대한보안위험도측정은 DREAD 와같은값기반의위험도모델이나발생가능성이나영향도와같이일반적위험요소들을기반으로하는비교적덜주관적인질적위험모델을이용해측정할수있다. 3 단계 : 대응방안과완화방안을강구하라. 특정위협에대한보안결함은바로대응해야할정도로위협에노출된취약점을내포하고있다. 이러한대응책은위협대응매핑목록을사용해인증될수있다. 일단어떤보안위협이위험도순위에올라가면위협의최상위부터최하위까지정렬이가능하며, 인증된대응방안을적용함으로써위와같은위협의대응을위한완화작업에대해우선순위를매길수있다. 위험완화전략에는위험을제거하고감소시키는사업적효과로인한위협을평가하는것도포함시켜야한다. 다른옵션에는보상을통제하고해당위협의대상이되는사용자에게이를알리며, 위협을제거하거나최소한더나은옵션을취하기위해, 위험을감수했을때의사업적효과가적합한지추정하는것을포함시켜야한다. 위의각단계를수행한후에는문서화된다. 결과문서는해당애플리케이션에대한위협모델이다. 이가이드는위협모델링의개념을설명하기위한예시로사용될것이다. 본예제는대학도서관웹사이트로, 이를이용해위의 3 단계각각을학습하게될것이다. 본가이드의마지막에서여러분들은대학도서관웹사이트의위협모델을만들게된다. 위협모델링과정의각단계는아래에자세히서술하겠다. 애플리케이션분리 이단계의목표는해당애플리케이션을이해하고, 어떻게애플리케이션이외부개체와상호작용하는지이해하는것이다. 정보수집하고문서화를통해목표를달성할수있다. 올바른정보가수집되었는지확인하도록명확하게정의된구조를이용해정보를수집하는프로세스를수행한다. 이구조는물론어떻게정보가문서화되어야하고위협모델을산출할지도정의한다. 위협모델정보 위협모델의첫번째항목은해당위협모델에관련된정보이다. 다음과같은것들이포함되어있어야한다. 1. Application Name 애플리케이션이름 2. Application Version 애플리케이션버전 3. Description 해당애플리케이션의상위레벨설명 4. Document Owner 본위협모델링문서의소유자 5. Participants 본애플리케이션위협모델링프로세스참여자 6. Reviewer 위협모델검토자 27
예 : < 애플리케이션이름 > 위협모델정보 애플리케이션 버전 1.0 설명 : 대학도서관웹사이트는사서및도서관이용자 ( 학생및교직원 ) 에게온라인서비스를제공하는최초로구현된웹사이트이다. 웹사이트의첫번째구현이므로, 기능은제한된다. 애플리케이션의 3 종류의사용자가있다. 1. 학생 2. 교직원 3. 사서교직원과학생은로그인하고도서검색을할수있으며, 교직원은도서요청을할수있다. 사서는로그인하고, 도서추가, 사용자추가및도서검색을할수있다. 문서작성자 : 참가자 : 검토자 : David Lowry David Rook Eoin Keary 외부종속성 외부종속성은애플리케이션에위협을야기할수있는외부코드에서가져온요소들을의미한다. 이런요소들은일반적으로어떤조직의통제하에있겠지만, 개발팀이통제할수있는것은아니다. 외부종속성을조사할때첫번째로살펴볼것은해당애플리케이션이제품환경에서어떻게사용될것이고무엇을필요로할것인가이다. 이는애플리케이션이의도대로실행되는지혹은그렇지않은지확인하는것도해당된다. 예를들면해당기관의표준을강화시키고방화벽의뒤에서동작시킬목적으로서버상에서동작하는애플리케이션의경우, 이러한정보는외부종속성절에문서화되어야한다. 외부종속성은다음과같이문서화한다. 1. ID 외부종속성에인가된고유 ID 2. 설명 외부종속성의텍스트설명 28
예 : 외부종속성 ID 설명 1 대학도서관웹사이트는아파치를실행하는리눅스서버에서실행된다. 서버는대학의서버보안강화 기준에따라보안성이강화된다. 즉최신의운영체제의애플리케이션과애플리케이션보안패치를 포함한다. 2 데이터베이스서버는 MySQL 이며리눅스서버에서실행된다. 서버는대학의서버보안강화기준에따라 보안성이강화된다. 즉최신운영체제의애플리케이션과애플리케이션보안패치를포함한다. 3 웹서버와데이터베이스서버는사설네트워크상에서연결된다. 4 웹서버는방화벽뒤에있으며, TLS 를통해서만통신이가능하다. 입력지점 입력지점은잠재적으로공격자가애플리케이션과상호작용하거나데이터를삽입할수있는인터페이스를의미한다. 잠재적인공격자가공격하기위해서는반드시입력지점이존재한다. 애플리케이션내의입력지점은계층화될수있는데, 예를들면웹애플리케이션의각웹페이지는다수의입력지점을갖고있다. 입력지점은다음과같이문서화되어야한다 : 1. ID 입력지점에허용된고유 ID. 이 ID 를이용해서식별된어떤위협또는취약점을가지고있는입력 지점은상호참조한다. 계층입력지점의경우 major.minor 표기법이사용되어야함. 2. 이름 입력지점과그목적을확인할서술명. 3. 설명 입력지점에서발생하는인터랙션이나프로세싱을자세하게글로묘사. 4. 신뢰수준 입력지점에요구되는접근수준은여기에문서화된다. 이는나중에문서에정의되는신뢰 수준과상호참조되어야한다. 예 : 입력지점 ID 이름설명신뢰수준 29
1 HTTPS 포트 대학도서관웹사이트는 TLS 를통해서만접근 가능하다. 대학도서관웹사이트에있는모든 페이지는이입력지점에계층화되어있다. (1) 익명웹사용자 (2) 정상로그인사용자 (3) 비정상로그인사용자 (4) 사서 (1) 익명웹사용자 1.1 도서관메인 페이지 대학도서관웹사이트의시작페이지는모든 사용자의입력지점이다. (2) 정상로그인사용자 (3) 비정상로그인사용자 (4) 사서 (1) 익명웹사용자 1.2 로그인 페이지 학생, 교직원및사서는유스케이스하나를 실행하기전에반드시대학도서관웹사이트에 로그인해야한다. (2) 정상로그인사용자 (3) 비정상로그인사용자 (4) 사서 1.2.1 로그인기능 로그인기능은데이터베이스와비교하여, 사용자를인증한다. (2) 정상로그인사용자 (3) 비정상로그인사용자 (4) 사서 1.3 검색엔트리 페이지 검색어를입력하는데사용되는페이지. (2) 정상로그인사용자 (4) 사서 자산 시스템에는해커가관심을가질만한무언가를반드시갖고있다. 이런흥미로운아이템들과영역을자산이라고정의한다. 자산은본질적으로위협목표가되는데, 즉이런것들이위협이존재하는이유이다. 자산은물리적자산과추상적자산모두가될수있다. 예를들면, 애플리케이션자산은클라이언트목록및클라이언트의개인정보가될것이다. 이런것들이물리적자산이다. 추상적자산은조직의평판이될수있다. 자산은다음과같이위협모델에서문서화된다. 30
1. ID - 유일한 ID는각자산을식별하기위해사용된다. ID는위협이존재하는자산또는정의된취약점을상호참조하는데사용 2. 이름 - 자산을식별하도록설명한이름 3. 설명 - 어떤자산을왜보호해야하는지를설명 4. 신뢰수준 입력지점에접근하기위해필요한접근레벨은문서화되어있다. 이것들은다음단계에서정의된신뢰수준과함께상호참조 31
예 : 자산 ID 이름설명신뢰수준 1 도서관 사용자및 사서 학생, 교수진및사서와관련된자산 (2) 정상로그인 사용자 1.1 상세 사용자 로그인 대학도서관웹사이트에로그인하기위해학생또는 교수진들이사용하는로그인자격인증 (4) 사서 (5) DB 서버관리자 (7) 웹서버사용자프로세스 (8) DB 읽는사용자 (9) DB R/W 사용자 (4) 사서 (5) DB 서버관리자 1.2 상세사서 로그인 대학도서관웹사이트에로그인하기위해사서들이 사용하는로그인자격인증 (7) 웹서버사용자프로세스 (8) DB Read 사용자 (9) DB R/W 사용자 1.3 개인정보 대학도서관웹사이트는학생, 교직원, 사서와관련된 개인정보를저장할것이다 (4) 사서 (5) DB 서버관리자 (6) 웹사이트관리자 (7) 웹서버사용자프로세스 (8) DB Read 사용자 (9) DB R/W 사용자 2 시스템하부시스템과관련된자산 32
대학도서관 웹사이트 2.1 가용성대학도서관 대학도서관웹사이트는학생들, 교수진, 사서들이 하루 24 시간언제든지접근할수있어야한다. (5) DB 서버관리자 (6) 웹사이트관리자 웹사이트의 가용성 2.2 웹서버사용자로코드실행권한 웹서버사용자로서웹서버에서소스코드를실행할 수있다. (6) 웹사이트관리자 (7) 웹서버사용자 프로세스 DB 열람 / 등록 SQL 을실행하는능력. 데이터베이스에서 Select (5) DB 서버관리자 2.3 사용자로서 쿼리를수행하여, 대학도서관에저장된정보를 (8) DB Read 사용자 SQL 실행 검색한다. (9) DB R/W 사용자 권한 DB R/W SQL 을실행하는능력. 데이터베이스에대한열람, 2.4 사용자로서 SQL 실행 등록및수정쿼리를실행하여, 대학도서관데이터베이스에저장된정보에읽기및쓰기접근 (5) DB 서버관리자 (9) DB R/W 사용자 권한 권한이있다. 3 웹사이트대학도서관웹사이트와관련된자산 3.1 로그인 세션 대학도서관웹사이트에대한사용자로그인세션이다. 사용자는학생, 교직원또는사서이다. (2) 정상로그인 사용자 (4) 사서 3.2 DB 서버 접근 데이터베이스운영을위한접근권한을갖고, 모든 사용자에대한접근권한과데이터베이스내의모든 데이터에대한접근권한을갖는다. (5) DB 서버관리자 3.3 사용자 생성권한 학생, 교수진, 사서들개개인이시스템에신규계정을 생성할수있도록한다 (4) 사서 (6) 웹사이트관리자 3.3 감사 데이터 감사데이터는대학도서관애플리케이션내에서 사용자들로부터발생한모든감사가능한이벤트들을 (6) 웹사이트관리자 33
접근보여준다. 신뢰수준 신뢰수준은애플리케이션이외부객체들에게허용하는접근권한을나타낸다. 신뢰수준은입력지점과 자산을상호참조한다. 이를통해각각의입력지점에서요구되는접근권한과각각의자산과상호작용하는 접근권한을정의한다. 신뢰수준은위협모델에아래와같이문서화되어있다 : 1. ID - 각신뢰수준에부여된유일한식별자. 입력지점, 자산과함께상호참조된다. 2. 이름 - 신뢰수준을가진외부객체를식별하기위한이름 3. 설명 - 신뢰수준을가진외부객체에대해자세히설명된본문 예 : 신뢰수준 ID 이름설명 1 익명웹사용자 정당한자격증명을제공하지않고대학도서관웹사이트에접속된 사용자 2 정상로그인사용자정상적인로그인을통해대학도서관웹사이트에접속한사용자 3 비정상로그인 사용자 비정상로그인을시도하여대학도서관웹사이트에접속한사용자 4 사서 사서는도서관웹사이트에신규사용자를생성할수있으며 그들의개인정보를열람할수있다. 5 DB 서버관리자 DB 서버관리자는대학도서관웹사이트 DB 에읽기또는쓰기가 가능하다 6 웹사이트관리자웹사이트관리자는대학도서관웹사이트설정을할수있다 7 웹서버사용자웹서버에서코드를실행하고데이터베이스서버에대해하고 34
프로세스데이터베이스서버를대상으로자신을인증하는프로세스 / 사용자이다. 8 DB Read 사용자 DB 사용자계정은 DB 읽기접근을위해사용된다. 9 DB R/W 사용자 DB 사용자계정은 DB 읽기및쓰기접근을위해사용된다. 데이터흐름도 데이터흐름도 (DFD:Data Flow Diagram) 를이용해서수집된모든정보를통해애플리케이션에대해정확하게모델링할수있다. DFD는애플리케이션프로세스데이터에대한시각적인표현을제공하여애플리케이션에대해더쉽게이해할수있도록한다. DFD의장점은애플리케이션을통해데이터가이동하는방법과데이터가이동할때발생하는점에대해서초점을두고있다. DFD는계층구조이기때문에애플리케이션을서브시스템과낮은수준의서브시스템으로분해하는데사용될수있다. 높은수준의 DFD를통해애플리케이션모델링범위를명확하게할수있다. 낮은수준의반복은특정데이터를프로세싱할때해당프로세스에초점을맞추도록해준다. DFD에서는위협모델링을위해사용되는기호들이있다. 이들은다음과같다. 외부개체 외부엔터티모양은입력지점을통해연동되는애플리케이션외부의개체를표현하는데사용된다. 되어진다 프로세스 프로세스모양은애플리케이션내의데이터를처리하는일을표현한다. 해당태스크는데이터를처리하거나 데이터에기반한동작을수행할것이다. 35
다중프로세스 다중프로세스모양은서브프로세스집합을보여준다. 다중프로세스는다른 DFD 에서서브프로세스로나뉠수 있다. 데이터저장소 데이터저장소모양은데이터가저장된위치를나타내는데사용된다. 데이터저장소는데이터를수정할수 없으며오직데이터를저장한다. 데이터흐름 데이터흐름모양은애플리케이션내의데이터이동을나타낸다. 데이터이동의방향은화살표에의해표현된다. 권한범위 권한범위모양은데이터가응용프로그램을통해이동할때권한수준이변경되는것을나타낸다. 36
예 : 대학도서관웹사이트에대한데이터흐름다이어그램 37
대학도서관웹사이트에대한사용자로그인데이터흐름다이어그램 위협결정기준및순위화 위협분류 위협을결정하기위한첫번째단계는위협을분류하는것이다. 위협분류를통해해당하는예와함께위협분류 집합을제공하며, 이를통해구조적및반복적으로위협이체계적으로애플리케이션에서식별될수있다. STRIDE STRIDE 와같은위협분류는아래와같이공격목적을분류하여위협식별하는데유용하다. 스푸핑 (Spoofing) 조작 (Tampering) 부인 (Repudiation) 38
정보공개 (Information Disclosure) 서비스거부 (Denial of Service) 권한상승 (Elevation of Privilege) 이분류의일반적으로위협목록과보안통제목록에대한예는아래와같다. STRIDE 위협목록 타입예시보안통제 스푸핑불법적인접근과다른사용자의 ID, 패스워드와같은인증정보를사용한다인증 조작 데이터를악의적인목적으로예를들어데이터베이스에저장된지속적인데이터를 변경및수정하고, 인터넷과같은공개된네트워크를통해두컴퓨터사이에서 통신하는데이터를변경한다. 무결성 부인보안에취약한시스템내에서불법적인행위를수행한다. 부인방지 정보공개허가되지않은파일을열람하거나전송되는데이터를열람한다. 기밀성 서비스거부웹서비스를일시적으로중단시켜정상적인사용자의접근을거부한다. 가용성 권한상승정보에대한비인가된접근을위해권한획득을시도하거나시스템을손상시킨다. 인가 보안통제사항 기본위협원과비즈니스영향이분석되면, 코드검토팀은비즈니스영향을주는위협원을막기위한대응방안을 식별해야한다. 코드리뷰의주안점은보안통제사항들이필요한부분에서알맞게동작하는것을보장하는 것이다. 아래점검항목은모든발생가능한위험을식별하는데도움이된다. 인증 : 모든내부, 외부연결 ( 사용자와객체 ) 이적절하고충분한인증절차를통해이루어지도록확인한다. 또한인증절차가우회되지않도록확인한다. 모든페이지가인증을수행하는지확인한다. 인증관련정보또는민감정보가전달될때마다, HTTP "POST" 메소드를통한정보들만처리되며, HTTP "GET" 메소드는허용되지않도록확인한다. 39
어떤페이지는비즈니스또는개발팀에의해인증을우회하여외부에서접근이가능한것으로간주하며, 이에대한리뷰및보안취약점평가를수행한다. 인증정보가평문으로전송되지않도록확인한다. 개발및디버그관련백도어가제품코드에포함되어있지않는지확인한다. 인가 : 인가절차가존재한다. 애플리케이션이정확하게사용자유형과권한을정의한다. 운영에필요한최소한의권한이사용된다. 인가절차적절하게수행되고, 장애안전성을보장하고, 우회되지않는다. 모든요청에대해서인가절차가수행된다. 개발및디버그관련백도어가제품코드에포함되어있지않다. 쿠키관리 : 민감한정보를포함하지않는다. 쿠키조작을통한비인가활동이수행되지않는다. 적절한암호화가수행된다. 보안플래그 (secure flag) 를사용하여안전하지않은방법으로쿠키가전송되지않는다. 만약애플리케이션코드의변경이발생하면쿠키에대한부분을적절하게검사하고사용한다. 세션데이터의유효성을검증한다. 가능한최소한의개인정보만사용한다.. 민감한정보가쿠키에존재할경우전체쿠키에대한암호화를수행한다. 모든쿠키들이사용하는애플리케이션의이름과필요한사유를정의한다. 데이터 / 입력값검증 : 데이터검증절차가존재한다. http 헤더, 입력폼, 히든필드, 드롭다운리스트와기타웹컴포넌트들처럼악의적인사용자에의해수정될수있는모든입력값에대해적절한확인을수행한다. 모든입력값의길이를검사한다. 모든필드, 쿠키, http 헤더 / 바디, 폼필드를검증한다. 데이터가형식에맞고, 안전한문자만포함되어있다. 서버측에서데이터검증이수행된다. 중앙집중형구성또는분산형구성을사용할경우, 데이터검증이어느곳에서수행되는지확인한다. 40
데이터검증모델에는백도어가없는지확인한다. 황금규칙 : 종류에상관없이모든외부입력값을검사하고확인한다. OWASP 코드리뷰가이드 1.1 한글본 2015 오류처리 / 정보누출 : 값을리턴하는모든메소드 / 함수가적절한오류처리및리턴값을검사한다. 예외및오류조건이적절하게처리되고있는지확인한다. 시스템오류가사용자에게전달되지않도록한다. 안전한방법으로애플리케이션장애가처리된다. 오류발생시할당된자원이해제된다. 로그 / 감사 : 오류발생시민감정보를기록하지않는다. 정의된최고길이값또는기록절차에서요구하는길이값에대한페이로드가기록된다.. 민감한데이터, 예를들면, 쿠키, HTTP "GET" 메소드, 인증정보들이기록되지않는지확인한다. 애플리케이션에대한감사를수행하게되면, 데이터조작 / 생성, 갱신, 삭제행위에대한기록을검사한다. 성공또는실패한인증을기록한다. 애플리케이션오류를기록한다. 민감한정보에대한애플리케이션의디버그기록을검사한다. 암호 : 내부또는외부에서민감한데이터는평문으로전송하지않는다. 애플리케이션은검증된암호화알고리즘을사용한다. 시큐어코딩환경 : 사용자가직접접근할수있는컴포넌트가있는지파일구조를검사한다. 모든메모리할당 / 해제를검사한다. 애플리케이션의동적 SQL을검사하고인젝션취약점이있는지확인한다. 애플리케이션의 main() 을실행하는함수또는백도어를검사한다. 민감한정보를포함할코멘트아웃코드및테스트코드 ( 디버그를위해일시적으로주석처리한코드 ) 를찾는다. 조건로직에는디폴트값이있어야한다. 빌드디렉토리에개발환경도구를포함하지않는다. OS 호출및파일생성호출을검색하고, 오류가능성을검사한다. 41
세션관리 : 언제, 어떻게인증된사용자또는인증되지않은사용자에대한세션이생성되는지검사한다. 세션 ID의강도가요구사항을충족시키는지세션 ID를검사한다. 세션이 DB, 메모리등에저장되는방법을검사한다. 애플리케이션이어떻게세션을추적하는지검사한다. 유효하지않은세션 ID가발생할경우애플리케이션에서취할조치를결정한다. 세션무효화를조사한다. 멀티쓰레드 / 멀티사용자세션관리를수행방법을확인한다. HTTP 타임아웃세션을확인한다. 로그아웃기능을확인한다. 위협분석 위협분석을위한기본조건은위협원이애플리케이션을공격할수있는취약점을이용하여애플리케이션에 영향을미치는가능성, 즉위험을정의하는것이다. 위험관리측면에서, 위협모델링은위험을최소화하고 애플리케이션환경에대한위협을식별하고열거하기위해체계적이고전략적으로접근해야한다. 위협분석은애플리케이션의위험을식별하고, 애플리케이션기능성과구조적인측면과관련있다. 또한잠재적 인취약점을식별및분류하기위한설계가필요하다. 위협모델링의첫번째단계로서, 우리는데이터흐름, 신뢰영역, 프로세스구성요소, 입력지점 - 출력지점에 대한시스템을모델링했다. 예 : 대학도서관웹사이트에대한 DFD 가해당예제로서사용되었다. 데이터흐름은데이터가종단간논리적으로흐르는방법을보여주고있어, 임계점을통해컴포넌트에미치게되는컴포넌트와이러한컴포넌트를통한제어흐름을알수있다. 프로세스구성요소는웹서버, 애플리케이션서버그리고데이터베이스서버의데이터가처리되고있는위치를보여준다. 입력지점은데이터가입력되는위치를보여주며출력지점은시스템을종료하는지점이다. 입력, 출력지점은신뢰의경계선을정의한다. STRIDE 모델기반위협목록은해킹과관련된위협을식별하는데있어서유용하다. 예를들어, 로그인공격시나리오의경우, 해커가패스워드를알아내기위해무차별대입공격을한다면? 또는권한상승을위해다른사용자의권한을얻으려고강제브라우징 (forceful browsing) 공격을시도한다면? 위협의종류를인식하고모든가능한공격요소를해커의관점에서평가하는것과, 입력-출력지점을고려하는것은매우중요하고필수적이다. 예를들어, 로그인페이지는로그인데이터를입력받는데, 이런경우악의적인목적을가진 SQL 인젝션, 크로스사이트스크립팅그리고버퍼오버플로우가발생할가능성이있다. 추가로, 해당 42
데이터는데이터흐름에따라다음단계에있는진입지점에서위협을확인하기위해사용되어진다. 만약다음컴포넌트가민감한데이터를가지고있다면, 해당지점이좀더중요할수있다. 종단간데이터흐름에서, 예를들면, 로그인페이지로부터받은 ID와패스워드같은입력데이터가검증되지않고전달될경우, 인증을우회할수있는 SQL 인젝션공격을통해 DB 테이블변경이발생할수있다. 출력지점은 XSS 공격같이클라이언트에대한공격지점으로활용될수있다. 예를들면, 컴포넌트출력지점에서 인증데이터를처리하는경우, 기밀성및무결성에대한보안통제가부족한종료지점은비인가사용자에게 인증정보정보를유출될수있다. 출력지점에서의위협은대부분입력지점이가진위협과관련되어있다. 로그인을예로들면, 입력지점이 취약한출력지점을통해계정정보및 SQL 예외에관한오류메시지가사용자에게리턴된다. 방어하는입장에서, 위협식별은 ASF 와같은보안통제분류에의해수행되며, 위협분석가는보안통제사항에 있는취약점과관련된이슈에초점을맞출수있다. 일반적으로위협식별프로세스는각컴포넌트에서평가되는 위협리스트에서발생가능한위협이반복되는사이클과관련되어있다 다음에는위협이공격되기위한공격경로, 근본원인 ( 취약점 : 오렌지색깔로된부분 ) 및필요한통제 조치 ( 대응방안 : 초록색으로된부분 ) 사항을조사하여좀더상세히위협을분석한다. 그림 2 에서보여주는위협 트리는위협분석에유용하다. 일반적인위협, 취약점그리고해커에대한확인이되면, 오남용사례에대해좀더집중적으로위협을분석해야한다. 철저한실제시나리오분석을통해, 보안약점이식별될수있다. 악용사례는보안요구엔지니어링활동의일부로서식별되어야한다. 이런사례는어떻게보호장치를우회할수있었는지, 또는어느곳에보호대책이부족한지묘사할수있다. 오남용사례를아래그림을통해보여준다. 43
결국시스템내에각컴포넌트에대한위협의종류를알아냄으로써이모든게동시에가능하다. 이것은 STRIDE 또는 ASF 같은위협분류화를이용하면가능하다. 어떻게취약점을이용해위협이노출되는지알아내기위해 위협구조를사용하고, 오남용사례는위협을줄이기에부족한대응책을알수있다. DFD 아이템에 STRIDE 를적용하여아래테이블을사용할수있다. 44
위협순위화 위협은위험요소의관점에서순위화할수있다. 다양한식별된위협으로부터위험요소를확인할수있고, 위험완화전략에도움이되는위협우선순위를만들수있다. 다른위험요소들은어떤위협이높음, 중간, 낮음위험에랭크되었는지알아내기위해사용된다. 일반적으로, 위협-위험모델은아래표와같이서로다른요소들을사용한다. DREAD 마이크로소프트 DREAD 위협위험순위모델에서는영향도에대한기술적인위험요소는피해수준및해킹된사용자수이며, 공격난이도요소는재현가능성, 악용가능성그리고발견가능성이다. 위험을분해하면위협에영향을줄수있는서로다른요인에값을할당할수있다. 순위를알아보기위해위헙분석가들은각위험요소에대한기본적인질문에답해야한다. 예를들면아래와같다. 피해수준 (Damage) : 얼마나피해가날수있는가? 재현가능성 (Reproducibility) : 얼마나쉽게공격을재현할수있는가? 악용가능성 (Exploitability) : 해당위협을악용되기위해어느정도의시간과노력이필요한가? 사용자영향도 (Affected Users) : 위협이노출된다면, 얼마나많은사용자에게영향을미치는가? 발견가능성 (Discoverability) : 얼마나쉽게해커가위협을찾아낼수있는가? 45
대학도서관웹사이트를참조하여아래샘플처럼사용할수있다. 위협 : 악의적인사용자가학생, 교직원그리고사서들의기밀정보를열람할수있다. 1. 피해가능성 : 재정적, 법적책임및평판에대한위협 : 8 2. 재현가능성 : 완벽히재현가능함 : 10 3. 악용가능성 : 같은서브넷또는취약한라우터가요구됨 : 7 4. 사용자영향도 : 모든사용자에영향을미침 : 10 5. 발견가능성 : 쉽게발견가능함 : 10 전체적인 DREAD 점수 : (8+10+7+10+10)/5 = 9 이경우, 10 점만점에 9 점이며대단히높은위험을갖는다. 일반적위험모델 보다일반적인위험모델은발생가능성 ( 즉, 공격가능성 ) 과영향도 ( 즉잠재적손상 ) 을고려한다. 위험 = 발생가능성 x 영향도 발생가능성과확률은악용되기쉬운정도로정의되며, 주로위협의종류와시스템특성, 그리고적절한대응책에 따른위협에대한인식정도에좌우된다. 아래는취약점악용가능성을확인하기위해고려해야할내용들이다. 1. 해당취약점이원격에서실행가능한가? 2. 인증을필요로하는가? 3. 취약점에대한자동화가가능한가? 해당영향은주로잠재적인손상가능성과영향의규모, 위협에의해영향을받는컴포넌트숫자에좌우된다. 피해가능성을확인하기위한예제는아래와같다. 1. 해커는완전하게시스템을장악할수있는가? 2. 해커는관리자권한으로시스템에접근할수있는가? 3. 해커는시스템장애를일으킬수있는가? 4. 해커는민감한정보를획득할수있는가? 46
위협을받은컴포넌트숫자를확인하기위한예제는다음과같다. 1. 얼마나많은데이터소스와시스템들에영향을주었는가? 2. 위협원이얼마나깊이깊숙히인프라에영향을주었는가? 해당예제들은정성적인값들 ( 높음, 중간, 낮음 ) 을할당하여전체적인위험수준을계산하는데도움이된다. 이 경우 DREAD 모델과같은경우질적인값보다는양적인값을사용하면객관적인순위를정할수있다. 대응책확인 대응책을확인하는목적은위협분석을통해확인된각위협에대해몇가지보호대책 ( 예 : 보안관리, 정책방안 ) 으로 실제발생을사전에예방하기위해서이다. 대응책이없는위협은취약점이된다. 이러한위협은각각 STRIDE 나 ASF 로분류되어있기때문에, 주어진범주내에서응용프로그램에서적절한대응책을찾을수있습니다. 아래간략하고제한적인점검표가제공되며특정위협에대한대응책확인을위해완벽한목록은아니다. 예를들어 ASF 위협유형에대한대응책은다음의표와같다 : ASF 위협및대응책항목 위협유형 대응책 인증 1. 자격증명과인증토큰을통해전송및저장시보호한다. 2. 무차별대입공격, 사전공격및재생공격에내성이있는프로토콜을사용한다. 3. 강력한암호정책을사용한다. 4. 신뢰할수있는인증서버로 SQL 인증을대신한다. 5. 패스워드는해쉬화하여저장한다. 6. 패스워드재설정시패스워드힌트와계정의유효여부를제공하지않는다. 7. 서비스거부공격으로계정이 47
잠기지않도록한다. 인가 1. 자원에대한접근권한에강력한접근통제목록들을사용한다. 2. 역할기반접근통제를통해특정작업에대한접근을통제한다. 3. 시스템사용자와서비스계정에대해최소권한의원칙을따른다 4. 프리젠테이션, 비즈니스와데이터접근계층간정확하게권한분리를구성한다. 구성관리 1. 최소권한프로세스는관리기능이없는서비스계정을사용한다. 2. 모든관리및활동에감사및로깅이활성화되야한다. 3. 환경구성파일과관리자인터페이스에대한접근권한은관리자로제한한다. 데이터저장및전송시보호 1. 표준암호화알고리즘과적절한크기의키를사용한다. 2. 해쉬메시지인증코드 (HMAC) 를통해데이터무결성을보호한다. 3. 비밀데이터 ( 예 : 키, 기밀데이터 ) 를전송및저장시암호화하여보호한다. 4. 보안을제공하는저장소는보호키를사용한다. 5. 자격증명없이민감한데이터를 48
평문으로전송하지않는다. 데이터확인 / 매개변수확인 1. 데이터유형, 형식, 길이와범위의확인을강화한다. 2. 클라이언트에서보내온모든데이터를검증한다. 3. 매개변수 ( 예 : URL 매개변수 ) 를기반으로보안정책을적용하지않는다. 4. 화이트리스트로입력값필터링을검증한다. 5. 출력값을인코딩한다. 오류처리및예외관리 1. 모든예외는구조화된방식으로처리한다. 2. 오류나예외의경우적절한권한으로복원한다. 3. 오류메시지민감하지않은정보가담긴하찮은오류메시지라도공격자에게공개되지않도록한다. 사용자및세션관리 1. 쿠키에일반텍스트로중요한 정보를저장하지않는다. 2. 인증된쿠키의내용은 암호화한다. 3. 쿠키는만료되도록구성한다. 4. 재생공격에강한세션사용 5. 안전한통신채널을통해인증 쿠키를보호한다. 6. 중요기능수행전강제로 사용자재인증을수행한다. 7. 로그아웃시세션을만료한다. 49
STRIDE 위협 & 완화기술목록 위협유형 완화기법 접근권한획득 1. 적절한권한부여 2. 비밀데이터보호 3. 비밀저장금지 데이터변조 부인 정보유출 1. 적절한권한부여 2. 해쉬 3. MAC 4. 전자서명 5. 변조방지프로토콜 1. 전자서명 2. 타임스탬프 3. 감사추적기록 1. 권한부여 2. 프라이버시개선프로토콜 3. 암호화 4. 비밀데이터보호 5. 비밀저장금지 1. 민감한정보 ( 패스워드등 ) 는기록하지않는다. 2. 로그파일에무단접근을막기위해접근통제목록 (ACL) 을적용한다. 3. 로그파일부인방지를위해무결성제어 ( 서명 ) 를적용한다. 4. 로그파일은민감한작업과주요이벤트에대한감사추적을제공한다. 5. 여러서버와계층간에감사와로깅이가능하게한다. 서비스거부 1. 적절한권한부여 2. 적절한승인 3. 필터링 4. 제한 5. 서비스품질 권한상승 1. 최소권한으로실행 50
STRIDE 를사용할경우다음과같은위협완화테이블을통해위협을완화하기위해사용할수있는기술을 확인할수있다. 위협및대응책이확인되면, 다음과같은프로필을도출할수있다. 1. 완화되지않은위협 : 위협에대한대응책이없으며취약점이전체적으로악용되여영향을일으킬수있다. 2. 부분적으로완화된위협 : 위협에대해하나이상의부분적인대응책으로취약점일부가악용되어제한적인영향을일으킬수있다. 3. 완벽히완화된위협 : 이위협은적절한대응책을가지고있고취약점이악용되지않으며영향을미치지않는다. 완화대책 위험관리의목적은응용프로그램개발에서있을수있는위협의영향을줄이는것이다. 이것은위협완화대책을 통해해결할수있다. 일반적으로위협을완화하는데는 4 가지방법이있다. 1. 아무것도하지않는다 : 예 ) 최선을희망 2. 위험에대해알린다 : 예 ) 위험에대해사용자에게경고 3. 위험을완화시킨다 : 예를들면, 적절한대책을통해완화 4. 위험을수락한다 : 예 ) 개발효과 ( 사업효과 ) 를평가한후 5. 위험을전환 : 예 ) 계약및보험계약을통해 위협이발생하여미치는영향즉전환비용 ( 보험료 ), 피해수준 ( 피해복구비용 ) 에따라전략이적절한지여부는달라진다. 위대책은시스템에대한위협의위험을기초로하고있다. 따라서전략을선택한자체만으로시스템의위협은완화되지않는다. 궁극적으로비지니스위험관리전략의중요한요인으로전반적인위험에대해사업적영향을고려한다. 한전략이수정되기위해서는취약점이잠재적으로비지니스에미치는영향보다적을경우전략을수정할수있다. 또다른전략은일부보안통제 ( 예 : 기밀성, 무결성, 가용성 ) 기능이상실되었을경우서비스나중요비즈니스의손실이적을때는위험을감수한다. 또다른예로다른서비스제공자에게위험을전가하는방법이있다. 51
코드리뷰메트릭스 코드리뷰는소프트웨어개발프로세스를향상시킬수있는훌륭한지표이다. 여기에는상대적지표와절대적 지표등두가지유형이있다. 절대적지표는응용프로그램에서특정변수또는코드라인 (LOC) 의개수에대한참조의숫자로코드의특성을설명하는수치다. 절대측정값은이러한코드의라인수로모든것을포함하지않지만중요한척도이다. 상대적지표는직접측정할수없는속성을표현하고있으며주관적이고측정기준에서파생된문맥에의존한다. 이러한속성을측정하는데이보다확실한방법은없다. 변수가많으면테스트난이도가상승하는등, 모든숫자로표현된정보는다른지표를예측하게되거나주관적이된다. 메트릭의장점 코드리뷰의목적은취약점이발생되어악용될수있는개발오류를감지하는것이다. 또한코드리뷰는애플리케이션개발보안업무에서개발팀의진행사항을측정하는데사용할수있다. 코드리뷰는보안에대한개발이취약한분야와강한분야를정확하게파악할수있다. 개발자에게개발된솔루션내에서보안취약점의근본원인을해결할수있도록한다. 이를통해소프트웨어개발정책과지침그리고사용자자체적으로해석에대해서조사할수있다. 소통이핵심요소이다. 또한지표는코드검토자의역량, 코드리뷰과정의정확성, 코드리뷰기능의생산성, 그리고코드리뷰기능의효율성과효과를측정할수있다. 52
위그림은코드리뷰프로세스전반에걸쳐측정지표사용에대한설명이다. 개발보안지표 결함밀도 : 코드라인 (LOC) 당프로그래밍평균결함비율이다. 이것은코드품질의상위수준관점을제공하지만그이상은아니다. 결함밀도가실제적인통계를의미하지는않는다. 결함밀도는코드의사소한문제뿐만아니라심각한보안결함까지같은수준에서검출하기때문이다. 결함밀도만을사용해서는코드의보안성을정확하게판단할수없다. 코드라인 (LOC): 실행코드라인의개수이다. 주석코드와공백은포함되지않는다. 코드라인은코드의크기를측정하기위한 또다른통계이다. 이것은대략적인크기만제공할뿐정확하지않다. 코드라인수에따라서응용프로그램의 크기를추정하는것은전문가의오판이라고생각하는견해도있다! 53
기능점수 : 기능을측정하여소프트웨어크기를추정하는것이다. 특정태스크수행, 프로그래밍언어의사용또는개발 방법론의독립적인수행구문수를조합하는것이다. 위험도 : 결함밀도와마찬가지로발견된문제는위험에의해등급이매겨진다 ( 높음, 중간및낮음 ). 위험도는 [X 위험 / 코드라인 ] 또는 [Y 위험 / 기능점수 ] 값을통해개발되고있는코드의품질에대해서정확히파악할수있다. 내부애플리케이션개발정책및표준에의해정의된다 (X&Y 는높음, 중간또는낮음위험 ). 예 : 1000 라인의코드당높은위험결함 4 개 3 기능점수당중간위험결함 2 개 경로복잡도 / 복잡도와결함 / 순환복잡도 순환복잡도 (Cyclomatic Complexity) 는클래스와메소드또는전체시스템과같은코드항목에대해위험및안전성을평가기준을만들수있다. 70 년대토마스멕케이브 (Thomas McCabe) 가정의하였고계산및적용방법이쉬워유용하다. CC = 분기문의수 +1 분기노드는다음과같은명령문들이다 : If...else, Switch, Case, Catch, While, do, 기타등등... 분기노드수가증가할수록복잡도또한증가한다. 복잡한코드는불안정성하며유지보수가어렵다. 복잡한코드는더높은결함위험이있다. 순환복잡도의임계값설정 : 0-10: 안정적코드. 허용된복잡도 54
11-15: 중간위험. 더복잡함 16-20: 높은위험코드. 코드단위에대해많은분기노드. 검토진행율측정 검사율 이통계는코드리뷰를수행하는데필요한기간을산정하는데사용할수있다. 검사율은코드리뷰자가시간당 수행할수있는범위에대한비율이다. 경험에따르면시간당 250 줄이기준속도이다. 검사율은검토품질 측정의일부로사용해서는안되며단순히작업기간을결정하기위해사용해야한다. 결함검출율 이통계는측정시간당결함발견율이다. 코드검토팀이성능을재측정하는데사용할수있다. 그러나품질측정 수단으로는사용하지않는다. 일반적으로검사율이감소하면결함검출율은증가한다. 코드커버리지 코드라인의기능포인트를 % 로측정하고, 코드커버러지는검토코드의비율이다. 수동검토의경우거의 100% 에다다르지만그와달리자동검토는 80-90% 정도만해도좋은것으로간주한다. 결함수정율 발견된결함을수정하는데많은시간이소요된다. 이통계는 SDLC 를최적화하는데사용할수있다. 평균 결함율은오버타임을측정할수있으며, 프로젝트계획단계에서얼마나시간이필요한지측정가능하다. 재검토결함율 코드를재검사시더많은결함이존재할비율로, 몇가지결함이여전이존재하거나이전에발견된결함을 해결하는중에발생하는기타결함이다. 55
코드크롤링 코드크롤링은의문이있는검토대상의코드베이스를스캔하는것이다. 이것은보안취약점이있는핵심포인터를찾는것이다. 특정 API 는외부, 파일입출력또는사용자관리인터페이스를연결한다. 이는공격자가노리는핵심영역이다. 코드크롤링을통해우리는이러한영역과관련된 API 를찾는다. 또한우리는보안문제를발생할수있는비지니스로직영역을찾을필요가있지만, 일반적으로메소드명명규칙에의한맞춤형이름과직접검색이안되게하지만우리는특정주요 API 의관계로특정메소드에접근할수있다. 또한특정언어와관련된공통적인문제를찾을필요가있다 ; * 보안 * 과관련되어있지않은문제라도어떤특별한상황의경우응용프로그램의안정성 / 가용성에영향을미칠수있다. 코드리뷰를할때있을수있는또다른문제점은지적재산권을보호하기위해저작권을공지하는것이다. 코드크롤링은수동또는자동화된도구를사용하여자동화된방식으로수행할수있다. Grep 나 wingrep 와같은간단한도구를사용할수있다. 또한특정프로그래밍언어에관련된키워드를검색하는다른도구를사용해도된다. 이절에서는 Java/J2EE,.NET 및클래식 ASP 를위한코드크롤링의기능을다룬다. 또한트랜잭션분석세션에서자세히다룬다. 주요지표의검색 코드리뷰의기본은애플리케이션보안에영향을미칠수있는코드의영역을찾아서분석하는것이다. 코드리뷰는코드에대해철저하게이해하고, 어떤의도가있는지그리고어떤의미가있는지확인하며최우선적으로관심영역에대한코드베이스를조사해야한다. 코드베이스에서텍스트검색을통해 API 및기능에관련된키워드를찾을수있다. 다음은.NET 프레임워크 1.1 & 2.0 에대한가이드이다..NET 에서코드검색 첫째로텍스트검색을수행하기위해사용할수있는도구에익숙혀져야하고, 무엇을찾는지알아야한다. 이절에서우리는비쥬얼스튜디오 (VS) 와.NET 을가지고있다고가정한다. VS 는 " 파일에서찾기 " 와 Findstr 이라불리는커맨드라인도구가있다. 경험상윈도우 XP 의검색시험도구는좋지않으며, 만약사용해야할경우 SP2 가확실히더욱효과적이다. 시작하려면 "User", "Password", "Pswd", "Key", "Http" 등일반적인패턴이나키워드를찾고철저하게코드를검사해야한다. 이것은 VS 의툴인 findstring 을사용하여수행할수있다.: findstr /s /m /i /d:c:\projects\codebase\sec "http" *.*] 56
HTTP 요청문자열 외부자원에서들어오는요청은보안코드리뷰시핵심영역이다. 수신하는모든 HTTP 요청이구성, 최대및최소 길이에대한유효성이검증된데이터인지, 그리고데이터가화이트리스트파라미터범주에포함되는지 확인해야한다. 요점은이것은분석해야하고, 보안을보장하기위한핵심영역이다. request.accepttypes request.browser request.files request.headers request.httpmethod request.item request.querystring request.form request.cookies request.certificate request.rawurl request.servervariables request.url request.urlreferrer request.useragent request.userlanguages request.issecureconnection request.totalbytes request.binaryread InputStream HiddenField.Value TextBox.Text recordset HTML 출력 여기서는클라이언트로응답하는것을찾고있다. 데이터가검증되지않은채또는데이터검증없이외부입력 값을반사하는응답은반드시확인해야한다. 많은클라이언트측공격은응답검증을수행하지않아발생한다. XSS 와같은공격이이에해당한다. response.write <% = HttpUtility UrlEncode innertext innerhtml HtmlEncode SQL 및데이터베이스 데이터베이스가코드와관련있는곳을찾는것은코드리뷰시중요한일이다. 데이터베이스코드를살펴보면 응용프로그램이 SQL 인젝션에취약한지확인하는데도움이된다. 이를위해코드에 SqlParameter, 57
OleDbParameter 또는 OdbcParameter(System.Data.SqlClient) 를사용하고있는지확인하는것이다. 즉 데이터베이스에서파라미터를문자그대로처리하여실행되지않도록한다. exec sp_executesql execute sp_executesql select from Insert update delete from where delete exec sp_ execute sp_ exec xp_ execute sp_ exec @ execute @ executestatement executesql setfilter executequery GetQueryResultInXML adodb sqloledb sql server driver Server.CreateObject.Provider.Open ADODB.recordset New OleDbConnection ExecuteReader DataSource SqlCommand Microsoft.Jet SqlDataReader ExecuteReader GetString SqlDataAdapter CommandType StoredProcedure System.Data.sql 쿠키 쿠키조작은세션하이제킹 / 세션고정및매개변수조작과같은다양한애플리케이션보안공격에활용될수 있다. 쿠키기능과관련된모든코드를검사해야하며, 이를통해세션보안을수립할수있다. System.Net.Cookie HTTPOnly 58
document.cookie HTML 태그 아래의대부분의 HTML 태그는크로스사이트스크립팅 (XSS) 과같은클라이언트측공격에사용될수있다. 태그가사용되는곳과웹애플리케이션의표현및태그의사용에관련된모든데이터유효성검사는전체 문맥상에서검토하여야한다. HtmlEncode URLEncode <applet> <frameset> <embed> <frame> <html> <iframe> <style> <layer> <ilayer> <meta> <object> <body> <frame security <iframe security <img> 입력값제어 아래입력값제어는웹애플리케이션폼필드를생성하고보여주는서버클래스이다. 이를참고하면애플리케이 션으로의입력지점을찾을수있다. system.web.ui.htmlcontrols.htmlinputhidden system.web.ui.webcontrols.hiddenfield system.web.ui.webcontrols.hyperlink system.web.ui.webcontrols.textbox system.web.ui.webcontrols.label system.web.ui.webcontrols.linkbutton system.web.ui.webcontrols.listbox system.web.ui.webcontrols.checkboxlist 59
system.web.ui.webcontrols.dropdownlist WEB.CONFIG.NET 프레임워크는.config 파일에환경설정을정의한다..config 파일은텍스트기반의 XML 파일이다. 일반적으로단일시스템에여러개의.config 파일이존재할수있다. 웹애플리케이션은애플리케이션의루트디렉토리에있는 web.config 파일을참고한다. ASP.NET 애플리케이션의 web.config 는애플리케이션의운용에대한많은정보를포함하고있다. requestencoding responseencoding trace authorization compilation CustomErrors httpcookies httphandlers httpruntime sessionstate maxrequestlength debug forms protection appsettings ConfigurationSettings appsettings connectionstrings authentication mode allow deny credentials identity impersonate timeout remote global.asax 필요한경우각각의애플리케이션은자체 Global.asax 을가지고있다. Global.asax 는이벤트코드와애플리케이 션사용을위한값을설정한다. 전체애플리케이션과그에속한모든사용자가접근할수있기때문에, 애플리케 이션변수가민감한정보를포함하지않는지확인해야한다. Application_OnAuthenticateRequest Application_OnAuthorizeRequest Session_OnStart Session_OnEnd 60
로깅 로깅은정보유출의원인이될수있다. 로깅하위시스템에대한모든호출을검사하고모든민감한정보가 기록된다면이를확인하고검사해야한다. 일반적인실수로인증기능내에사용자 ID 와패스워드가결합된 기록을남기거나민감한데이터가포함된데이터베이스요청을기록한다. log4net Console.WriteLine System.Diagnostics.Debug System.Diagnostics.Trace Machine.config 특정프로그램에서는 Machine.config 의많은변수가 Web.config 에서덮어씌여질수있다는점을기억해야 한다. validaterequest enableviewstate enableviewstatemac 쓰레드와병행실행 멀티쓰레드기능을포함하는코드의위치를확인한다. 동시실행문제는보안취약점이될수있는경쟁상태가발생할수있다. 쓰레드키워드는새로운쓰레드객체에서생성된다. 민감한보안정보를가지고있는정적전역변수를사용하는코드는세션문제가발생할수있다. 정적생성자는사용하는코드는쓰레드간의문제가발생할수있다. 쓰레드해제를동기화하지않는경우동시에쓰레드해제를요청는문제를일으킬수있으며, 이는리소스해제문제가발생한다. Thread Dispose 클래스설계 61
Public( 공개 ) 과 Sealted( 봉인 ) 클래스는클래스수준의설계와관계가있다. 의도치않게파생된클래스는 봉인되어야한다. 모든클래스필드는합당한이유로 public 인지확인해야한다. 불필요한경우에는노출시키면 안된다. Public Sealed 리플렉션, 직렬화 코드는실행시동적으로생성될수있다. 외부입력에의해동적으로생성되는코드는문제를야기할수도있다. 코드에민감한데이터를포함하는경우에는직렬화할필요가없다. Serializable AllowPartiallyTrustedCallersAttribute GetObjectData StrongNameIdentityPermission StrongNameIdentity System.Reflection 예외및오류 catch 블록를통해사용자에게정보를누출하지않도록해야한다. Finally 블록이사용되는자원일경우확인해야 한다. 추적을활성화하는것은정보누출관점에서는좋은방법은아니다. 맞춤형오류가구현되었는지확인해야 한다. catch{ Finally 62
trace enabled customerrors mode 암호화 암호를사용할경우 AES 나 3DES 같이강력한것을사용해야한다. 암호키사이즈는클수록좋다. 다음과같은 사항을고려해야한다. 해쉬는어디서수행하는지? 패스워드는해쉬값으로저장하고있는지? 난수는어떻게 생성되는지? PRNG( 의사난수생성기 ) 는충분히랜덤한지? RNGCryptoServiceProvider SHA MD5 base64 xor DES RC2 System.Random Random System.Security.Cryptography 스토리지 만약민감한데이터를메모리에저장할경우다음과같이사용하는것을권장한다. SecureString ProtectedMemory 인가, ASSERT 및 REVERT 코드접근통제권한을우회하는것은좋은생각이아니다. 또한아래는관리되지않은코드호출, CLR( 공용언어 런타임 ) 와같은잠재적으로위험한권한목록이다..RequestMinimum.RequestOptional Assert Debug.Assert CodeAccessPermission ReflectionPermission.MemberAccess SecurityPermission.ControlAppDomain SecurityPermission.UnmanagedCode SecurityPermission.SkipVerification SecurityPermission.ControlEvidence SecurityPermission.SerializationFormatter SecurityPermission.ControlPrincipal 63
SecurityPermission.ControlDomainPolicy SecurityPermission.ControlPolicy 레거시메소드 printf strcpy 64
J2EE/JAVA 에서코드검색 입력과출력스트림 아래는애플리케이션으로데이터를읽는데사용하는것이다. 아래는애플리케이션으로데이터를읽을때입력 지점이될수있다. 입력지점은외부자원으로부터생길수있으며, 반드시이를조사해야한다. 이것은경로 추적 (Path Traversal) 공격또는 DoS 공격에사용될수있다. Java.io java.util.zip java.util.jar FileInputStream ObjectInputStream FilterInputStream PipedInputStream SequenceInputStream StringBufferInputStream BufferedReader ByteArrayInputStream CharArrayReader File ObjectInputStream PipedInputStream StreamTokenizer getresourceasstream java.io.filereader java.io.filewriter java.io.randomaccessfile java.io.file java.io.fileoutputstream mkdir renameto 서블릿 API 호출은파라미터, 헤더, URL 그리고쿠키변조 (Tampering), HTTP 응답쪼개기는정보유출을위한경로가될 수있다. 이와같은 HTTP 요청으로부터직접적으로얻은 API 의파라미터는엄격히검사하여야한다. javax.servlet.* getparameternames getparametervalues getparameter getparametermap getscheme getprotocol getcontenttype getservername getremoteaddr getremotehost getrealpath getlocalname getattribute getattributenames getlocaladdr getauthtype getremoteuser getcookies issecure HttpServletRequest getquerystring getheadernames getheaders getprincipal getuserprincipal isuserinrole 65
getinputstream getoutputstream getwriter addcookie addheader setheader setattribute putvalue javax.servlet.http.cookie getname getpath getdomain getcomment getmethod getpath getreader getrealpath getrequesturi getrequesturl getservername getvalue getvaluenames getrequestedsessionid 크로스사이트스크립팅 javax.servlet.servletoutputstream.print javax.servlet.jsp.jspwriter.print java.io.printwriter.print 분할응답 javax.servlet.http.httpservletresponse.sendredirect addheader, setheader 리다이렉션 sendredirect setstatus addheader, setheader SQL 및 DATABASE 코드와관련된자바데이터베이스를검색할때, 다음목록은검토되는애플리케이션의영속성계층 (persistence layer) 과관련된클래스 / 메소드를정확하게찾는데도움이된다. 66
jdbc executequery select insert update delete execute executestatement java.sql.connection.preparestatement java.sql.connection.preparecall createstatement java.sql.resultset.getstring java.sql.resultset.getobject java.sql.statement.executeupdate java.sql.statement.executequery java.sql.statement.execute java.sql.statement.addbatch SSL 종단간암호화를위한도구로써, SSL 이용하는코드를찾는다. 다음은 SSL 기능이개발된곳을찾아준다. com.sun.net.ssl SSLContext SSLSocketFactory TrustManagerFactory HttpsURLConnection KeyManagerFactory 세션관리 getsession invalidate getid 레거시상호작용 명령어인젝션공격또는 OS 인젝션공격에취약할수있다. 네이티브 OS 에연결된자바는심각한문제와 잠재적인위험으로인해모든서버에심각한문제가발생할수있다. 67
java.lang.runtime.exec java.lang.runtime.getruntime 로깅 애플리케이션에포함된아래코드를검사하면몇가지정보유출을알수있다. java.io.printstream.write log4j jlo Lumberjack MonoLog qflog just4log log4ant JDLabAgent 아키텍쳐분석 애플리케이션에서주요설계요소를찾을수있다면검색범위를좁힐수있다. 그러면구성요소와프레임워크 의알려진취약점을찾을수있다. ### Ajax XMLHTTP ### Hibernate import org.hibernate ### Struts org.apache.struts ### Castor org.exolab.castor ### Spring org.springframework ### JAXB javax.xml ### Java Server Faces (JSF) import javax.faces 68
### JMS JMS 일반적키워드 개발자들은가장중요한것은소스코드라고말한다. 아래의키워드를이용하면가능한소프트웨어취약점을 찾을수있다. Hack Kludge Bypass Steal Stolen Divert Broke Trick FIXME ToDo Password Backdoor WEB 2.0 Ajax 와자바스크립트 Ajax 에서발생할수있는자바스크립트이슈 document.write eval document.cookie window.location document.url XMLHTTP window.createrequest 69
클래식 ASP 에서코드검색 입력 Request Request.QueryString Request.Form Request.ServerVariables Query_String hidden include.inc 출력 Response.Write Response.BinaryWrite <%= 쿠키.cookies 오류처리 err. Server.GetLastError On Error Resume Next On Error GoTo 0 URL 정보 location.href location.replace method="get" 70
데이터베이스 commandtext select from update insert into delete from where exec execute.execute.open ADODB. commandtype ICommand IRowSet 세션 session.timeout session.abandon session.removeall DOS 공격방지 server.scripttimeout IsClientConnected 로깅 WriteEntry 리다이렉션 Response.AddHeader Response.AppendHeader Response.Redirect Response.Status Response.StatusCode 71
Server.Transfer Server.Execute 72
자바스트립트 / WEB 2.0 키워드와포인터 Ajax 와자바스크립트를이용해서클라이언트측에서돌아가는기능을구현할수있다. 그기능들로인해예전의보안이슈들이다시회자되고있다. 다음키워드는사용자상태와브라우저를제어하는데사용하는 API 호출에관한것이다. AJAX 및기타웹 2.0 패러다임은클라이언트측으로보안이슈를집중시켰지만서버측보안이슈도포함을하고있다. Ajax 사용및자바스크립트문제를찾는것 eval( ) document.cookie document.referrer document.attachevent document.body document.body.innerhtml document.body.innertext document.close document.create document.createelement document.execcommand document.forms[0].action document.location document.open document.url document.urlunencoded document.write document.writeln location.hash location.href location.search window.alert window.attachevent window.createrequest window.execscript window.location window.open window.navigate window.setinterval window.settimeout XMLHTTP 73
코드리뷰와 PCI DSS 소개 카드결제산업데이터보안표준 (Payment Card Industry Data Security Standard; PCI) 은 2005 년 6 월에신용카드결제처리회사에대한강제준수사항이되었다.. 자체개발한코드에대해코드리뷰하는것은표준이처음발표되었을부터요구사항이다. 이절은해당 PCI 요구사항에서준수해야할코드리뷰에관한설명이다. 코드리뷰요구사항들 PCI 표준은안전한응용프로그램개발과관련해서몇가지가더있지만여기서는코드리뷰에만초점을맞춘다. 코드리뷰에관한모든요구사항은 6 에서찾을수있다 : 보안시스템및응용프로그램을개발하고유지하고있다. 특히요구사항 6.3.7 은사용자정의코드의코드리뷰 : 6.3.7 - 잠재적인코딩취약점을찾아내기위해출시전에자체개발한코드에대한리뷰. 이요구사항은다른 PCI 요구사항을반드시고려해야한다는의미이다. 즉 6.3.5 출시전자체응용프로그램계정, 사용자 ID 및패스워드제거 6.5 OWASP 가이드라인과같이시큐어코딩에기반하여모든웹응용프로그램을개발. 소프트웨어개발 프로세스의일반적인코딩취약점예방법은다음과같다 : 6.5.1 검증되지않은입력값 6.5.2 부적절한접근통제 ( 예 : 사용자 ID 의악의적인사용 ) 6.5.3 인증과세션관리취약점 ( 계정정보와세션쿠키의사용 ) 6.5.4 크로스사이트스크립트공격 6.5.5 버퍼오버플로우 6.5.6 인젝션결함 ( 예 : SQL 인젝션 ) 74
6.5.7 부적절한오류처리 6.5.8 안전하지않은저장 6.5.9 서비스거부 6.5.10 안전하지않은구성관리 이표준은구체적인방법에대해서설명하지않지만방향을제시해준다. 어떤방법으로접근할수있도록도와 준다. 현재버전의표준 ( 작성시버전 1.1) 은요구사항 6.6 을소개했다. 이요구사항은기업들에게두가지 옵션을주었다 : 1) 모든고객의응용프로그램코드는응용프로그램보안전문조직에의해일반적인보안취약점검토 2) 웹인터페이스가있는응용프로그램앞에응용계층방화벽설치 PCI 위원회는코드리뷰를하는내부자원을포함했다. 이것으로내부코드리뷰에중점을두고, 이프로세스가 제대로수행되었는지확인할수있다. 75
기술통제검토 : 인증 소개 너는누구인가? 인증은일반적으로사용자이름및패스워드와같은자격증명을통해, 한개체가다른개체의신원을확인하는프로세스이다. 조직마다의다양한요구사항에따라, 여러가지선택가능한인증방법이있다. 인증방법이올바르게선택되지않고개발되는경우, 공격자가시스템에접근하기위해악용할수있는취약점을노출할수있다. 패스워드저장및사용자자격증명은다층보안및컴플라이언스관점에서도이슈이다. 아래절은패스워드저장및검토에대해논의한다. 취약한인증기능과관련된소스코드측면에대해논의할것입니다. 결함이있는구현또는깨진비즈니스로직이원인이될수도있다.: 인증은비공개된데이터, 민감한기능을보호하는핵심적인방어책이다. 취약한패스워드및패스워드기능 패스워드강도는사용자설정 / 패스워드생성시에시행되어야한다. 패스워드는복잡하게구성되어야한다. 새로운패스워드등록단계에서애플리케이션의백엔드 / 서버측면에서확인되어야한다. 잘못된예 패스워드가널이아닌지확인하는것으로충분하지않다. String password = request.getparameter("password"); if (password == Null) { throw InvalidPasswordException() } 좋은예 패스워드가아래규칙에적합한지확인해야한다. 1 개이상의대문자 (A-Z) 1 개이상의소문자 (a-z) 1 개이상의숫자 (0-9) 76
1 개이상의특수문자 (!" $%&...) 지정된최소길이 (8 자리 ) 지정된최대길이 ( 모든외부입력과함께 ) 연속된문자않됨 (123abcd) 1 줄에서두개이상의동일한문자안됨 (1111) HTTP 요청을받자마자, 코드에서위의규칙을찾아서사용해야한다. 규칙은복잡한정규표현식이나논리적인 자체코드구문이어야한다. if password.regex([a-z]) and password.regex([a-z]) and password.regex([0-9]) and password.regex({8-30}) and password.rexex([!" $%^&*()]) return true; else return false; 위의코드의정규표현식구문 : (?=^.{8,30}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{"":;'?/>.<,]).*$..NET 인증제어.NET 은환경설정파일에인증관련태그가있다. <authentication> 요소는응용프로그램이사용하는인증모드를구성한다. <authentication> 77
적절한인증모드는응용프로그램또는웹서비스설계방법에따라달라진다. 아래그림과같이기본 Machine.config 설정은보안 Windows 인증을기본적으로적용한다. authentication Attributes:mode="[Windows Forms Passport None]" <authentication mode="windows" /> 양식인증가이드라인. 양식인증을사용하기위해, <authentication> 요소에 mode= Forms 로설정한다. 다음, 하위 <forms> 요소를사용하여양식인증을구성한다. 다음은안전한 <forms> 인증요소환경설정을보여준다. <authentication mode="forms"> <forms loginurl="restricted\login.aspx" Login page in an SSL protected folder protection="all" requiressl="true" timeout="10" name="appnamecookie" path="/formsauth" slidingexpiration="true" > Privacy and integrity Prevents cookie being sent over http Limited session lifetime Unique per-application name and path Sliding session lifetime </forms> </authentication> 양식인증보안을향상하기위하여, 아래권장사항을사용하시기바란다. 웹사이트분할 protection= All 설정쿠키시간제한값을작게설정고정된만료기간을사용하는것을고려양식인증에 SSL 사용 SSL 을사용하지않을경우 slidingexpiration = false 설정 78
프로덕션서버에 <credentials> 요소를사용하지말것 <machinekey> 요소구성 고유쿠키이름및경로사용 클래식 ASP 페이지에서는일반적으로 DB 에대하여검증한후, 세션변수에사용자정보를포함하여수동으로 인증을수행하였으며, 아래와같이확인할수있다. Session ("UserId") = UserName Session ("Roles") = UserRoles 쿠키없는폼인증 HTTP 헤더의쿠키에있는고유 ID 와같은폼안의인증티켓은기본적으로쿠키에저장된다. ( 인증티켓은사용자가시스템에인증되었는지를기억하는데사용된다.) 상태를저장하지않는 http 프로토콜에서인증을유지하기위한다른방법. 쿠키가없는디렉티브 (directive cookieless) 로사용되는인증티켓의유형을정의할수있다. <forms> 엘리먼트의쿠키가없는값의종류 : UseCookies 항상사용하는쿠키티켓지정 UseUri 사용하지않는쿠키티켓지정 AutoDetect 기기가지원하지않으면쿠키티켓은사용되지않는다. 기기프로파일이쿠키를지원하면탐색기능을사용하여쿠키가활성화할수있다. UseDeviceProfile 정의되지않은경우기본설정됨. 기기프로파일이쿠키를지원하는경우에만쿠키기반의인증티켓을사용. 탐색기능은사용되지않는다. cookieless="useuri" : 위의 <forms> 요소에서무엇을찾을수있나? 탐색에대하여이야기할때, HTTP 헤더안의사용자에이전트디렉티브를참고하고있다. 이것은 ASP.NET 에서 쿠키가지원된다는정보를준다. 패스워드저장전략 79
패스워드저장소또한문제이다. 공격자는애플리케이션에비인가접근을통해패스워드가저장된장소에접근할수있다. 패스워드는일방향해쉬알고리즘으로저장되어야한다. 일방향기능 (SHA-256 SHA-1 MD5,..;) 은해쉬기능으로알려져있다. 일단패스워드가저정되고나면, 사람들이패스워드를읽어야할이유가없다. 인증기능은사용자가입력한패스워드의해쉬를수행하고, 저장된해쉬값과비교하는것이다. 패스워드가동일하다면, 해쉬값은동일하다. 복구될수없는패스워드해쉬값을저장하면, 평문의패스워드복구가더어렵게된다. 이것은또한, 애플리케이션관리자가다른사용자의패스워드에접근할수없으므로내부위협벡터를완화하는데도움을준다. SHA-1 해쉬가구현된자바코드예시 : import java.security.messagedigest; public byte[] gethash(string password) throws NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); byte[] input = digest.digest(password.getbytes("utf-8")); 솔트 : 단순하게해쉬된패스워드를저장하는것은이러한두개의패스워드가동일한경우동일한해쉬값이생성될가능성과생일공격 (http://en.wikipedia.org/wiki/birthday_paradox) 의문제가있다. 위문제점의해결책은솔트를이용하는것이다. 솔트는지정된길이의랜덤숫자이다. 솔트는각각의저장된입력값에따라반드시달라야한다. 솔트는해쉬된패스워드옆에평문으로저장되어야한다. import java.security.messagedigest; public byte[] gethash(string password, byte[] salt) throws NoSuchAlgorithmException { MessageDigest digest = MessageDigest.getInstance("SHA-256"); digest.reset(); 80
digest.update(salt); return digest.digest(password.getbytes("utf-8")); } 인증관련취약점 양식필드를활용하는인증과관련된많은문제가있다. 부적절한필드유효성검사로인해아래와같은문제가 일어날수있다. SQL 인젝션을위한코드리뷰 SQL 인젝션은인증기능을우회하는사용할수있으며, 심지어추후공격을위해시스템에악의적사용자를 추가할수있다. 데이터검증을위한코드리뷰 모든외부에서입력되는데이터에대해서는반드시검증되어야한다. 이것은인증필드에도해당된다. XSS 이슈를위한코드리뷰 크로스사이트스크립트는인증페이지에서 ID 도용, 피싱, 세션하이재킹공격을수행할수있다. 오류처리를위한코드리뷰 잘못되고취약한오류처리는데이터베이스구조고, 유효하거나유효하지않은사용자 ID 등과같은것을이해할 수있도록하여인증기능의내부동작을이해하는데사용될수있다. 자바를이용한해쉬 http://www.owasp.org/index.php/hashing_java 출처 http://www.owasp.org/index.php/codereview-authentication 81
기술통제검토 : 인가 소개 웹애플리케이션의광범위한계층에서인가에관한문제가존재한다. 사용자가애플리케이션계층에서애플리케이션의특정기능에대한접근권한을얻기위한사용자의기능적인가에서부터데이터베이스접근인가과영속성계층 (persistence layer) 에서최초권한과같은문제들이있다. 그렇다면, 코드리뷰시봐야할것은무엇인가? 공격관점에서가장일반적인이슈는호기심의결과나, SQL 인젝션과같은취약점이다. 예 : SQL 인젝션에취약한애플리케이션에서 system/admin 접근권한을가지고있는애플리케이션이사용하는데이터베이스계정은최소권한의데이터베이스계정보다공격에대한영향도가더크다. 사용자데이터가나뉘어져있는다중사용자데이터베이스환경에서인가는핵심요소이다. 클라이언트 / 사용자들은다른클라이언트의데이터를볼수없다 ( 수평인가 ). 인가는또한일부사용자그룹의기능을제한하는데사용될수있다. 또한슈퍼유저는일반유저가접근하지못하도록하는특별한관리기능을가질수있다. 인가는애플리케이션개발에서맞춤영역이다. 인증이성공한후로드되는사용자세션을가지고테이블을조회하도록구현될수있다. 각요청에따라백엔드 LDAP 또는데이터베이스시스템에실시간으로질의를할수있다. 잠재적으로취약한코드찾는방법 비즈니스로직오류는인가오류를찾는데있어주요영역이다. 인가체크부분은주의깊게봐야하는부분이다. 악성로직등논리적조건의경우에는검사가필요하다. if user.equals("normaluser"){ grantuser(normal_permissions); }else{ //user must be admin/super grantuser("super_persmissions); } 82
클래식 ASP 페이지에서는접근제어유효성검사나제한기능이포함된인클루드파일을이용해서인가기능이동작한다. 아래와같은문장을자주볼수있을것이다. <!--#include file="validateuser.inc"--> 추가적인이슈 : inc 확장자가인식되지않으면 ASP 코드가실행되지않으므로인클루드파일은직접호출되거나 애플리케이션기능을노출시킬수있다. 인가에취약한패턴 인가모델이단순하게권한이없는사용자에게특정기능을보여주지않는기능만있는지확인해봐야한다. 애플리케이션을크롤링해보면, 사용자 GUI 상에서보여지지않는링크들을찾을수있을것이다. 간단한 HTTP GET 요청만으로도숨겨진링크를찾을수있다. 확실히, 서버측에서도작업수행에대한권한이있는지확인해야한다. 그리고 GUI 를 숨기는 버튼과링크에의존하면안된다. 사용자수준의인가때문에클라이언트단에서버튼을숨기는것으로는사용자가버튼을통해수행하는실행작업을막을수없다 document.form.adminfunction.disabled=true; <form action="./doadminfunction.asp"> 페이지를로컬로저장하고, disable=true 를 disable=false 로변경하고 form action 을추가하면 disable 된 버튼을활성화할수있다. HotSpots 데이터베이스 : 데이터베이스에접근하는애플리케이션이사용하는계정은최소권한이적용되었는지확인하라. ASP.NET: (WEB.CONFIG) <authorization> 엘리먼트는사용자나웹클라이언트별로 ASP.NET 에서특정폴더, 페이지, 자원에대한인가및 접근을제어할수있다. 오직인가된사용자만이특정페이지에접근하거나볼수있게해야한다. <system.web> <authorization> <deny users="?"/> <-- 익명의사용자는접근거부. 사용자는반드시인증되어야함. </authorization> 83
</system.web> ASP.NET 2.0 에서 rolemanager 엘리먼트는프레임워크내에서관리역할을지원하는데사용된다. rolemanager 엘리먼트는개발자에게개발되어야할많은샘플코드를지원한다. web.config 에서활성화 (enable) 되어있는지 확인하라. <system.web>... <rolemanager enabled="true false" <providers>...</providers> </rolemanager>... </system.web> APACHE 1.3 아파치에는 httpd.conf 라는파일이있다. 이파일에서 Allow 와 Deny 로접근제어를구현할수있다. allow from address 는허용할 IP 주소나도메인이름을나타낸다. 단위는호스트수준의단위이다. Deny from 124.20.0.249 : 해당 IP 의접근을거부한다. Order 지시자 : 접근순서지정 Order Deny, Allow : 먼저모두거부하고, 특정호스트만접근가능 Deny from all Allow from owasp.org : 모두거부하고, owasp.org 만허용 아파치에서사용자수준인가를바꾸기위해서 Satisfy 지시문을이용할수있다. 좋은예 모든사용자요청에대해인가를확인한다. String action = request.getparameter("action") if (action == "dostuff"){ boolean permit = session.authtable.isauthorised(action); // check table if authoirsed to do action 84
} if (permit){ dostuff(); }else{ throw new (InvalidRequestException("Unauthorised request"); // inform user of no authorization session.invalidate(); // Kill session } 외부개체로부터모든요청을수행하는인가기능 나쁜예 사용자인가를기반으로 GUI 를만드는것이나쁜예이다. 제어기능을볼수없다면, 아무도사용하지않는다 - 가장많이발생하는오류다. 만약사용자가 URL 을가지고있다면기능이계속호출될수있다. 이것은모든 HTTP 요청에대해인가를확인하지않기때문이다. 85
관련취약점 OS 인젝션을위한코드리뷰 OS 인젝션을이용하면완벽하게인가제약사항을무시할수있다. 운영체제에접근하는것이해킹의핵심 목표이다. 애플리케이션은단순히데이터에접근하기위한통로이다. SQL 인젝션을위한코드리뷰 SQL 인젝션을이용해서인가를우회할수있다. 데이터를얻기위해시스템이해킹되는것이며애플리케이션 자체를위해해킹되지않았다. SQL 인젝션은애플리케이션의의도하지않은 대역외 채널을통해데이터에 접근할수있다. 데이터유효성검사를위한코드리뷰 모든악의근원임 : 더얘기가필요한가? :) 안전한코드환경검토 안전하지않은클래스파일과폴더는애플리케이션자체이외의다른애플리케이션을공격하는데이용될수 있다. 경쟁상태를위한코드리뷰 다중사용자, 멀티쓰레드환경에서, 오류하나로인해다른개인의세션을얻을수있으므로쓰레드의안전성은 매우중요하다. 86
기술적인통제사항검토 : 세션관리 정의 코드리뷰관점에서세션관리는애플리케이션전반에걸쳐사용자세션의생성, 갱신, 파기에초점을맞추어야 한다. 코드리뷰프로세스를통해다음을보장해야한다. 세션 ID: 인증된사용자는견고하고암호학적으로안전한세션을가진다. 세션식별자 ( 세션 ID) 는예측할수없어야 ( 랜덤해야 ) 하며, 하부프레임워크에세션식별자가생성되어야한다. 충분한엔트로피를가지는세션을만들지는오류에따라달라진다. 시도하고, 신뢰할수있는방법으로하면최선의것을만들수있다. 인가 : 애플리케이션은모든사용자의요청전에세션이유효한지확인해야한다. 사용자의세션객체는인가데이터를가지고있을수있다. 인증이성공하면, 새사용자에게세션 ID 가적용되어야한다. 어디서세션이만들어지고, 검증되지않았는지를확인할수있는코드를검토하는것은중요하다. 세션고정공격을완화하기위해, 인증후에는사용자에게유일한신규세션을할당해야한다. 인가가실패하면세션이종료되어야한다. 가능하지않은논리적조건이존재하고, 상태전이가우회되지않거나, 권한을상승시키는시도가없다면, 세션은종료되어야한다. 세션전송 : 애플리케이션은재생, 요청변조, 중간자공격과같은일반적인웹공격을회피하고막는다. 세션식별자는세션 ID 가쿼리스트링에포함되는 HTTP GET 메소드가아닌안전한방식으로사용자에게전달되어야한다. 이러한데이터 ( 쿼리문자열 ) 은웹서버로그에기록이남는다. 안전한채널로쿠키가전송되어야한다. 쿠키조작관련코드를검토해야한다. 보안플래그가설정되었는지확인하라. 이를통해비보안채널을통해쿠키가전송되는것을막을수있다. 세션생명주기 : 세션타임아웃 세션은비활동시간제한을정하거나, 어떤경우에는강제적인시간제한이있어야한다. 코드리뷰과정에이러한세션설정을검사해야한다. 설정파일이나코드자체에정의되어있을수있다. 강제시간제한은세션활동에관계없이세션을종료시킨다. 로그아웃명령은반드시브라우저를종료하는것으로끝나면안된다. 서버에서로그아웃명령을통해세션이무효화되는지코드를검토해야한다. 로그아웃요청시 ( 파라미터나 URL 의경우 ) 세션이무효화되는지반드시검토해야한다. 87
세션무효예 : import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import java.sql.*; public class dologout extends HttpServlet { ServletException,IOException public void doget(httpservletrequest req,httpservletresponse res)throws { res.setcontenttype("text/html"); HttpSession ses =req.getsession(); ses.removevalue("login"); ses.removevalue("password"); ses.invalidate(); res.sendredirect("http://company.com/servlets/login.html"); } } 관련취약점 데이터유효성코드리뷰 88
http://www.owasp.org/index.php/reviewing_code_for_data_validation XSS 코드리뷰 http://www.owasp.org/index.php/reviewing_code_for_xss_issues 인가코드리뷰 http://www.owasp.org/index.php/reviewing_code_for_authorization_issues 인증코드리뷰 http://www.owasp.org/index.php/reviewing_code_for_authentication 세션무결성코드리뷰 http://www.owasp.org/index.php/reviewing_code_for_session_integrity_issues 관련보안활동 세션관리취약점설명 다음 URL 의 OWASP 문서를참고하길바란다. http://www.owasp.org/index.php/category:session_management_vulnerability 세션관리대책설명 다음 URL 의 OWASP 문서를참고하길바란다. http://www.owasp.org/index.php/category:session_management 세션관리취약점회피방법 다음 URL 의 OWASP 개발가이드문서를참고하길바란다. http://www.owasp.org/index.php/session_management Vulnerabilities. 89
세션관리취약점시험방법 다음 URL 의 OWASP 테스트가이드문서를참고하길바란다. http://www.owasp.org/index.php/testing_for_session_management_schema 90
기술통제검토 : 입력값검증 개요 입력값검증은가장효과적인애플리케이션보안기술중하나이다. 이를통해수많은취약점들을줄일수있다. 입력값유효성검사는필드값을확인하는것이상이다. 데이터검증 시스템에대해서모든외부입력값은검증되어야한다. 검증규칙은응용프로그램에대한비즈니스요구사항에의해서결정된다. 가능하다면정확한매칭검증기가구현되어야한다. 정확한매칭을하면예상되는값을준수하는데이터만허용가능하다. 일반적으로 안전한또는화이트리스트 방법은약간취약하지만유연한적용이가능하다. 안전한항목허용방식은화이트리스트에정의된범위내의문자나 ASCII 만을허용한다. 허용범위는입력값필드의비즈니스요구사항에의해정의된다. 다른데이터검증검사방법은사후검증없이유지보수가필요한 위험한문자 로구성된블랙리스트방법이다. 단순하게인코딩된문자는 위험한 것으로여겨지는문자를애플리케이션의기능에영향을미치지않는것으로생각되는형식으로인코딩하기때문에취약할수있다. 비즈니스유효성검사 비즈니스유효성검사는비즈니스로직과관련되어있다. 비즈니스로직을수행하는코드를검토하기전에비즈니스로직에대한이해는필요하다. 비즈니스유효성검사는값범위나사용자에의해입력된업무를제한하거나, 입력을거부하는데사용될수있다. 비즈니스유효성검사에대한코드를검토시에는핵심사항을손상시킬수있는정수오버플로우와같은것을일으킬수있는반올림오류, 부동소수점오류등을검토해야한다. 정규화 정규화는다양한형태의이름을하나의표준명또는 정규 명으로변환시키는프로세스이다. 가장인기있는인코딩은 UTF-8, UTF-16 등이있다 (RFC 2279 표준문서참고 ). period/full-stop(.) 와같은단일문자도여러 ASCII 의 2E 나유니코드의 C0 AE 와같이다른방식으로표현될수있다. 문제는모든사용자입력값을인코딩하는경우필터가신중히개발되지않는다면, 웹애플리케이션필터가정확히동작하지않을수있다. 91
나쁜예 : public static void main(string[] args) { File x = new File("/cmd/" + args[1]); String abspath = x.getabsolutepath(); } 좋은예 : public static void main(string[] args) throws IOException { File x = new File("/cmd/" + args[1]); String canonicalpath = x.getcanonicalpath(); } 참조문헌 본가이드에서 데이터유효성코드리뷰 절을확인하길바란다 데이터유효성코드리뷰 http://www.owasp.org/index.php/reviewing_code_for_data_validation OWASP ESAPI 를확인하길바란다 : OWASP ESAPI 프로젝트는애플리케이션에보안통제기능을제공하는보안 API 를제공하고있다. http://www.owasp.org/index.php/esapi 92
기술통제검토 : 오류처리 오류처리는여러가지면에서중요하다. 오류로인해애플리케이션의상태나시스템의정보를사용자에게노출시킬수있다. 오류를발생시키는초기실패로인해애플리케이션이안전하지않은상태로이동할수있다. 오류처리를잘못하면공격자가반환된오류값을이용해서공격벡터를구성할수있다. 코드를개발할때대부분의오류를위해일반적오류페이지를제작하는것을권장한다. 이러한방법을통해공격자가공격시그너쳐를식별하는것을더어렵게만들수있다. 일반적인오류의의미를분석하여시스템을우회할수있는방법이있다 : 불린방식이나응답시간특성을이용하는블라인드 SQL 인젝션공격을이용하면일반적인응답을해결할수있다. 오류처리와관련된다른핵심영역은 실패안정성 을보장하는것이다. 예상된애플리케이션을안전하지않은상태로두지않는다. 자원이잠기고, 해제되어야하며, 세션은종료되어야한다. 그리고 ( 오류형태에따라 ) 계산또는비즈니스로직은멈춰야한다. 안전한애플리케이션개발에중요한요소는정보유출을방지하는것이다. 오류메시지는공격자에게애플리케이션의내부동작을잘알수있도록해준다. 오류처리코드리뷰의목적은가능한예상및예상되지않은모든오류조건하에서애플리케이션의실패안정성을보장하는것이다. 오류가발생시사용자에게어떤민감정보도제공되면안된다. 예를들어 SQL 인젝션공격은유효한오류메시지가없이는성공하기가힘들다. 오류처리를잘하면공격시도를줄이게되고, 공격자는더어렵고시간이많이소비되는블라인드 SQL 인젝션을해야하는상황이된다. 다음 3 가지이유로인해잘계획된오류 / 예외처리전략은매우중요하다. 1. 잘개발된오류처리는공격자에게애플리케이션을공격할수있는어떠한정보도제공하지않는다. 2. 적절한중앙집중화된오류전략을통해애플리케이션앞뒤단에서유지가편하고알려지지않은오류를 줄일수있다. 3. 정보가누출되면사회공학공격을야기시킨다. 일부개발언어는특정 API 호출에대한예외설정이되어있지않은경우경고를알리는기능을제공한다. 자바와 C# 이좋은예제이다. C++ 이나 C 의경우아직은이기능을안전하게제공하지않고있다. 예외처리를체크한개발언어에도여전히정보유출이이루어진다. 왜냐하면모든형태의오류를확인하지않기때문이다. 예외나오류가발생하였을때이에대한로그를남겨야한다. 오류는개발을잘못했을때발생할수도있지만, 공격의결과나, 실패에의존하는애플리케이션의다른서비스일수있다. 발생하지않아야할예외사항을확인하기위해서예외사항을발생시키는모든코드경로를확인해야한다. NullPointerException 을피하기위해서접근되는객체가널 (Null) 인지확인하여야한다. 93
가능하다면오류처리를중앙집중화한다 코드를검토할때오류 / 예외처리관점에서애플리케이션내공통점을평가하여야한다. 프레임워크에는오류처리와관련된자원을가지고있으며, 이를이용하면보안프로그래밍을지원한다. 프레임워크내이러한자원들을검토하여오류처리가정확하게구현되었는지평가해야한다. 가능하다면모든예외사항에일반적인오류페이지를사용해야한다. 이를통해공격자가내부오류상태를내부의응답을파악하지못하도록만든다. 또한자동화도구를이용한 공격이성공하지못하도록한다. 예외처리의선언 <exception key= bank.error.nowonga path= /NoWonga.jsp type= mybank.account.nocashexception /> 이것은 struts-config.xml 파일로서, 잘설정된스트럿츠환경을검토할때핵심파일이다. 자바서블릿과 JSP 처리되지않은예외사항을처리하기위해 web.xml 파일에서설정할수있다. 코드에서처리되지않은오류가 발생하였을때, 사용자를일반오류페이지로넘길수있다 : <error-page> <exception-type>unhandledexception</exception-type> <location>genericerror.jsp</location> </error-page> 또한 HTTP 404 와 HTTP 500 오류를통해서발견할수있다. <error-page> <error-code>500</error-code> <location>genericerror.jsp</location> 94
</error-page> 장애안전성 오류의종류 : 비즈니스로직조건에맞지않은결과. 비즈니스로직이포함된환경에서장애가발생. 애플리케이션이영향받는상향및하향시스템에서장애가발생하는경우. 기술적인하드웨어 / 물리적장애. 누구도고장을기대하지는않지만실제로는종종발생한다. 장애상황에서는, 애플리케이션의문을열어두면안되고, 다른방에키를두지않는것이중요하다. 요구사항에기반하여설계된논리적워크플로우과정에서사용불가능하게된커넥션풀이나, 연결할수없게된다운스트림서버등과같이프로그래밍적으로처리될수있는오류가발생할수있다. 이러한장애의영역은코드리뷰과정에서검사해야한다. 자원누출, 메모리에존재하는자원, 커넥션풀, 파일처리등이발생할가능성이있다면쓰레드실행중이나실패의경우모든자원이해제되는지확인해야된다. 세션이종료되거나무효화되는정확한영역에서도코드를검토하여야한다. 오류는비즈니스로직관점이나, 기술적인견해로도설명이안되는상황에서발생할수있다. 예 : 로그인한사용자가등록되지않은계정에접근하기위해서입력하는사용자와해당데이터는정상적으로입력될수없다. 이러한상태는악의적인활동을반영한다. 코드가어떻게방어하고, 사용자세션객체를삭제하고, 사용자에게로그인페이지를보여주는지검토해야한다. ( 세션객체는매 HTTP 요청마다검사해야한다는것을명심하라 ). 정보은닉 예외사항을빈 catch() 블록으로해결하는것은예외원인에대한감사가완벽하지않기때문에추천하지않는다. 일반적인오류메시지 모든예외사항별로설명문자열을넣을필요가있다. 시스템오류 - 나중에다시시도해주세요 같은친근한오류메시지이다. 사용자들이오류메시지를보았을때, 발생된예외사항을설명하는문자열이어야하며, 포함된스택추적을포함된예외클래스, 오류가발생한라인숫자, 클래스이름또는메소드이름등에서설명이나오면안된다. 절대로민감한정보를예외메시지에담지말아야한다. 로컬파일시스템의경로와같은정보는권한이있는정보로간주된다 ; 어떠한내부시스템정보도사용자로부터숨겨야한다. 앞에서언급하였지만, 공격자는 95
애플리케이션이나, 앱의요소들로부터개인정보를획득하기위해이러한정보를이용할수있다. 어떠한사람의 이름이나내부접속정보를오류메시지에넣으면안된다. 개인정보가노출되면사회공학공격에이용될수있다. 잠재적으로취약한코드찾기 자바자바는오류객체 ( 예외객체 ) 에대한개념을가지고있다. 이객체는자바패키지 java.lang 에있으며, Throwable 객체에서파생되었다. 비정상적인이벤트가발생했을때예외가발생한다. Throwable 객채에서파생된또다른객체는더심각한것이발생했을때발생하는 Error 객체이다. 개발자가예외메소드를사용할때정보유출이발생할수있다. 예외메소드로인해오류처리전략이부재하여사용자 UI 로정보가나오게된다. 이러한메소드다음과같다 : printstacktrace() getstacktrace() 또한중요한점은이메소드의출력값은 System.out.println(e) 와같이시스템콘솔에서출력된다는것이다. (e 는예외 (Exception) 사항이다 ). outputstream 을 PrintWriter 로리디렉션하지않도록해야한다. 일반적으로 out 이라고부른다. 예 : printstacktrace(out) 다른객체는 java.lang.system 패키지에서볼수있는 seterr() 와 System.err 필드이다..NET.NET 은 System.Exception 객체를가지고있다. 일반적으로 ApplicationException 과 SystemException 이라는자식객체가이용된다. SystemException 을런타임시수행하는것을권고하지않는다. 오류가발생하였을때시스템이나, 현재실행중인애플리케이션은자바와비슷하게오류에대한정보를가지고있는예외사항을보고해준다. 예외사항이발생하면, 다음과같이애플리케이션이나기본예외핸들러에의해서처리된다. 이 Exception 객체는다음과같이자바와유사한메소드를가지고있다. StackTrace Source Message HelpLink.NET 에서예상되지않은오류의처리나글로벌오류처리전략에대해주목할필요가있다. 이것은다양한 방법으로처리되며, 이문서에서는전부를다루지는않는다. 먼저, 처리되지않은예외사항이발생하면오류 이벤트가발생한다. 96
이것은 TemplateCotrol 클래스의일부분이다. http://msdn.microsoft.com/library/default.asp?url=/library/enus/cpref/html/frlrfsystemwebuitemplatecontrolclasserrortopic.asp.net 에서오류처리는 3 가지방법으로수행된다 web.config 파일의 customerrors section. global.asax 파일의 Application_Error aspx 나 Page_ERROR 하위에있는관련된 codebehind 페이지.NET 에서오류처리순서는다음과같다. 1. Page_Error 하위의페이지 2. global.asax 의 Application_Error 3. web.config 파일 이애플리케이션의오류전략을이해하기위해서다음의영역들을보는것을추천한다. 클래식 ASP 자바와.NET 과는다르게클래식 ASP 페이지는 try-catch 블록에서구조화된오류처리를하지않는다. 대신에 err 로불리우는특별한객체가있다. 이것은전통 ASP 페이지에서오류처리를힘들게하고, 경쟁상태나정보를유출시키는형태로오류가처리되게끔설계되는경향이있다. 또한 ASP 는 VBScript( 비주얼베이직의일부분 ) 을사용하는데 On Error GoTo label 같은것을사용할수없다. 오류처리에대한취약한패턴 Page_Error Page_Error 는서버측에서동작하는처리되는페이지수준이다. 아래는예로서, 오류정보는너무정보가많아서 좋지않은사례이다. <script language="c#" runat="server"> Sub Page_Error(Source As Object, E As EventArgs) 97
Dim message As String = "<font face=verdana color=red> <h1>" & Request.Url.ToString()& "</h1>" & "<pre><font color='red'>" & Server.GetLastError().ToString()& "</pre></font>" Response.Write(message) // display message End Sub </script> 위예제에있는텍스트는몇가지문제가있다 : 첫번째 Request.URL.ToString() 의폼에서 HTTP 요청을사용자에게다시보여준다. 여기에는데이터유효성검증이없으며 XSS 취약점이있다. 두번째로사용자가 Server.GetLastError().ToString() 통해서오류메시지와스택추적을할수있으며, 애플리케이션의내부정보를유출할수있다. Page_Error 가호출된이후에, Application_Error 가호출된다. Global.asax 오류가발생할때, Application_Error 가호출된다. 이메소드에서오류를기록하고다른페이지로이동시킬수 있다. <%@ Import Namespace="System.Diagnostics" %> <script language="c#" runat="server"> void Application_Error(Object sender, EventArgs e) { String Message = "\n\nurl: http://localhost/" + Request.Path + "\n\nmessage:\n " + Server.GetLastError().Message + "\n\nstack TRACE:\n" + Server.GetLastError().StackTrace; // Insert into Event Log EventLog Log = new EventLog(); Log.Source = LogName; Log.WriteEntry(Message, EventLogEntryType.Error); Server.Redirect(Error.htm) // this shall also clear the error } 98
</script> 위코드는 Global.asax 에있는예제이며 Application_Error 메소드이다. 오류는기록되고, 사용자는다른페이지로 이동된다. 검증되지않은파라미터는이메소드에서 Request.Path 의형태로기록될것이다. 어떠한외부로부터 오는검증되지않은입력값에대해서도로그로보이거나다시표시하지않도록주의해야한다. WEB.CONFIG Web.config 는오류를처리하기위해서사용될수있는, 전용오류태그를가지고있다. 이것은가장마지막에호출되며만약 Page_error 나 Application_error 가호출되고기능이설정되어있다면, 그기능이먼저실행된다. 앞선두처리메커니즘이리다이렉트 (Response.Redirect ) 하거나클리어 (Server.ClearError) 하지않으면, Web.config 가호출될것이고 Web.config 에정의되어있는페이지로포워드될것이다. <customerrors defaultredirect="error.html" mode="on Off RemoteOnly"> <error statuscode="statuscode" redirect="url"/> </customerrors> On 지시자는자체오류가활성화된것을의미한다. 만약 defaultredirect 지시자가명시되어있지않다면, 사용자는일반적인오류페이지를볼것이다. Off 지사자는자체오류가비활성화된것을의미한다. 이것은상세한오류를표시하는것을허가한다. RemoteOnly 지시자는자체오류페이지를원격의클라이언트에게만보이게하고, 로컬호스트에는 ASP.NET 오류가보이게한다. 이설정이기본값이다. <customerrors mode="on" defaultredirect="error.html"> <error statuscode="500" redirect="err500.aspx"/> <error statuscode="404" redirect="nothere.aspx"/> <error statuscode="403" redirect="notauthz.aspx"/> </customerrors> 오류처리모범사례 TRY & CATCH ( 자바 /.NET) 99
예외가발생하는코드는 try 블록안에있어야하고예외를처리하는코드는 catch 블록안에있다. catch 블록은키워드 catch 로시작하여예외형태와수행할행위를나열한명령문이다. 이형태는자바와.NET 에서서로유사하다. 예 : 자바 Try-Catch: public class DoStuff { public static void Main() { try { StreamReader sr = File.OpenText("stuff.txt"); Console.WriteLine("Reading line {0}", sr.readline()); } catch(exception e) { Console.WriteLine("An error occurred. Please leave to room ); logerror( Error:, e); } } }.NET try catch public void run() { while (!stop) { try { // Perform work here } catch (Throwable t) { 100
// Log the exception and continue WriteToUser( An Error has occurred, put the kettle on ); logger.log(level.severe, "Unexception exception", t); } } } 일반적으로자바의경우에는기본적인 catch(exception) 나 catch(throwable) 명령문을이용하는것보다는 특정한타입의예외사항을잡는것이가장좋은방법이다. ASP 에는 2 가지의오류처리기법이있는데, 첫번째방법은 On Error Resume Next 와함께 사용하는것이다. err 객체를 Public Function IsInteger (ByVal Number) Dim Res, tnumber Number = Trim(Number) tnumber=number On Error Resume Next ' 오류가발생하면계속실행 Number = CInt(Number) ' 만약 Number 가영숫자 (alphanumeric) 문자열형태이면, 타입불일치오류가발생 Res = (err.number = 0) On Error GoTo 0 ' 만약오류가발생하지않았다면 true 를반환 ' 만약오류가있다면실행을멈추고오류를표시 re.pattern = "^[\+\-]? *\d+$" ' 단하나의 +, - 기호와숫자들만허용 IsInteger = re.test(tnumber) And Res End Function 두번째방법은오류발생페이지에서오류핸들러를이용하는것으로, 이방법을사용하기위해서는다음 URL 를 참고하라 : http://support.microsoft.com/kb/299981 101
Dim ErrObj set ErrObj = Server.GetLastError() ' 지금부터 ErrObj 를정규 err 객체로이용하시오 자원해제및정리정돈 만약사용하는언어가 finally 메소드를가지고있다면, 사용하는것이좋다. Finally 메소드는항상호출된다. Finally 메소드를이용해서예외사항을처리하는메소드에의해서참조된자원을해제할수있다. 이부분은매우중요하다. 예를들어, 한메소드가컨넥션풀에서데이터베이스에연결한후, finally 메소드가없는상태에서예외가발생한다면, 연결객체는일정시간동안풀로 ( 타임아웃이될때까지는 ) 리턴되지않는다. 이로인해연결풀이고갈될수있다. Finally() 는아무런예외사항이없더라도호출된다. try { System.out.println("Entering try statement"); out = new PrintWriter(new FileWriter("OutFile.txt")); //Do Stuff. } catch (Exception e) { System.err.println("Error occurred! ); } catch (IOException e) { System.err.println("Input exception "); } finally { if (out!= null) { out.close(); // RELEASE RESOURCES } } 시스템자원을해제하기위해 finally() 를사용하는 Java 예제 102
클래식 ASP 클래식 ASP 페이지의경우, 하나의함수에있는모든크리링을감싸고, "On Error Resume Next" 이후에그 함수를오류처리명령문에서호출할것을추천한다. 중앙집중식예외처리 ( 스트럿츠사례 ) 일관된오류보고를위한인프라를구축하는것이오류처리보다더힘들다. 스트럿츠는보고되는오류메시지의스택을관리하기위한 ActionMessages 와 ActionErrors 클래스를제공한다. 이두클래스는사용자에게오류메시지를표시하기위한 <html: error> 와같은 JSP 태그와함께사용될수있다. 심각도가다른메시지를다른방법 ( 오류, 경고, 또는정보등 ) 으로보고하기위해서는다음작업이요구된다. 1. 적절한심각도에해당오류를등록, 초기화한다. 2. 이런메시지를확인하고, 일관된방법으로보여준다. 스트럿츠의 ActionErrors 클래스는쉽게오류처리를해준다 : ActionErrors errors = new ActionErrors() errors.add("fatal", new ActionError("...")); errors.add("error", new ActionError("...")); errors.add("warning", new ActionError("...")); errors.add("information", new ActionError("...")); saveerrors(request,errors); // Important to do this 오류를추가하였기때문에 HTML 페이지내태그를이용하여오류를표시한다. <logic:messagepresent property="error"> <html:messages property="error" id="errmsg" > <bean:write name="errmsg"/> </html:messages> </logic:messagepresent > 103
클래식 ASP ASP 페이지를위해서는 IIS 설정을해야한다. 다음링크를참조하라. http://support.microsoft.com/kb/299981 104
기술통제검토 : 안전한애플리케이션배치 코드를받았을때또한가지중요한점은배치레이아웃에서의코드와제품 (Production) 화코드가동일한지확인하는것이다. 잘짜여진코드를작성하는것도중요하지만, 이것을애플리케이션서버상의보호되지않는폴더에배치하는것은좋은생각이아니다. 공격자들또한코드리뷰를하며, 목표하는애플리케이션에대해코드리뷰이상의작업을수행한다는것을알아야한다코드리뷰외에도, 웹애플리케이션이전체적으로안전한환경에서배포되었는지반드시확인해야한다. 코드자체가아무리안전하더라도코드가배포된환경이안전하지않다면소용이없다. 환경내에서자원에대해직접접근하는것은반드시통제되어야한다. 환경설정파일, 디렉토리나자원등인증이필요한부분은호스트상에서보안이이루어져야하며, 이런자원에대해서는직접접근을허용하면안된다. 예 : Google 의경우 http://www.google.com/search?q=%0d%0aintitle%3aindex.of+web-inf 이목록들은 WebSphere, Tomcat 그리고다른애플리케이션서버들의 Web-inf 디렉토리를보여준다. WEB-INF 디렉토리트리는웹애플리케이션클래스들, 프리-컴파일된 (pre-compliled) JSP 파일들, 서버측라이브러리들, 세션정보그리고 web.xml 과 webapp.properties 와같은파일들을갖고있다. 그러므로코드베이스가제품화된상태가동일한지확인해야한다. 안전한코드환경 을갖고있는지확인하는것도애플리케이션보안코드검사에서매우중요한부분이다. 코드자체가공격으로부터 방탄조끼 (bullet proof) 를입고있다하더라도, 코드에대해서사용자접근이허용된다면다른문제들이생길수있다. 코드리뷰는개발자만하는것이아니라, 공격자들도열심히한다는것을명심해야한다. 사용자에게유일하게보여지는부분은백엔드서버로부터수신된 HTML 상태로브라우저상에보여지는정도여야한다. 애플리케이션의엄격한환경뿐만아니라백엔드서버로나가는그어떤요청도허락되거나보여져서는안된다. 다시말해, 명백히허용된것이아니면모두거절한다 고생각하면된다. 예 : Tomcat web.xml 의디렉토리인덱싱예방하기위한예 <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.defaultservlet</servlet-class> 105
<init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <init-param> <param-name>readonly</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> 따라서모든디렉토리에대한접근거부를설정하기위해아래와같이추가한다. <Directory /> Order Deny,Allow Deny from All </Directory> 그리고접근을요청하는디렉토리들에대해아래내용을덮어씌운다. 106
또한아파치 HTTP 서버의경우 WEB-INF 와 META-INF 와같은디렉토리들을보호하기위해서는 httpd.conf ( 아파치웹서버의메인설정파일 ) 에다음내용을추가하여야한다. <Directory /usr/users/*/public_html> Order Deny,Allow Allow from all </Directory> <Directory /usr/local/httpd> Order Deny,Allow Allow from all </Directory> 아파치서버의경우, 디렉토리와하위디렉토리에대한권한을설정하려면.htaccess 파일을추가한다..htaccess 파일자체를보호하기위해서는아래를추가한다. <Files.htaccess> order allow,deny deny from all </Files> 디렉토리인덱싱을막기위해서는.htaccess 파일에다음의설정을추가한다 : IndexIgnore* * 는모든파일을인덱싱으로부터막는와일드카드이다. JSP 페이지보호하기 스트럿츠프레임워크를사용할경우, 어떤 JSP 페이지라도사용자가직접접근하는것은바람직하지않다. 요청 프로세서를거치지않고 JSP 에직접접근하게되면, 공격자들이 JSP 상서버측코드를볼수있다. 초기페이지가 107
HTML 문서이면일단브라우저의 HTTP GET 이이페이지를요청하는데, 그다음단계의모든페이지는반드시 프레임워크를거쳐야한다. Web.xml 파일에다음내용을추가하여사용자가 JSP 페이지로직접접근하는것을방지하도록한다. <web-app>... <security-constraint> <web-resource-collection> <web-resource-name>no_access</web-resource-name> <url-pattern>*.jsp</url-pattern> </web-resource-collection> <auth-constraint/> </security-constraint>... </web-app> Web.xml 에위의설정을이용하면 JSP 페이지에직접접근하는 HTTP 요청이실패하게된다. ASP 페이지보호하기 클래식 ASP 페이지의경우설정파일을이용하여이와같은방어대책을설정할수있는방법이없다. 대신환경 파일설정은오직 IIS 콘솔을통해서만가능하며, 본문서에서는다루지않는다. 108
개발환경전체환경을검토할때에는디렉토리안에개발과정에서나온결과물이포함되었는지여부를반드시확인해야한다. 이런파일들은어떤방식으로도참조되어있지않기때문에애플리케이션서버는이파일들을보호하지못한다..bak,.old,.tmp 등의파일은소스코드를포함하고있을지모르기때문에반드시제거해야한다. 소스코드는제품디렉토리에들어가서는안된다. 대부분의경우컴파일된클래스파일이면충분하다. 모든소스코드는제거하고오직 실행할수있는 것들만남겨야한다. 개발도구역시제품환경에남아있으면안된다. 예를들어 Java 애플리케이션이작동하는데 JRE (Java Runtime Environment) 만필요하지, JDK (Java Development Kit) 는필요없다. 모든소스코드와설정파일상에서시험코드와디버그코드도제거해야한다. 심지어주석도예방차원에서제거해야한다. 시험코드는애플리케이션작업흐름을우회하는백도어경로를포함할수있으며, 최악의경우유효한인증데이터나계정정보를포함할수도있다. 코드에대한주석이나개발에사용된 IDE 나기술에관련된메타태그도제거해야한다. 어떤주석들은코드버그나포인터에관련된중요한정보를누설할수있다. 이는 JSP 나 ASP 파일처럼서버사이드코드에서더욱중요하다. 저작권과크리덴셜선언문은모든파일의상단에위치해야한다. 이를통해누가어떤코드를소유하고있는지에대한혼란을줄일수있다. 사소한일처럼보이겠지만, 코드의주인이누구인지밝히는것은중요한일이다. 요약하자면, 코드리뷰란단순히코드만보는것이아니라애플리케이션서버의설정도보는것이다. 작업하려는서버에대해지식을쌓는것이중요하며, 관련정보는인터넷에서쉽게찾을수있다. 109
기술통제검토 : 암호제어 소개 세상에는두종류의암호기술 (Cryptocraphy) 이존재한다. 첫째는당신의여동생이당신파일을보는것을막는암호이고, 둘째는주요정부당국이당신파일을보는것을막는암호이다 [1]. 개발자는애플리케이션이어떤종류의암호기술을사용할지를결정해야한다. 암호기법은데이터보안을제공하고 ( 암호화기반 ), 데이터무결성을규정하며 (Hasing/Digesting 기반 ), 데이터부인방지 ( 전자서명기반 ) 기능을제공한다. 따라서, 이세가지암호화프로세스를포함하는안전한코딩을하기위해서는강력한키사이즈를가진표준암호화보안알고리즘사용원칙을준수하여야한다. 비표준암호화알고리즘을사용하는것, 사용자에의해수정된알고리즘을구현 ( 표준및비표준 ) 하는것, DES 처럼암호학적으로안전하지않은표준알고리즘의사용하는것, 안전하지않은키를구현하는것은애플리케이션의전체보안을취약하게만들수있다. 이와같은방법을사용하면시중에알려진암호분석도구나기술을통해중요한데이터가해독될수있다. 관련보안활동 암호가이드 https://www.owasp.org/index.php/guide_to_cryptography 자바암호확장사용하기 https://www.owasp.org/index.php/using_the_java_cryptographic_extensions 표준암호라이브러리의사용일반적으로암호알고리즘및라이브러리를직접개발하지않는것을권장한다. 그이유는알고리즘을개발할때각그룹별, 조직별, 개인별차이가너무크며, 각소프트웨어나하드웨어상에서암호구현에도차이또한크기때문이다. 110
.NET 및 C/C++ (WIN32).NET 코드의경우, System.Security.Cryptography 에있는클래스라이브러리와프로그램이사용되어야한다 [2]..NET 내네임스페이스의목적은암호에대한전문적지식없이도쓸수있는몇가지래퍼를제공하는것이다. Win32 플랫폼에서실행되는 "C/C++" 코드의경우에는 CryptoAPI 를사용할것을권장한다 [2]. CryptoAPI 는최근윈도우비스타대체버전이발표되기이전부터비주얼 C++ 개발자툴킷에서제공하고있다. 최근의 CtypoAPI 는앞으로레거시애플리케이션이될것들에대한오리지날벤치마크를제공한다. 클래식 ASP 클래식 ASP 페이지는암호기능에직접접근할수없으므로, 유일한방법은비쥬얼 C++ 나비쥬얼베이직상에서 COM 래퍼를만들고 DPAPI 나 CryptoAPI 로호출하도록구현하고, 그다음에 Server.CreateObject 방법을이용하여 ASP 페이지로부터호출하는것이다. 자바 JCE (Java Cryptography Extension)[5] 는 Java 2 SDK 에서옵션패키지로소개된이후, J2SE 1.4 나이후버전에는포함되어있다. 자바코드구현할때는 JCE 를제공하는라이브러리를사용할것을권장한다. Sun 은암호서비스제공로활동하고, JCE 의클린룸구현을제공하는업체목록을제공하고있다 [6]. 암호기법의취약패턴사례 소스코드내강력한암호기술을구현하는안전한방법중하나는 DPAPI(Microsoft Data Protection API)[4] 나 JCE[5] 를이용하여 FIPS(Federal Information Processing Standards, 미연방정보처리표준규정 )[7] 를준수한알고리즘을구현하는것이다. 암호코드전략수립시다음내용을확인하여야한다. 표준알고리즘 (Standard Algorithms) 강력한알고리즘 (Strong Algorithms) 강력한키사이즈 (Strong Key Sizes) 부가적으로, 애플리케이션이관할하는모든민감한데이터를확인해야하고암호화를적용되어야한다. 이는 사용자의민감정보, 환경설정데이터등이포함된다. 특히, 암호화코드관련아래이슈들을확인해야한다..NET MSDN 라이브러리의 Security Practices:.NET Framework 2.0 Security Practices at a Glance 암호예제확인 1. DPAPI (Data Protection API) 가사용되었는지확인 111
2. 독자적인알고리즘이사용되지않았는지검증 3. PRNG(Pseudo-Random Number Generator, 의사난수생성기 ) 를위한 RNGCryptoServiceProvider class 사용여부확인 4. 키길이가최소한 128 비트이상인지검증 클래식 ASP ASP 는암호기능에직접접근이불가능하므로 COM 래퍼에대한아래사항을확인한다. 1. COM 객체내부에 DPAPI (Data Protection API) 가사용되었는지확인 2. 독자적인알고리즘이사용되지않았는지검증 3. PRNG 를위한 RNGCryptoServiceProvider 클래스사용여부확인 4. 키길이가최소한 128 비트이상인지검증 Java 1. JCE 가사용되었는지확인 2. 독자적인알고리즘이사용되지않았는지검증 3. PRNG 를위한 SecureRandom 클래스사용여부확인 4. 키길이가최소한 128 비트이상인지검증 나쁜사례 : 취약한암호화알고리즘의사용 다음알고리즘은암호학적으로안전하지않다 : DES, SHA-0. 아래내용은 DES 암호구현을보여준다. (Using the Java Cryptographic Extensions 에서확인가능 ) package org.owasp.crypto; import javax.crypto.keygenerator; import javax.crypto.secretkey; 112
import javax.crypto.cipher; import java.security.nosuchalgorithmexception; import java.security.invalidkeyexception; import java.security.invalidalgorithmparameterexception; import javax.crypto.nosuchpaddingexception; import javax.crypto.badpaddingexception; import javax.crypto.illegalblocksizeexception; import sun.misc.base64encoder; /** * @author Joe Prasanna Kumar * 본프로그램은암호화기능을제공한다. * 1. DES 를이용한암호화 * 2. DES 를이용한복호화 * * SUNJce provider 가다음의 DES 암호화모드를지원한다. * 1. ECB (Electronic code Book) 모든평문블록이각자암호화됨 * 2. CBC (Cipher Block Chaining) 모든평문블록이이전암호화된블록과 XOR 연산이됨 * 3. PCBC (Propogating Cipher Block Chaining) * 4. CFB (Cipher Feedback Mode) - 이전에암호화되어진암호문블록이현재의평문블록과 XOR 연산되어현재의암호화된블록으로생산됨 * 5. OFB (Output Feedback Mode) - * * 고수준알고리즘 : * 1. DES 키생성 key * 2. 암호문생성 ( 코드와패킹명세 ) * 3. 암호화 : 암호화를위한암호문초기화 * 4. 복호화 : 복호화를위한암호문초기화 * * 패딩추가 : * 고정된 n 크기의데이터블록이블록암호연산이됨 * 데이터는항상 n 의배수크기로결정되지않기때문에, 나머지비어있는비트를채워넣음 * PKCS#5 패딩기법이본프로그램에서사용됨. * */ 113
public class DES { public static void main(string[] args) { String strdatatoencrypt = new String(); String strciphertext = new String(); String strdecryptedtext = new String(); try{ /** * Step 1. Generate a DES key using KeyGenerator * */ KeyGenerator keygen = KeyGenerator.getInstance("DES"); SecretKey secretkey = keygen.generatekey(); /** * Step2. Create a Cipher by specifying the following parameters * a. Algorithm name - here it is DES * b. Mode - here it is CBC * c. Padding - PKCS5Padding */ Cipher descipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); /** * Step 3. Initialize the Cipher for Encryption */ descipher.init(cipher.encrypt_mode,secretkey); /** * Step 4. Encrypt the Data * 1. Declare / Initialize the Data. Here the data is of type String * 2. Convert the Input Text to Bytes * 3. Encrypt the bytes using dofinal method 114
*/ strdatatoencrypt = "Hello World of Encryption using DES "; byte[] bytedatatoencrypt = strdatatoencrypt.getbytes(); byte[] byteciphertext = descipher.dofinal(bytedatatoencrypt); strciphertext = new BASE64Encoder().encode(byteCipherText); System.out.println("Cipher Text generated using DES with CBC mode and PKCS5 Padding is " +strciphertext); /** * Step 5. Decrypt the Data * 1. Initialize the Cipher for Decryption * 2. Decrypt the cipher bytes using dofinal method */ descipher.init(cipher.decrypt_mode,secretkey,descipher.getparameters()); //descipher.init(cipher.decrypt_mode,secretkey); byte[] bytedecryptedtext = descipher.dofinal(byteciphertext); strdecryptedtext = new String(byteDecryptedText); System.out.println(" Decrypted Text message is " +strdecryptedtext); } catch (NoSuchAlgorithmException nosuchalgo) { System.out.println(" No Such Algorithm exists " + nosuchalgo); } catch (NoSuchPaddingException nosuchpad) { System.out.println(" No Such Padding exists " + nosuchpad); } catch (InvalidKeyException invalidkey) { System.out.println(" Invalid Key " + invalidkey); } catch (BadPaddingException badpadding) { 115
} System.out.println(" Bad Padding " + badpadding); catch (IllegalBlockSizeException illegalblocksize) { System.out.println(" Illegal Block Size " + illegalblocksize); } } catch (InvalidAlgorithmParameterException invalidparam) { System.out.println(" Invalid Parameter " + invalidparam); } } 암호화의좋은패턴사례 모범사례 : 강력한엔트로피사용 아래소스코드는강력한엔트로피를사용하는안전한키생성을보여준다 (Using the Java Cryptographic Extensions 에서확인가능 ): package org.owasp.java.crypto; import java.security.securerandom; import java.security.nosuchalgorithmexception; import sun.misc.base64encoder; /** * @author Joe Prasanna Kumar * This program provides the functionality for Generating a Secure Random Number. 116
* * There are 2 ways to generate a Random number through SecureRandom. * 1. By calling nextbytes method to generate Random Bytes * 2. Using setseed(byte[]) to reseed a Random object * */ public class SecureRandomGen { /** @param args */ public static void main(string[] args) { try { // Initialize a secure random number generator SecureRandom securerandom = SecureRandom.getInstance("SHA1PRNG"); // Method 1 - Calling nextbytes method to generate Random Bytes byte[] bytes = new byte[512]; securerandom.nextbytes(bytes); // Printing the SecureRandom number by calling securerandom.nextdouble() System.out.println(" Secure Random # generated by calling nextbytes() is " + securerandom.nextdouble()); // Method 2 - Using setseed(byte[]) to reseed a Random object int seedbytecount = 10; byte[] seed = securerandom.generateseed(seedbytecount); // TBR System.out.println(" Seed value is " + new BASE64Encoder().encode(seed)); 117
securerandom.setseed(seed); System.out.println(" Secure Random # generated using setseed(byte[]) is " + securerandom.nextdouble()); } catch (NoSuchAlgorithmException nosuchalgo) { System.out.println(" No Such Algorithm exists " + nosuchalgo); } } } 모범사례 : 강력한알로리즘사용 아래는 AES 구현한것을보여준다 (Using the Java Cryptographic Extensions 에서확인가능 ): package org.owasp.java.crypto; import javax.crypto.keygenerator; import javax.crypto.secretkey; import javax.crypto.cipher; import java.security.nosuchalgorithmexception; import java.security.invalidkeyexception; import java.security.invalidalgorithmparameterexception; import javax.crypto.nosuchpaddingexception; 118
import javax.crypto.badpaddingexception; import javax.crypto.illegalblocksizeexception; import sun.misc.base64encoder; /** * @author Joe Prasanna Kumar * 본프로그램은암호화기능을제공합니다. * 1. AES 를사용하여암호화 * 2. AES 를사용하여복호화 * High Level Algorithm : * 1. AES key 생성 ( 이단계에키사이즈가결정됨 ) * 2. Cipher 생성 * 3. To Encrypt : 암호화를위해서 Cipher 초기화 * 4. To Decrypt : 복호화를위해서 Cipher 초기화 */ public class AES { public static void main(string[] args) { String strdatatoencrypt = new String(); String strciphertext = new String(); String strdecryptedtext = new String(); try{ /** 119
* Step 1. KeyGenerator 를사용해 AES key 생성 * 키사이즈를 128 로초기화 */ KeyGenerator keygen = KeyGenerator.getInstance("AES"); keygen.init(128); SecretKey secretkey = keygen.generatekey(); /** Step 2. 다음의파라미터를이용하여 Cipher 생성 *a. 알고리즘이름 - AES */ Cipher aescipher = Cipher.getInstance("AES"); /** * *Step 3. 암호화를위해서 Cipher 초기화 */ aescipher.init(cipher.encrypt_mode,secretkey); /** * Step 4. 데이터암호화 *1. 데이터선언및초기화 이단계에서는아직데이터는문자열임. *2. 입력받은텍스트를바이트로바꿈. *3. dofinal 메소드를사용해서암호화함. */ */ strdatatoencrypt = "Hello World of Encryption using AES "; byte[] bytedatatoencrypt = strdatatoencrypt.getbytes(); byte[] byteciphertext = aescipher.dofinal(bytedatatoencrypt); strciphertext = new BASE64Encoder().encode(byteCipherText); System.out.println("Cipher Text generated using AES is " +strciphertext); 120
/** * Step 5. 데이터복호화 *1. 복호화를위해서 Cipher 초기화함. *2. dofinal 메소드를이용해암호화된바이트들을복호화함. */ aescipher.init(cipher.decrypt_mode,secretkey,aescipher.getparameters()); byte[] bytedecryptedtext = aescipher.dofinal(byteciphertext); strdecryptedtext = new String(byteDecryptedText); System.out.println(" Decrypted Text message is " +strdecryptedtext); } catch (NoSuchAlgorithmException nosuchalgo) { System.out.println(" No Such Algorithm exists " + nosuchalgo); } catch (NoSuchPaddingException nosuchpad) { System.out.println(" No Such Padding exists " + nosuchpad); } catch (InvalidKeyException invalidkey) { System.out.println(" Invalid Key " + invalidkey); } 121
catch (BadPaddingException badpadding) { System.out.println(" Bad Padding " + badpadding); } catch (IllegalBlockSizeException illegalblocksize) { System.out.println(" Illegal Block Size " + illegalblocksize); } catch (InvalidAlgorithmParameterException invalidparam) { System.out.println(" Invalid Parameter " + invalidparam); } } } 암호법및규제몇몇국가에서는암호를법적으로금지하기도한다. 따라서, 지역에따라암호기능이있는애플리케이션을배치또는사용하는것이영향을받을수있다. 다음의암호관련법조사내용이각국가별암호화현황을개괄할수있는정보를제공하고있다 [8]. 설계및구현 스펙정의 암호프로세스와알고리즘을구현하는모든코드는일련의스펙에따라검토해야한다. 이는소프트웨어가 충족해야할적정한보안수준을정하고, 암호화사용에대한측도를제공하기위해서이다. 122
코드품질수준 작성하거나사용하는암호코드는최고수준으로구현되어야한다. 이단계에는단순성, 검증, 단위테스팅과 모듈화가포함된다. 부채널과프로토콜공격 알고리즘은본래정적이기때문에프로토콜을구성하는통신매개체를통해서전달된다. 그러므로타임아웃에 관련된이슈들, 어떻게메세지가수신되고어떤채널을통해전달되는지등을고려해야한다. 참조 [1] Bruce Schneier, Applied Cryptography, John Wiley & Sons, 2nd edition, 1996. [2] Michael Howard, Steve Lipner, The Security Development Lifecycle, 2006, pp. 251-258 [3].NET Framework Developer's Guide, Cryptographic Services, http://msdn2.microsoft.com/en-us/library/93bskf9z.aspx [4] Microsoft Developer Network, Windows Data Protection, http://msdn2.microsoft.com/en-us/library/ms995355.aspx [5] Sun Developer Network, Java Cryptography Extension, http://java.sun.com/products/jce/ [6] Sun Developer Network, Cryptographic Service Providers and Clean Room Implementations, http://java.sun.com/products/jce/jce122_providers.html [7] Federal Information Processing Standards, http://csrc.nist.gov/publications/fips/ [8] Bert-Jaap Koops, Crypto Law Survey, 2007, http://rechten.uvt.nl/koops/cryptolaw/ 123
버퍼오퍼런과오버플로우를위한코드리뷰 버퍼 버퍼란정보를저장하기위해예비된연속메모리공간을별도로설정해놓은영역을의미한다. 예 : 어떤프로그램은당신이쇼핑장바구니에무엇을담는지또는이전에어떤것을담아두었는지를기억하고 있다. 이러한정보들을버퍼내의메모리에저장한다. 관련보안활동 버퍼오버플로우에대한설명 버퍼오버플로우공격에대한 OWASP 내용참조 http://www.owasp.org/index.php/buffer_overflow_attack 버퍼오버플로우취약성에대한 OWASP 내용참조 http://www.owasp.org/index.php/buffer_overflow 버퍼오버플로우취약성을막는방법 버퍼오버플로우취약성을막기위한방법에대한 OWASP 개발안내서참조 버퍼오버플로우취약성테스트방법 버퍼오버플로우취약성테스트방법에대한 OWASP 테스트안내서참조 취약가능한코드확인방법 버퍼오버플로우관점에서취약한코드를찾을때, 다음과같은특정시그너쳐를찾아봐야한다. 배열 : int x[20]; int y[20][5]; int x[20][5][3]; 포맷스트링 : printf(),fprintf(), sprintf(), snprintf(). 124
%x, %s, %n, %d, %u, %c, %f 오버플로우 strcpy (), strcat (), sprintf (), vsprintf () 버퍼오버플로우에취약한패턴 바닐라 (Vanilla) 버퍼오버플로우 : 예 : 한주의요일 (7) 을추적하는프로그램이있다. 프로그래머는컴퓨터에 7 개숫자의공간을저장하도록한다. 이것은버퍼의예이다, 그러나, 8 개의숫자를추가하려고할때, 어떤일이발생하는가? C 와 C++ 와같은언어는경계검사 (bounds checking) 를수행하지않으므로, 프로그램이이언어로작성된경우, 여덟번째데이터는메모리에다음프로그램의프로그램공간에덮어쓰이게되어, 데이터가손상된다. 이렇게하면, 프로그램이충돌하게되거나, 오버플로우페이로드가실제코드일때, 오버플로우가악성코드가실행될수있다. void copydata(char *userid) { char smallbuffer[10]; // size of 10 strcpy(smallbuffer, userid); } int main(int argc, char *argv[]) { char *userid = "01234567890"; // Payload of 11 copydata (userid); // this shall cause a buffer overload } 버퍼오버플로우는의도한것보다더많은코드를버퍼에채우면서발생한다. 125
포맷스트링 포맷함수는 ANSI C 규격내에포함된함수이다. 이함수는원시 C 데이터형식을사람이읽을수있는형태로변환할수있다. 거의모든 C 프로그램에서이함수를사용하여정보를출력하고오류메시지를인쇄하거나문자열을처리할수있다. 일부매개변수형식 : %x hexadecimal (unsigned int) %s string ((const) (unsigned) char *) %n number of bytes written so far, (* int) %d decimal (int) %u unsigned decimal (unsigned int) 예 : printf ("Hello: %s\n", a273150); 이경우, % 로매개변수 (a273150) 를문자열로인쇄하도록한다. 포맷함수에포맷문자열을공급하여포맷문자열의동작을제어할수있다. 입력값을문자열형식으로입력하면애플리케이션이의도하지않은동작을수행한다. 애플리케이션이정확하게동작하게하려면어떻게해야할까? 애플리케이션충돌 : printf (User_Input); 만약입력으로 %x( 부호없는 16 진수정수 ) 를제공하는경우, printf 함수는문자열형식과관련된정수를찾게 되지만, 인수가존재하지않는다. 컴파일시에는이러한것을찾을수없다. 실행과정에서이러한문제가나타난다. 스택검토 : printf 함수가찾는인수내의모든 % 에대해스택에관련된값이존재한다고가정한다. 이러한방식으로함수는 스택아래로계속하여스택에서대응하는값을읽고사용자에게그값을출력한다. 다음과같은문자열형식을사용하여일부무효포인터에접근할수있다. 126
printf ("%s%s%s%s%s%s%s%s%s%s%s%s"); printf() 내의 %n 지시어를사용하는것은좋지않다. 이지시어는 int* 를취하고, 그위치까지바이트수를쓰게된다. 이러한취약가능성에대해어느부분을조사할것인가? 이러한문제는주로 printf() 함수계열인 printf(), fprintf(), sprintf(), snprintf() 에서주로발생한다. syslog() ( 시스템로그정보기록 ) 및 setproctitle(const char *fmt,...) ( 프로세스식별자정보를디스플레이하기위해사용되는문자열설정 ) 에서도가능하다. 정수오버플로우 include <stdio.h> int main(void){ int val; val = 0x7fffffff; /* 2147483647*/ printf("val = %d (0x%x)\n", val, val); printf("val + 1 = %d (0x%x)\n", val + 1, val + 1); /*Overflow the int*/ return 0; } 0x7fffffff 를바이너리로표현하면 1111111111111111111111111111111 이며, 이정수는부호가있는긴정수를보유할수있는최고크기의값으로초기화된다. 여기서 0x7fffffff 의 16 진수값에 1 을더하게되면, 정수의값이오버플로우되어음수 (0x7fffffffffff + 1 = 0x80000000) 로된다. 10 진수에서이것은 (-2147483648) 이다. 이로인해발생하게되는문제를생각해보자. 컴파일러는이러한것을검출하지못하며, 애플리케이션은이러한문제를인식하지못한다. 비교시연산시또는부호가있는정수를부호가없는정수와비교할때이러한문제가발생하게된다. 예 : int myarray[100]; 127
int fillarray(int v1, int v2){ if(v2 > sizeof(myarray) / sizeof(int)){ return -1; /* Too Big!! */ } myarray [v2] = v1; return 0; } 여기서 v2 가큰음수인경우, if 조건이충족되어야한다. 이조건은 v2 가배열크기보다큰지를검사한다. myarray[v2] = v1 라인은 v1 값을배열경계밖의위치에할당하여예상하지못한결과를초래하게된다. 버퍼오버플로우를방지하기위한패턴및절차 : 예 : void copydata(char *userid) { char smallbuffer[10]; // size of 10 strncpy(smallbuffer, userid, 10); // only copy first 10 elements smallbuffer[9] = 0; // Make sure it is terminated. } int main(int argc, char *argv[]) { char *userid = "01234567890"; // Payload of 11 copydata (userid); // this shall cause a buffer overload } 위의코드는복사함수가지정된길이인 10 을사용하기때문에버퍼오버플로우에취약하지않다. 128
strcpy(), strcat(), sprintf() 및 vsprintf() 와같은 C 라이브러리함수는널종료문자열에의해범위검사를수행하지않는다. gets() 함수는새로운줄의종료또는파일끝 (EOF : End of File) 까지 stdin 에서입력을판단하는또다른함수이다. scanf() 함수패밀리도버퍼오버플로우가발생할수있다. strncpy(), strncat(), snprintf() 및 fgets() 사용할때는최대문자열길이를지정하여버퍼오버플로우문제를완화할수있다. 세부사항은약간다르므로관련사항을이해해야한다. 버퍼에기록하기전에항상배열범위를확인해야한다. 마이크로소프트 C 런타임은접미사가 _s 인추가적인함수버전을제공한다 (strcpy_s, strcat_s, sprintf_s). 이러한 함수는오류상황을추가적으로검사하며, 장애발생시오류처리기를호출한다. (CRT 보안강화참조 ) http://msdn2.microsoft.com/en-us/library/8ef0s5kh(vs.80).aspx.net 및자바.NET 프레임워크의 C# 또는 C++ 코드는관리되는경우버퍼오버플로우에내성을가지고있다. 관리되는코드는마이크로소프트의.NET 가상머신에서실행된다. 코드를실행하기전에중간단계의언어가원시코드로컴파일된다. 관리되는실행환경의자체런타임인식컴파일러가컴파일을수행하므로, 관리되는실행환경은그코드가무엇을하는지보장할수있다. Java 개발언어는버퍼오버플로우에취약하지않다. 원시메소드나시스템호출이이루어지지않는다면, 버퍼오버플로우는문제가되지않는다. 마지막으로 ASP 페이지는코드를실행하면서 VBScript 인터프리터가정수오버플로우를검사하므로버퍼오버플로우에내성을가지고있다. 129
OS 인젝션을위한코드리뷰 소개인젝션취약점이있으면공격자는웹애플리케이션을통해다른하위시스템으로악성코드를전달할수있다. 하위시스템에따라다음과같은유형의인젝션공격이수행될수있다. RDBMS: SQL 인젝션웹브라우저 / 앱서버 : SQL 인젝션 OS-쉘 : 애플리케이션에서외부애플리케이션을호출하는운영체제명령. OS 인젝션명령은인젝션결함에해당하는공격클래스중하나이다. 다른분류방식으로이인젝션은입력값검증및표현범주로서 OS 인젝션명령위협클래스에해당하며, 또는제어영역에데이터제거실패취약점그리고인수인젝션공격패턴목록으로정의된다. 애플리케이션에서입력값검증또는이스케이핑을하지않은채, 신뢰하지않고안전하지않은입력값을받아서외부애플리케이션 ( 애플리케이션이름이나인수 ) 으로전달할때 OS 인젝션명령이발생한다. 취약한코드확인방법 많은개발자들은문자필드에서만데이터유효성을검사해야한다고생각하고있다. 이것은맞지않다. 외부입력값에대해서도데이터유효성검사를해야한다. 문자필드, 목록박스, 라디오버튼, 체크박스, 쿠키, HTTP 헤더데이터, HTTP 포스트데이터, 숨은필드, 파라미터명칭및파라미터값등. 이것이전체목록은아니다. 프로세스에서프로세스로가는것 또는 개체에서개체로가는 통신도조사해야한다. 업스트림또는다운스트림프로세스와통신하며, 이로부터입력값을받는코드를검토해야한다. 모든인젝션취약점은입력유효성검사에서발생하는오류다. 인젝션취약점이있다는것은신뢰범위외의소스에서수신한입력에대하여부정확한데이터유효성검사가있다는것을나타내며, 이는매년더취약해지고있다. 기본적으로이러한유형의취약성에대하여애플리케이션으로향하는모든입력스트림을찾아야한다. 이것은사용자의브라우저, CLI 또는팻클라이언트 (fat client) 에서올수있지만, 애플리케이션에공급되는업스트림프로세스에서도올수있다. 한가지예로통신용으로사용되는 API 또는패키지를사용하기위한코드베이스를검색하는것이다. java.io, java.sql, java.net, java.rmi, java.xml 패키지는모두애플리케이션통신용으로사용된다. 코드베이스내 의이들패키지에서방법을찾을수있다. 더 " 과학적 (scientific)" 이지못한방법은 UserID, LoginID 또는 Password 와같은공통키워드를검색하는것이다. 130
OS 인젝션에취약한패턴 먼저애플리케이션과운영체제간의관계및운영체제에서제공하는애플리케이션이사용할수있는함수를알아야한다. 런타임개체를사용하는자바에서는 java.lang.runtime 이이를수행한다..NET 은 System.Diagnostics. Process.Start 와같은요청을통해기초적인 OS 함수를호출한다. PHP 에서는 exec() 또는 passthru() 와같은호출을요청할수있다. 예 : HTTP 요청을통해사용자로부터입력을받는클래스가있다. 이클래스는애플리케이션서버에있는실행파일 (.exe) 를실행하여결과를회신하기위해사용된다. public class DoStuff { public string executecommand(string username) { try { String myuid = username; Runtime rt = Runtime.getRuntime(); rt.exec("cmd.exe /C dostuff.exe " + - +myuid); // Call exe with userid }catch(exception e) { e.printstacktrace(); } } } 이메소드는 java.lang.runtime 의정적메소드 getruntime() 을통해 dostuff.exe (cmd.exe 활용 ) 를호출한다. 전달된파라미터는이클래스에서어떠한방법으로도유효성검사되지않는다. 데이터는이방법을호출하기전에유효성검사가되지않은데이터라고가정한다. 트랜잭션분석시이포인트이전에데이터유효성검사를하게된다. Joe69 를입력하게되면다음 MS DOS 명령즉, dostuff.exe Joe69 이나타나게된다. Joe69 & netstat a 를입력하면다음과같은응답이온다. 즉 exe dostuff 는 User Id Joe69 의전달값을실행하지만, 도스명령 netstat 가호출될것이다. 이것이동작되는방법은애플리케이션에파라미터 "&" 를전달하는것이며, 그다음에이파라미터는 MS DOS 에서명령어의부가명령어로사용되며, & 뒤의문자의명령이실행된다. 131
위와같은코드로작성되었다면사실이아니다. ( 여기서 dostuff.exe 가 cmd.exe 또는 /bin/sh 와같은명령해석 프로그램으로동작하지않는다고가정 ) public class DoStuff { public string executecommand(string username) { try { String myuid = username; Runtime rt = Runtime.getRuntime(); rt.exec("dostuff.exe " + - +myuid); // Call exe with userid }catch(exception e) { e.printstacktrace(); } } } 그이유는? Java 2 documentation 참조... 더정확히말하면, 주어진명령문자열이문자카테고리를추가적으로수정하지않고, 새로운문자열토큰생성기 ( 명령 ) 를호출하고, 생성된문자열토큰생성기를사용하여토큰으로분할된다. 토큰생성기로생성된이토큰은동일한순서로, 새로운문자열배열 cmdarray 에위치하게된다... 생성된배열은호출할수있는실행파일 ( 첫번째아이템 ) 과그인수들 ( 나머지인수들 ) 을포함하고있다. 따라서호출되는첫번째아이템이인수를파싱하고해석하는애플리케이션이아니면, 이인수에따라다른외부애플리케이션을추가적으로호출하는경우위코드의미리보기 (snippet) 에서 netstat 를실행하지못할수도있다. 호출되는이들첫번째아이템은윈도우에서는 cmd.exe 이거나유닉스에서는 sh 가된다. 대부분의외부소스코드 / 어셈블리분석기는위험한 API 를발견하면, 명령실행예외신호인 System.Diagnostics.Process.Start, java.lang.runtime.exec 를보낸다 ( 일부는보내지않을수도있음 ). 그러나계산된위험은다르다. 첫번째예에서 " 명령인젝션 (command injection)" 이그러하며, 반대로두번째예와같이 132
유효성검사나이스케이핑이없을경우 " 인자인젝션 (argument injection)" 취약성이존재한다고할수있다. 따라서아직도위험이존재하지만심각도는호출되는명령에따라다르다. 따라서이문제는분석이필요하다. UNIX /bin/bash 또는 /bin/sh 와같은쉘 (shell) 을통해명령이실행되는경우, 공격자가문자열 ; cat /etc/hosts 을 삽입할수도있고유닉스호스트파일의내용이공격자에게노출될수도있다..NET 예제 : namespace ExternalExecution { class CallExternal { static void Main(string[] args) { String arg1=args[0]; System.Diagnostics.Process.Start("doStuff.exe", arg1); } } } 다시한번말하지만여기서는데이터검증은없다. 즉다른클래스에서발생하는상향식유효성검사는없다고 가정한다. 클래식 ASP 예제 : <% option explicit 133
dim wshell set wshell = CreateObject("WScript.Shell") wshell.run "c:\file.bat " & Request.Form("Args") set wshell = nothing %> 이공격의예는시스템호출을통해운영체제호출, 쉘명령을통해외부프로그램을사용하는것과 SQL( 즉, SQL 인젝션 ) 로백엔드데이터베이스를호출과같은것이다. 펄, 파이썬, 쉘, 배치와기타언어로작성된완벽한 스크립트는엉성하게설계된웹애플리케이션으로삽입되어실행될수있다. OS 인젝션을방지하기위한패턴및절차 데이터유효성검사절을참조하기바란다. 관련문서 명령어삽입 해석프로그램삽입 http://www.owasp.org/index.php/command_injection http://www.owasp.org/index.php/interpreter_injection 134
SQL 인젝션을위한코드리뷰 개요 SQL 인젝션공격은클라이언트에서애플리케이션으로의입력데이터를통해 SQL 질의를주입 (insertion) 또는삽입 (injection) 하는것이다. 연속적으로 SQL 인젝션하여데이터베이스에서민감한데이터를읽고데이터베이스의데이터를수정 ( 추가 / 변경 / 삭제 ), 데이터베이스의관리자작업을실행 (DBMS 종료 ), DBMS 파일시스템에존재하는일정한파일컨텐츠를복구, 일부경우에운영체제명령을내릴수있다. SQL 인젝션공격은인젝션공격의형태이며, 여기서사전에정의된 SQL 명령을실행하기위해일반적인데이터입력값에 SQL 명령어를삽입한다. 관련보안활동 SQL 인젝션취약점설명 SQL 인젝션취약점에대한 OWASP 문서참조 http://www.owasp.org/index.php/sql_injection 블라인드 SQL 인젝션취약점에대한 OWASP 문서참조 http://www.owasp.org/index.php/blind_sql_injection SQL 인젝션취약점방지방법 SQL 인젝션취약점예방방법에대한 OWASP 개발자가이드참조 http://www.owasp.org/index.php/guide_to_sql_injection SQL 인젝션취약점시험방법 SQL 인젝션취약점시험방법에대한 OWASP 테스트가이드참조 http://www.owasp.org/index.php/testing_for_sql_injection 취약가능한코드확인방법 SQL 문장을안전하게작성하는방법은문장대신에미리작성된문장으로모든질의를구성하여, 파라미터화된절차를사용하는것이다. 파라미터화되어저장된절차는사용자입력값을추가하기전에컴파일되어, 해커가실제 SQL 문장을수정할수없게한다. 데이터베이스에연결하기위해사용되는계정은반드시 " 최소권한 " 을가져야한다. 만약애플리케이션이읽기접근만을요구하는경우그계정에읽기권한만제공해야한다. 135
오류정보누출방지 : 오류처리를잘못하면, 공격자가 SQL 인젝션공격을아주쉽게성공할수있다. 발견되지 못한 SQL 오류는사용자에게보통너무많은정보를제공하며, 테이블명과프로시져명과같은것을포함하게된 다. 데이터베이스관리방법모범사례 데이터베이스에저장된프로시져를사용하는것이좋다. 하지난이것도취약할수있다. 동적인 SQL 문장대신에파라미터화된질의를사용한다. 모든외부입력데이터의유효성검사 : 모든 SQL 문장이사용자입력값을변수로서인식하도록하고실제입력값이자바에서변수로대체되기전에문장이사전컴파일되어있는지확인한다. SQL 인젝션예 : String DRIVER = "com.ora.jdbc.driver"; String DataURL = "jdbc:db://localhost:5112/users"; String LOGIN = "admin"; String PASSWORD = "admin123"; Class.forName(DRIVER); //Make connection to DB Connection connection = DriverManager.getConnection(DataURL, LOGIN, PASSWORD); String Username = request.getparameter("user"); // From HTTP request String Password = request.getparameter("password"); // From HTTP request int iuserid = -1; String sloggeduser = ""; String sel = "SELECT User_id, Username FROM USERS WHERE Username = '" +Username + "' AND Password = '" + Password + "'"; Statement selectstatement = connection.createstatement (); ResultSet resultset = selectstatement.executequery(sel); 136
if (resultset.next()) { iuserid = resultset.getint(1); sloggeduser = resultset.getstring(2); } PrintWriter writer = response.getwriter (); if (iuserid >= 0) { writer.println ("User logged in: " + sloggeduser); } else { writer.println ("Access Denied!") } 소프트웨어가실행될때 SQL 문장이동적으로생성되는경우, 입력데이터가잘리거나, 오동작하게하거나또는심지어 SQL 질의를확장하게될때보안침해가발생할수있다. 먼저, request.get 파라미터는데이터유효성검사 ( 최소 / 최대길이, 허용문자, 악성문자 ) 를하지않고 HTTP 요청에서직접 SQL 질의에대한데이터를검색한다. 이러한오류는페이로드에 SQL 명령을입력하거나구문내함수를변경하는취약점이생기게된다. 애플리케이션에서페이로드를직접구문에위치시켜 SQL 이취약점이생길수한다. String sel = "SELECT User_id, Username FROM USERS WHERE Username = '" Username + "' AND Password = '" + Password + "'"; 137
.NET SqlParameterCollection 과같은파라미터를수집하면형식및길이유효성검사할수있다. 파라미터수집을사용한다면입력값을그자체값으로처리하고, SQL 서버는이값을실행가능한코드로처리하지않는다. 그래서페이로드는삽입될수없다. 파라미터수집을사용하면형식과길이검사를강제화할수있다. 범위에해당하지않는값은예외처리된다. 정확하게예외처리할수있는지확인해야한다. SQL 파라미터수집의예는다음과같다. using System.Data; using System.Data.SqlClient; using (SqlConnection conn = new SqlConnection(connectionString)) { DataSet dataobj = new DataSet(); SqlDataAdapter sqladapter = new SqlDataAdapter( "StoredProc", conn); sqladapter.selectcommand.commandtype = CommandType.StoredProcedure; //specify param type sqladapter.selectcommand.parameters.add("@usrid", SqlDbType.VarChar, 15); sqladapter.selectcommand.parameters["@usrid "].Value = UID.Text; // Add data from user sqladapter.fill(dataobj); // populate and execute proc } 저장된프로시져가항상 SQL 인젝션을막아주지는않음 : CREATE PROCEDURE dbo.runanyquery @parameter NVARCHAR(50) AS EXEC sp_executesql @parameter 138
GO 위의프로시져는사용자가전달하는각종 SQL 을실행한다. 지시어 sp_executesql 은마이크로소프트 SQL 서버의 저장된프로시져이다. 이것을전달해보자. DROP TABLE ORDERS; 무슨일이발생할까? " 저장된프로시져를사용하고있으므로안전하다 " 라고생각하는것은위험하다. 클래식 ASP 이러한기법에대해서, SQL 인젝션을피하기위해파라미터화된질의를사용할수있다. 여기좋은예가있다. <% option explicit dim conn, cmd, recordset, itableidvalue 'Create Connection set conn=server.createobject("adodb.connection") conn.open "DNS=LOCAL" 'Create Command set cmd = server.createobject("adodb.command") With cmd.activeconnection=conn.commandtext="select * from DataTable where Id = @Parameter" 'Create the parameter and set its value to 1.Parameters.Append.CreateParameter("@Parameter", adinteger, adparaminput,, 1) 139
End With 'Get the information in a RecordSet set recordset = server.createobject("adodb.recordset") recordset.open cmd, conn '... 'Do whatever is needed with the information '... 'Do clean up recordset.close conn.close set recordset = nothing set cmd = nothing set conn = nothing %> 이것은특정 SQL 서버의코드라는것에주목해야한다. ISAM 이파라미터화된질의를지원하는다른 DB 에 ODBC/Jet 연결을시도할경우다음과같이질의를변경해야한다. cmd.commandtext="select * from DataTable where Id =?" 마지막으로다음과같이잘못하게될 ( 하지만그러면안되는 ) 일은항상발생한다. cmd.commandtext="select * from DataTable where Id = " & Request.QueryString("Parameter") 140
데이터유효성검증을위한코드리뷰 웹애플리케이션보안의주요영역중하나는외부소스로부터입력된데이터의유효성을검증하는것이다. 응용프로그램악성코드의대부분은응용프로그램의입력값검증을허술하게하는데서파생된다. 데이터유효성검증이제대로이루어지지못하면공격자들에게애플리케이션이의도하지않는기능까지도수행할수있는기회를제공한다. 관련보안활동 크로스 - 사이트스크립팅취약점예방방법 데이터유효성의 OWASP 개발가이드문서참조. 입력값의정형화 입력값을인코딩해도응용프로그램이올바르게해석할수있도록할수있지만, 여전히공격받을수있다. 유니코드에서 ASCII 의인코딩은입력값검증을우회하는또다른방법이기도하다. 응용프로그램은유니코드공격에대한테스팅을거의하지않아서공격자에게공격경로를제공한다. 여기서주목할점은유니코드기호나다른변형기호가입력되더라도응용프로그램은안전하다는점이다. 응용프로그램은정확하게응답하고, 가능한모든유효하지않은문자를인식한다. 예 : The ASCII: <script> ( 만약에 < 와 > 문자를차단하면, 아래와같은다르게표현하면데이터검증을통과하고실행된다.). URL 인코딩값 : %3C%73%63%72%69%70%74%3E 유니코드인코딩값 : <script> 이주제에대해서는 OWASP 개발가이드에서보다상세하게다루고있다. 데이터검증전략 일반적으로적용하는규칙은 안전한항목 에해당하는문자즉, 예측가능한문자만허용하는것이다. 이것이어려울경우에는그다음으로가장강력한전략은알려진모든나쁜문자를차단하는 위험한항목 이다. 여기서문제는최근의금지된목록이엔터프라이즈급인프라에새로운기술이추가되면서미래에도확장될수있다는점이다. 141
데이터검증전략을설계할때다음몇가지모델을고려할수있다. 다음은가장강력한모델부터가장취약한 모델순으로나열한것이다. 1. 정확한일치 ( 제한 ) 2. 안전한값 ( 승인 ) 3. 위험한값 ( 거부 ) 4. 위험한값인코딩 ( 제거 ) 또한, 서비스 / 컴퓨터또는웹브라우저사용자와같은외부소스로부터흘러오는모든입력값에대해반드시최대길이를확인해야한다. 거부된데이터는반드시데이터저장소에남아있으면안된다. 잘못된데이터를일반적으로기록하는실수를하고있으나, 공격자는이러한애플리케이션오류를놓치지않는다. 정확한일치 : ( 바람직한방법 ) 알려진값한정목록으로부터받은값만수용. 예 : 3 개의설정 (A,B,C) 을갖는웹페이지의라디오버튼컴포넌트. 이 3 개의설정중하나만 (A 또는 B 또는 C) 이허용되며, 나머지값은반드시거부된다. 안전한값 : 시스템에입력가능한모든값에대한제한된목록을가지고있지않다면, 허용된항목을이용한접근방식을사용한다. 예 : 이메일주소에는 @ 을단한개만포함한다는것은누구나안다. 또한하나이상의마침표 "." 는존재할수있다. 나머지정보는 [a-z] 또는 [A-Z] 또는 [0-9] 와더불어 _ 나 와같은그밖의모든문자가가능하다. 따라서주소의최대길이를정의하는데이러한범위를적용한다. 위험한값 : 시스템에입력되지않길바라는금지된목록이존재하는상황이다. 이는자유형식텍스트영역이나사용자가메모를쓸수있는영역에서발생한다. 이모델의취약점은현재악성으로알려진것들이미래를대비하기에는충분하지않다. 위험한값인코딩 : 가장취약한접근방식이다. 이접근방식은모든입력값을수용하지만 HTML 은특정문자범위내의모든문자열을인코딩한다. HTML 인코딩이완료되어버리므로, 입력값이브라우저에다시표시될필요가생기면브라우저는텍스트를스크립트로해석하지않으나, 텍스트는사용자가원래입력한것과동일하게보인다. 클라이언트에게응답을보낼때사용자입력값을 HTML 인코딩과 URL 인코딩한다. 이러한경우엔, 어떤입력값도 HTML 로취급하지않으며모든출력값은보호된형태로응답한다고가정한다. 이는동작과정에서데이터를필터링하는것이다. 데이터검증에좋은패턴 142
데이터검증예시 다음은 PHP 응용프로그램에서 OS 인젝션을방지하기위한데이터검증패턴의좋은예다 : $string = preg_replace("/[^a-za-z0-9]/", "", $string); 위의코드는알파벳이나숫자가아닌다른문자를 로대체한다. preg_grep() 함수는 True/False 판별에쓰일수있다. 이를통해 허용된항목 문자만응용프로그램으로넘겨줄수있도록한다. 정규표현식을사용하는것은입력문자형식을제한하는일반적인방법이다. 정규표현식을개발할때자주하는실수는제어문자로해석되는문자를이스케이핑지않고입력값의모든경로를검증하지않는것이다. 정규표현식의예는다음과같다 : http://www.regxlib.com/cheatsheet.aspx ^[a-za-z]+$ 알파벳만, a 에서 z 와 A 에서 Z ( 정규표현식은대소문자를구분한다 ). ^[0-9]+$ 숫자만 (0 에서 9). [abcde] [^abcde] 집합내에정의된문자와겹치는문자모두 집합내에정의되지않은문자모두 프레임워크예시 ( 스트럿츠 1.2) J2EE 의스트럿츠프레임워크 (1.1) 에는공통유효성검사기라는유틸리티가포함되어있다. 이유틸리티를이용해 두가지를할수있다. 1. 중앙에서한꺼번에데이터검증을할수있다. 2. 데이터검증프레임워크를제공한다. 스트럿츠를조사할때찾아볼것은다음과같다 : struts-config.xml 파일에는아래내용을반드시포함해야한다. <plug-in classname="org.apache.struts.validator.validatorplugin"> <set-property property="pathnames" value="/technology/web-inf/ validator-rules.xml, /WEB-INF/validation.xml"/> 143
</plug-in> 이를통해프레임워크에서유효성검증플러그인을로드하게한다. 여기서는쉼표로구분되는목록으로정의된속성파일도불러온다. 기본적으로개발자는 validation.xml 파일에정해진필드에정규표현식을추가할것이다. 다음으로는응용프로그램에대한 form-beans 를살펴본다. 스트럿츠에서 form-beans 는서버단에서 HTTP 폼을통해응용프로그램에보낸정보를캡슐화한다. 아래와같이구체적인 form-beans( 개발자가코드에탑재 ) 혹은동적인 form-beans 를가질수있다. package com.pcs.necronomicon import org.apache.struts.validator.validatorform; public class LogonForm extends ValidatorForm { private String username; private String password; public String getusername() { return username; } public void setusername(string username) { this.username = username; } public String getpassword() { return password; } public void setpassword(string password) { this.password = password; } } 144
LoginForm 이 ValidatorForm 을상속받는다는점에주의하라. 이는부모클래스 (ValidatorForm) 에는자동으로호출되어 validation.xml 에정의된규칙을호출하는인증메소드가반드시있어야한다는것을뜻한다. 이제이폼빈이호출되고있는지확인하기위해서 struts-config.xml 파일을보자 : 이파일에는다음과같은내용이들어있어야한다. <form-beans> <form-bean name="logonform" type=" com.pcs.necronomicon.logonform"/> </form-beans> 다음은 validation.xml 파일을확인할것이다. 다음과유사한코드를포함하고있어야한다. <form-validation> <formset> <form name="logonform"> <field property="username" depends="required"> <arg0 key="prompt.username"/> </field> </form> </formset> </form-validation> validation.xml 내에이름이같은 struts-config.xml 을주의하라. 이것은중요한관계가있으며대소문자를 구별한다. username 필드도대소문자를구별하며 LoginForm 클래스의 String username 을나타낸다. 지시어 depends 는매개변수가필요하다는것을뜻한다. 이것이공백으로되어있는경우, 오류정보는 Application.properties 파일에정의되어있다. 이설정파일은다른것들사이에있는오류메시지도포함하고 있다. 정보유출문제를찾기에도좋은곳이다 : 145
유효성프레임워크검증을위한오류메시지 errors.required={0} is required. errors.minlength={0} cannot be less than {1} characters. errors.maxlength={0} cannot be greater than {2} characters. errors.invalid={0} is invalid. errors.byte={0} must be a byte. errors.short={0} must be a short. errors.integer={0} must be an integer. errors.long={0} must be a long.0. errors.float={0} must be a float. errors.double={0} must be a double. errors.date={0} is not a date. errors.range={0} is not in the range {1} through {2}. errors.creditcard={0} is not a valid credit card number. errors.email={0} is an invalid e-mail address. prompt.username = User Name is required. arg0 에서정의한오류인 prompt.username 은스트럿츠프레임워크가사용자에게경고상자로표시한다. 개발자는정규표현식을통해입력값을검증함으로써한단계더검증할수있다. <field property="username" depends="required,mask"> <arg0 key="prompt.username"/> <var-name>mask ^[0-9a-zA-Z]*$ 146
</var> </field> </form> </formset> </form-validation> 여기서는 Mask 지시어를추가했다. 변수 <var> 과정규표현식을명시하고있다. username 필드에대해 A 부터 Z 까지, a 부터 z 까지, 0 부터 9 까지의문자이외의모든입력은오류를발생시켜예외가될것이다. 이러한유형의개발에서가장일반적인문제는개발자가모든필드및폼전체를검증하는것을망각하는것이다. 이밖에살펴볼부분은잘못된정규표현식이므로, RegEx s kids 를배워보자!!! JSP 페이지가 validation.xml 까지기능적으로잘연결되어있는지부터확인해야한다. 이것은다음과같이 JSP 에포함되어있는 <html:javascript> 커스텀태그에서이루어진다. <html:javascript formname="logonform" dynamicjavascript="true" staticjavascript="true" /> 프레임워크예시 (.NET) ASP.NET 프레임워크는입력값검증을더쉽게할수있고이전보다오류가적게발생하는유효성검사프레임워크를가지고있다..NET 에대한검증기능도스트럿츠 (J2EE) 와유사한클라이언트와서버기능을갖추고있다. 검증기능이란무엇인가? 마이크로소프트 (MSDN) 사의정의를따르면다음과같다 : 검증기능은특정유형의오류조건에대해하나의입력값통제를확인하고, 그문제에대한설명을표시하는일종의통제기능이다. 코드리뷰관점에서이에대한핵심내용은하나의유효성검사기능은한가지형식의기능을수행한다는것이다. 입력값에대해여러가지검사를해야한다면, 더많은유효성검사기능활용해야한다..NET 제품은그밖의여러개의통제기능를가지고있다 : RequiredFieldValidator 필수적으로입력해야할필드로만든다. CompareValidator 사용자가입력값통제에입력한값과, 또다른입력값통제혹은상수로입력되는 값을비교. RangeValidator 입력값통제의값이정의된범위내에있는지확인. RegularExpressionValidator 정규표현식에대한사용자입력값확인. 147
검증을포함하는웹페이지 (.aspx) 의예는다음과같다 : <html> <head> <title>validate me baby!</title> </head> <body> <asp:validationsummary runat=server HeaderText="There were errors on the page:" /> <form runat=server> Please enter your User Id <tr> <td> <asp:requiredfieldvalidator runat=server ControlToValidate=Name ErrorMessage="User ID is required."> * </asp:requiredfieldvalidator> </td> <td>user ID:</td> <td><input type=text runat=server id=name></td> <asp:regularexpressionvalidator runat=server display=dynamic controltovalidate="name" errormessage="id must be 6-8 letters." validationexpression="[a-za-z0-9]{6,8}" /> </tr> <input type=submit runat=server id=submitme value=submit> 148
</form> </body> </html> 정규표현식은응용프로그램을보호하는데충분한것인지확인해야한다. runat 지시어는이코드가 클라이언트에게전송되기전에서버에서실행되는것을의미한다. 이것이사용자의브라우저에표시된다면, 일반적인 HTML 이다. 클래식 ASP 예시 기존의 ASP 페이지에는원래검증기능이탑재되어있지않지만, 작업을완료하기위해정규표현식을사용할 수는있다. 다음은예시로정규표현식으로미국의우편번호를검증하는것이다. Public Function IsZipCode (ByVal Text) Dim re set re = new RegExp re.pattern = "^\d{5}$" IsZipCode = re.test(text) End Function 길이검사 고려해야할또다른문제는입력값의길이에대한검증이다. 입력값이길이에제한을받으면, 웹애플리케이션으로삽입될수있는스크립트의길이를줄어든다. 많은웹응용프로그램들이각각의기능을수행하기위해운영체제의기능과외부프로그램을사용한다. 웹응용프로그램이외부요청의일부분을통해 HTTP 요청으로부터정보를전달할때는, 내용과최소 / 최대길이에대한검증이신중히이루어져야만한다. 데이터검증없이는공격자가메타문자열, 악의적인명령혹은명령을변조하는구문, 합법적인것으로가장된정보를삽입할수있게되어, 이러한것들을실행하기위해외부시스템에마구잡이로전달하게될것이다. 코드베이스가버퍼오버플로우공격에취약하지않더라도, 최소및최대길이를확인하는것은매우중요하다. 특정트랜잭션에서이용되는모든데이터를로깅하기위해로깅기능이사용되는경우, 수신된페이로드가 크기로인해로깅기능에영향을주지않도록해야한다. 너무큰로그파일을전송하면다운될수있다. 혹은 149
반복적으로너무큰페이로드를전송한다면, 응용프로그램서버의하드디스크를가득채워서비스거부가발생할수있다. 로그파일을재사용해서이러한유형의공격이가능하므로, 감사흔적은삭제해야한다. 응용프로그램이전달받은페이로드상에서스트링파싱이수행되고, 아주많이큰스트링이반복적으로응용프로그램에전송된다면, 응용프로그램이페이로드를파싱하는데사용하는 CPU 사이클로인해서비스성능의저하또는서비스거부까지발생할수있다. 클라언트측데이터검증에만의존하지말라 클라이언트측검증은늘간과하기쉽다. 서버측코드는자체적으로검증을수행해야한다. 공격자가정당한클라이언트의권한을우회하거나, 클라이언트스크립트루틴을제대로동작하지않도록, 예를들면자바스크립트를비활성화한다면? 클라이언트측검증을사용하여서버로의라운드트립횟수를줄이는데도움은줄수있지만, 보안을위해여기에만의존해서는안된다. 주의사항 : 데이터검증은반드시서버측에서이루어져야만한다. 코드리뷰는서버측코드에집중해야한다. 모든클라이언트측보안코드는보안이고려되지않고있다. 파라미터명데이터검증 HTTP 를통해데이터가웹응용프로그램의한메소드에전달되면, 페이로드는 UserId =3o1nk395y password=letmein123 와같이 키-값 의쌍에전달된다. 앞에서는응용프로그램에전달되는페이로드 ( 매개변수값 ) 의입력값검증에대해서다루었다. 하지만매개변수이름 ( 위의 UserId, password) 도변조되지않았는지확인해야할것이다. 정당하지않은매개변수이름으로인해응용프로그램에충돌이발생하거나, 기대하지않은동작을유발할수있다. 가장좋은접근방법은앞에서언급한바와같이 Exact Match 이다. 웹서비스데이터검증 웹서비스를위한입력값검증하기위해서는스키마를사용하는것을추천한다. 하나의스키마는각각의매개변수가주어진웹서비스메소드에대해취할수있는모든허용가능한값에대한 지도 이다. SOAP 메시지가웹서비스핸들러에의해수신될때, 호출된메소드와관련된스키마는 SOAP 메시지의내용을검증하기위한메시지는훑어본다. 웹서비스통신방식에는두가지가있다 ; XML-IN/XML-OUT 과 REST (Representational State Transfer) 이다. XML-IN/XML-OUT 은요청형태가 SOAP 메시지이고응답또한 SOAP 임을의미한다. REST 웹서비스는 URI 요청 (Non XML) 을받아들이지만 XML 응답으로리턴한다. REST 는요청의마지막목적지이전에있을다중노드통신의 SOAP 체인내에서의단말간솔루션만을지원한다. REST 웹 150
서비스입력값을검증하는것은 GET 요청을검증하는것과같다. XML 요청을검증하는것은스키마로조치할수있는가장좋은방법이다. <?xml version="1.0"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/xmlschema" xmlns="http://server.test.com" targetnamespace="http://server.test.com" elementformdefault="qualified" attributeformdefault="unqualified"> <xsd:complextype name="addressin"> <xsd:sequence> <xsd:element name="addressline1" type="hundredanumeric" nillable="true"/> <xsd:element name="addressline2" type="hundredanumeric" nillable="true"/> <xsd:element name="county" type="tenanumeric" nillable="false"/> <xsd:element name="town" type="tenanumeric" nillable="true"/> <xsd:element name="userid" type="tenanumeric" nillable="false"/> </xsd:sequence> </xsd:complextype> <xsd:simpletype name="hundredanumeric"> <xsd:restriction base="xsd:string"> <xsd:minlength value="1"/> <xsd:maxlength value="100"/> <xsd:pattern value="[a-za-z0-9]"/> </xsd:restriction> </xsd:simpletype> <xsd:simpletype name="tenanumeric"> <xsd:restriction base="xsd:string"> <xsd:minlength value="1"/> 151
<xsd:maxlength value="10"/> <xsd:pattern value="[a-za-z0-9]"/> </xsd:restriction> </xsd:simpletype> </xsd:schema> 여기 AddressIn 이라는객체에대한스키마가있다. 엘리먼트각각은제한이적용되었고해당제한은엘리먼트각각에입력될수있는정당한문자열을정의하고있다. 여기서는각각의엘리먼트들이 xsd:string 같은간단한형태로정의된것과반대로각엘리먼트에제한이적용되었는가를검토해야한다. 물론이스키마에는수신된데이터시퀀스에강제적으로적용되는 <xsd:sequence> 태그가있다. 취약한코드와관련된수정사항 첫번째예시 - PERL 다음 PERL 코드스니펫은 XSS 에취약한코드를보여준다. #!/usr/bin/perl use CGI; my $cgi = CGI->new(); my $value = $cgi->param('value'); print $cgi->header(); print "You entered $value"; 코드에서무조건허용해주고있으며파라미터에서제공되는데이터는 value 라는붙혀져있다. 이렇게검증없이데이터를수용하는문제점이외에코드는사용자에게입력받은데이터를고스란히보여줄것이다. 만약논문에서이것을읽었다면이러한특정취약점이반사 XSS 공격을발생시킬수있다는생각을머릿속에떠올리기바란다. value 매개변수는제공된데이터를검증해야하며검증필터가 cleaned 로처리한데이터만을출력해야한다. 이매개변수를정확히검증하려면펄의여러옵션들을이용할수있다. 우선, 간단한필터는다음과같다 : 152
$value =~ s/[^a-za-z0-9 ]*/ /g; 이것은대문자, 소문자, 공백과숫자로매개변수의데이터를제한한다. 물론 < 와 > 와같이 XSS 에이용되는위험한문자들은제거한다. 두번째옵션은펄에서입력된데이터를모두 HTML 인코딩해주는 HTML::Entities 모듈을사용하는것이다. 여기서는 HTML::Entities 모듈을포함해서코드를변경하였으며, 실제인코딩된것을출력하는예제이다. #!/usr/bin/perl use CGI; use HTML::Entities; my $cgi = CGI->new(); my $value = $cgi->param('value'); print $cgi->header(); print "You entered ", HTML::Entities::encode($value); If the data provided was <SCRIPT>alert( XSS )</SCRIPT> the HTML::Entities module would produce the following output: <SCRIPT>alert("XSS")</SCRIPT> 이렇게하면원입력값에의한위협을제거할수있다. 두번째예시 - PHP PHP 를이용하면사용자가동적인웹페이지를아주쉽게만들수있으나, 동시에보안에취약한 PHP 코드를만들수있다. 아래의예는충분한데이터검증없이설치되는매우간단한 PHP 메시지게시판을보여준다. <form> <input type="text" name="inputs"> <input type="submit"> </form> <?php if (isset($_get['inputs'])) 153
{ $fp = fopen('./inputs.txt', 'a'); fwrite($fp, "{$_GET['inputs']}"); fclose($fp); } readfile('./inputs.txt');?> 위의간단한폼은사용자입력값을받아 inputs.txt 라는파일에기록되는것을볼수있다. 그런다음, 이파일을사용해서다른사용자들이볼수있는메시지보드에메시지를기록한다. 이폼으로인한위험은명확하다. 초기입력값은어떤종류의검증도하지않고다른사용자에게악성코드를전파한다. 간단한검증기법을구현하면이런위험을피할수있다. PHP 에서는개발자가 htmlentities() 함수를사용할수있다. 폼에 htmlentities() 를추가해보았다 : <form> <input type="text" name="inputs"> <input type="submit"> </form> <?php if (isset($_get['inputs'])) { $message = htmlentities($_get['inputs']); $fp = fopen('./inputs.txt', 'a'); fwrite($fp, "$inputs"); fclose($fp); } readfile('./inputs.txt');?> 154
추가한코드는간단하지만실질적인효과를얻을수있다. 이제메시지보드는악의적인사용자에의해입력되었을수있는모든스크립트코드에대응하는몇가지보호기능을갖추었다. 입력되는스크립트코드는 htmlentities() 함수로인코딩된 HTML 개체가된다. 세번째예시 클래식 ASP PHP 와마찬가지로, ASP 페이지도다음과같은 XSS 공격코드때문에동적컨텐츠생성이가능하다 : Response.Write "Please confirm your name is " & Request.Form("UserFullName") 다음과같은방식으로 HTMLEncode 내장함수를사용하여입력값을검증할수있다. Response.Write "Please confirm your name is " & Server.HTMLEncode (Request.Form("UserFullName")) 네번째예시 JAVASCRIPT 네번째와마지막예에서는자바스크립트코드에대해알아볼것이다. 한번더코드의취약한부분을먼저보고, 그다음엔같은코드이지만적소에데이터검증이이루어진코드를볼것이다. URL 에서사용자이름을얻어환영메시지를만드는몇가지취약한자바스크립트를살펴보겠다. 취약한스크립트는다음과같다 : <SCRIPT> var pos=document.url.indexof("name=")+5; document.write(document.url.substring(pos,document.url.length)); </SCRIPT> 이스크립트의문제는앞에서논의되었던것이다 ; name= 에서제공되는값에대한검증절차가없다. 아주간단한검증기법을이용하여아래스크립트를수정해보았다. <SCRIPT> var pos=document.url.indexof("name=")+5; var name=document.url.substring(pos,document.url.length); if (name.match(/^[a-za-z]$/)) { document.write(name); 155
} else { window.alert("invalid input!"); } </SCRIPT> 스크립트의세번째줄은문자가사용자이름의대소문자를제한하는지확인한다. 주어진값이이를위반할경우, 사용자에게는 Invalid input 오류가리턴된다. 156
크로스사이트스크립팅을위한코드리뷰 개요 공격자가웹애플리케이션을사용하여일반적으로클라이언트측스크립트형식으로크로스사이트스크립팅 (XSS) 공격을하면다양한엔드유저를대상으로악성코드를전송할수있다. 이러한공격을허용하는문제는사용자로부터의입력값에대한검증이없거나, 인코딩없이출력값을생성하는웹응용프로그램어디에서나발생가능하며, 광범위하게퍼져있다. 관련보안활동 크로스사이트스크립팅취약점설명 크로스사이트스크립에 (XSS) 대한 OWASP 문서를참조. http://www.owasp.org/index.php/cross-site_scripting_%28xss%29 크로스사이트스크립팅취약점예방법 피싱에대한 OWASP 개발가이드참조. http://www.owasp.org/index.php/phishing 데이터검증에대한 OWASP 개발가이드문서참조. http://www.owasp.org/index.php/data_validation 크로스사이트스크립팅취약점시험방법 크로스사이트스크립팅취약점테스트하는법에대한 OWASP 테스팅가이드문서참조. http://www.owasp.org/index.php/testing_for_cross_site_scripting OWASP AntiXSS 프로젝트참조 : http://www.owasp.org/index.php/category:owasp_php_antixss_library_project OWASP ESAPI 프로젝트참조 : http://www.owasp.org/index.php/esapi 취약한코드예시 157
사용자가입력한텍스트가반사되어돌아오고이데이터에대한검증이이루어지지않았다면, 브라우저는마크 업의일부로서입력된스크립트를해석해서실행한다. 이러한형태의취약점을완화하려면코드에서몇가지보안조치를수행해야한다 : 1. 데이터검증 2. 안전하지않은출력값인코딩 import org.apache.struts.action.*; import org.apache.commons.beanutils.beanutils; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; public final class InsertEmployeeAction extends Action { public ActionForward execute(actionmapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception{ // Setting up objects and vairables. Obj1 service = new Obj1(); ObjForm objform = (ObjForm) form; InfoADT adt = new InfoADT (); BeanUtils.copyProperties(adt, objform); String searchquery = objform.getquerystring(); 158
String payload = objform.getpayload(); try { service.dowork(adt); / /do something with the data ActionMessages messages = new ActionMessages(); ActionMessage message = new ActionMessage("success", adt.getname() ); messages.add( ActionMessages.GLOBAL_MESSAGE, message ); savemessages( request, messages ); request.setattribute("record", adt); return (mapping.findforward("success")); } catch( DatabaseException de ) { ActionErrors errors = new ActionErrors(); ActionError error = new ActionError("error.employee.databaseException" + Payload: +payload); errors.add( ActionErrors.GLOBAL_ERROR, error ); saveerrors( request, errors ); return (mapping.findforward("error: "+ searchquery)); } } } 위의텍스트는스트럿츠액션클래스개발에서흔히하는실수몇가지를보여준다. 첫째, HttpServletRequest 내에서전달된데이터가검증없이매개변수에배치된다. 159
XSS 에초점을둔다면, 함수가성공적으로동작할경우이액션클래스는 ActionMessage 라는메시지를반환하는것을볼수있다. Try/Catch 블록내의오류코드가실행되면, HttpServletRequest 에포함된데이터가검증을거치지않은상태로사용자가입력한형식내에서정확히사용자에게반환된다. import java.io.*; import javax.servlet.http.*; import javax.servlet.*; public class HelloServlet extends HttpServlet { public void doget (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String input = req.getheader( USERINPUT ); PrintWriter out = res.getwriter(); out.println(input); // echo User input. out.close(); } } 다음은 XSS 에취약할수있는함수의두번째예이다. 검증되지않은사용자입력값을브라우저로다시보내는 것은좋은취약점의증거가된다..NET 예시 (ASP.NET VERSION 1.1 ASP.NET VERSION 2.0): VB.NET 응용프로그램을위한서버측코드도유사한기능을가지고있다. ' SearchResult.aspx.vb Imports System Imports System.Web Imports System.Web.UI Imports System.Web.UI.WebControls Public Class SearchPage Inherits System.Web.UI.Page 160
Protected txtinput As TextBox Protected cmdsearch As Button Protected lblresult As Label Protected Sub cmdsearch _Click(Source As Object, _ e As EventArgs) // Do Search.. // lblresult.text="you Searched for: " & txtinput.text // Display Search Results.. // End Sub End Class 이코드는 VB.NET 으로작성되었으며, 사용자가입력한데이터를다시되돌려주는검색기능에서취약한부분을 보여주는예시이다. 이취약점에대응하려면데이터검증을적절히수행해야하며, 저장 XSS 공격의경우엔 위험한 입력값을인코딩할필요가있다.( 이내용은앞에서다루었음 ) 클래식 ASP 예시 대부분의웹기술과마찬가지로클래식 ASP 도 XSS 에취약하다. <%... Response.Write "<div class='label'>please confirm your data</div><br />" Response.Write "Name: " & Request.Form("UserFullName") 161
... %> XSS 대응.NET 프레임워크에는데이터검증과 HTML 인코딩을할수있는 ASP.NET 1.1 요청검증기능과 HttpUtility.HtmlEncode 등과같은보안기능이내장되어있다. 마이크로소프트는 ASP.NET 입력값검증에만의존하지말고정규표현식과같이개발자스스로만든데이터검증을이용할것을제안하고있다. ( 밑에서언급 ) 요청검증은각각의페이지에서특정페이지의관리하에비활성화시킬수있다. <%@ Page validaterequest="false" %> 또는 @pages 엘리먼트에는 ValidateRequest="false" 와같은세팅으로도제한할수있다. 또는 web.config 파일에서 : 다음과같이추가하는것으로요청검증기능을비활성화할수있다. <pages> element with validaterequest="false" 따라서코드를검토할때 validaterequest 가활성화되어있는지확인해야한다. 그렇지않다면데이터검증에어떤메소드가사용되고있는지확인해야한다. Machine.config 에서 ASP.NET 요청에대한검증이활성화되었는지확인해라. 요청검증은 ASP.NET 에의해기본값으로활성화되어있다. 다음과같은 Machine.config 파일의기본설정을확인할수있다. <pages validaterequest="true"... /> HTML 인코딩 : 컨텐츠는 HtmlEncode 함수를이용해쉽게인코딩해서출력할수있다. 다음과같이호출하면된다. Server.HtmlEncode(string) 특정폼에대한 html 인코더사용예 : Text Box: <%@ Page Language="C#" ValidateRequest="false" %> 162
<script runat="server"> void searchbtn _Click(object sender, EventArgs e) { Response.Write(HttpUtility.HtmlEncode(inputTxt.Text)); } </script> <html> <body> <form id="form1" runat="server"> <asp:textbox ID="inputTxt" Runat="server" TextMode="MultiLine" Width="382px" Height="152px"> </asp:textbox> <asp:button ID="searchBtn" Runat="server" Text="Submit" OnClick=" searchbtn _Click" /> </form> </body> </html> 클래식 ASP 페이지에서인코딩함수는 ASP.NET 과유사하게사용할수있다. Response.Write Server.HtmlEncode(inputTxt.Text) 저장크로스사이트스크립트 : 잠재적으로취약한출력값을인코딩하기위한 HTML 인코딩사용하기 : 악성스크립트는사용자에게검색되기까지실행되지않고데이터베이스에저장되거나잔류할수있다. 전자게시판이나구버전의웹이메일클라이언트에서도발생할수있는문제인데, 이러한잠복공격은스크립트가삽입된페이지를사용자가조회하기전까지오랜시간동안활동을하지않고있게된다 : 일반적으로엔터프라이즈급아키텍쳐의다른취약한응용프로그램에서악성스크립트가입력된다. 따라서손이쉽게닿는응용프로그램은데이터검증이잘이루어지고있을것이나, 이러한응용프로그램이아닌다른응용프로그램을통해유입된데이터자체는그렇지않다. 163
이러한사례에서우리는사용자에게보여지는데이터가 100% 안전하다고믿을수는없다 ( 엔터프라이즈급환경에서는또다른경로에서이러한방법을찾을수있듯이 ). 이를완화하기위해서브라우저로보내는데이터는브라우저에서마크업으로해석되지않는다고생각하고, 사용자데이터로다루어져야한다. 이러한 내부의적 으로부터의위협에대응하기위해 위험한항목 의문자열을인코딩한다. 이렇게하면실질적으로브라우저가모든특수문자를데이터와마크업으로해석하도록보장한다. 이것이어떻게수행될까? HTML 인코딩에서는보통 < 는 <, > 는 >, & 는 &, 는 &qout; 로변환된다. From To < < > > ( ( ) ) # # & & " " &apos ` %60 이를테면텍스트 <script> 는 <script> 로보이지만마크업에서는 <script> 로나타나는것이다. 164
CSRF 를위한코드리뷰 개요 CSRF 는웹애플리케이션에서사용자가인증된상태에서의도하지않은행위를하도록하는공격이다. 사회공학적인방법 ( 이메일 / 채팅프로그램을통한링크보내기 ) 을추가하면, 공격자가웹애플리케이션의사용자에게공격자가의도하는행위가수행하도록할수있다. CSRF 공격이성공하면정상적인사용자의경우최종사용자의데이터및운영도해킹할수있다. 만약공격대상이관리자계정이라면웹응용프로그램전체를위협할수도있다. 관련보안활동 CSRF 취약점설명 OWASP 문서중 CSRF 취약점을확인 http://www.owasp.org/index.php/csrf CSRF 취약점확인방법 CSRF 취약점을위한테스트에서 OWASP 테스팅가이드문서 http://www.owasp.org/index.php/testing_for_csrf 소개 CSRF 는 XSS(Cross Site Scripting) 와는다르다. 신뢰받는웹사이트에의해제공되는악성컨텐츠들이의심을하지않는사용자에게영향을미친다. 삽입된문자는브라우저에의해실행되는형태로처리되며, 이러한이유로스크립트가실행된다. 피싱, 트로이목마, 브라우저취약점공격등에이용된다. CSRF 공격자는공격대상이웹기반시스템에인증되어있다는것을알고있으면매우유용하게이용할수있다. CSRF 공격은공격대상이시스템에로그인되어있는경우에만가능하다. 그래서공격흔적이적게남는다. 다른사용자에의해서거래인가가없는것과같은논리적취약점도존재해야한다. 실제 CSRF 공격을통해대상사용자가인지하지못한상태에서대상브라우저를통해공격자가원하는시스템의기능 ( 자금이체, 서류제출등 ) 을수행하게하는데사용된다. 주요공격대상으로예를들면웹애플리케이션에서편리하게사용되는기능 ( 원클릭구매 ) 을악용하는것이다. CSRF 동작방식 165
CSRF 공격은응용프로그램에인증된사용자의브라우저로부터악의적인 HTTP 요청을전송하는것으로, 공격대상사용자의승인없이트랜잭션을수행한다. 사용자가인증을요청하고이것이승인되면사용자의브라우저가대상응용프로그램에특정의미있는 HTTP 요청을보내는데, 응용프로그램은사용자가인증받는동안의요청이유효한트랜잭션혹은사용자에클릭한링크등에의한것인지알지못한다. 예를들자면 CSRF 를사용하면공격자는공격대상자가의도하지않은웹사이트의취약점을통한로그아웃, 상품구매, 계좌정보변경, 그외많은기능을수행할수있다. 다음은티켓판매자가여러장의티켓을구매하는 HTTP POST 의예다. POST http://ticketmeister.com/buy_ticket.htm HTTP/1.1 Host: ticketmeister User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O;) Firefox/1.4.1 Cookie: JSPSESSIONID=34JHURHD894LOP04957HR49I3JE383940123K ticketid=athx1138&to=po BOX 1198 DUBLIN 2&amount=10&date=11042008 티켓판매자의응답에서는티켓의구매를승인한다. HTTP/1.0 200 OK Date: Fri, 02 May 2008 10:01:20 GMT Server: IBM_HTTP_Server Content-Type: text/xml;charset=iso-8859-1 Content-Language: en-us X-Cache: MISS from app-proxy-2.proxy.ie Connection: close <?xml version="1.0" encoding="iso-8859-1"?> <pge_data> Ticket Purchased, Thank you for your custom. 166
</pge_data> 잠재적으로취약한코드를발견하는방법 이문제는쉽게발견할수있으나, CSRF 공격시도를하면사용자에게경고를띄우는등의응용프로그램에보조적인기능을넣으면된다. 응용프로그램은형식을잘갖춘 HTTP 요청을받고그요청이어떤응용프로그램의비즈니스로직을충실히따르기만하면, CSRF 공격이가능하다 ( 단공격대상자가공격을받을시스템에로그인되어있는경우.) 페이지렌더링을체크하여어떤고유식별자가사용자브라우저내의응용프로그램이생성한링크에추가되는지확인해야한다. HTTPS 요청시사용자와관련되어있는고유식별자가없다면취약한것이다. 세션 ID 는사용자가인증된상태에서악의적인링크를클릭하면다른곳으로전송되어버릴수도있기때문에충분하지않다. 트랜잭션 DRIVE THRU' 눈에는눈, 요청에는요청응용프로그램이 HTTP 요청을수신하면애플리케이션이실행하지않고, 사용자의패스워드에대해서다른요청으로응답하는애플리케이션으로언제트랜젝션요청이보내졌는지를평가하기위해비즈니스로직을분석해야한다. Line 1 String actiontype = Request.getParameter("Action"); 2 if(actiontype.equalsignorecase("buystuff"){ 4 Response.add("Please enter your password"); 5 return Response; 6 } 위의 pseudo 코드에서는, HTTP 트랜잭션요청이수신되는지, 또응용프로그램이이를확인하기위해사용자 요청에응답하는지분석할수있다 ( 이경우에는패스워드재입력 ). 아래보이는흐름도는 CSRF 에대응하기위한트랜잭션관리도이다. 167
CSRF 에취약한패턴 HTTP 요청을검증하는제어기능이없이인증된사용자로부터의 HTTP 요청을수용하는모든응용프로그램은 사용자세션에만의존한다 ( 대부분의웹응용프로그램!!). 해당사용자가이미인증됨에따라, 악의적인 HTTP 요청에는유효한세션 ID 를포함하므로세션 ID 는여기에서다루는문제는아니다. CSRF 에대응하기위한좋은패턴및프로시저 세션쿠키만으로유효한요청을확인하는것이충분하지않기때문에애플리케이션으로보낸모든 HTTP 요청에고유식별자가전송되었는지확인할필요가있다. CSRF 요청은유효한고유식별자를갖고있지않지때문에링크, 버튼클릭을하면페이지의숨겨진필드에고유한 ID 를만들어 HTTP 요청에추가시킨다. 공격자는페이지와링크에서동적으로무작위로생성되는고유한 ID 에대하여알고있지못할것이다. 1. 사용자에게페이지를전달하기전에어떤목록이검증되어야한다. 이목록에는주어진페이지의모든링크에대해서생성된모든고유 ID 를포함하고있다. 168
2. 고유 ID 는사용자에게보여지는요청된페이지에서각각의링크와폼에서추가된다. 3. 사용자세션의고유 ID 의목록을유지관리하고, 애플리케이션에서 HTTP 요청의고유 ID 가유효한것인 지를확인한다. 4. 고유 ID 가제공되지않는다면사용자세션을종료하고사용자에게오류메세지를보여준다. 사용자상호작용 자금이체와같은트랜잭션발생시, 트랜잭션이발생하기이전에누군가의패스워드입력과확인을요구하는 것과같이사용자에게부가적인의사결정을요구한다. CSRF 공격자는사용자의패스워드를알수는없기 때문에 CSRF 공격을통해트랜잭션이발생하지않는다. 169
로깅을위한코드리뷰 요약 로깅은누가언제어떤행위를했는지저장장치에정보 ( 감사기록 ) 를기록하는것이다. 로깅은또한개발기간동안개발된디버그메시지및응용프로그램내문제점을반영하는모든메시지를처리할수있다. 이는응용프로그램을사용하는것을추적하기위해사업상중요하게생각되는모든것을감사할수있다. 로깅은다른보안기능들이정확하게작동하는지확인하는탐지방법을제공한다. 로그에는응용프로그램, 운영체제, 보안소프트웨어등세개의영역이있다 ; 모든로깅원리는일반적으로비슷하다. 이문서는응용프로그램로그에대하여특별히적용된다. 좋은로깅정책에는로그생성, 저장장치, 보호, 분석과보고가포함되어야한다. 로그생성 최소한다음과같은이벤트는로그를생성해야한다. 인증 : 성공및실패시도 승인요청 날짜변경 : 응용프로그램에서수행하는생성, 변경, 삭제행위 세션활동 : 종료 / 로그아웃이벤트 응용프로그램은예기치못한오류나애플리케이션의상태모델을거부하는것과같은이벤트와같은악의적인사용을기록하고검출할수있다. 예를들면권한없는데이터에접근하려고시도하는사용자와검증을거치지않은규칙, 혹은입력데이터조작이이에해당한다. 일반적으로는응용프로그램로직을우회하고자하는사용자의시도에의해발생하는모든오류상태를탐지해야한다. 로깅은사용자활동에대한감사추적을구성하는데필요한정보를제공해야한다. 그래서수행된날짜 / 시간행위는유용하지만, 애플리케이션은일반적인시간소스와동기화된시계를사용한다. 로깅기능에는특수하거나민감한시간이적용되어서는안된다. 예를들면애플리케이션이 HTTP GET 을허용하는경우 URL 과 GET 의페이로드가기록되어야한다. 이는중요로깅데이터의결과값이된다. 로깅은정보의최대길이, 악성문자등데이터검증에대한모범사례를따라야한다. 로그기록기능은합리적인길이의로그메시지만로깅하고, 이길이를적용할수있도록해야한다. 또한로그는사용자입력을직접적으로기록해서는안되며, 이를검증하고기록해야한다. 170
로그저장로그기록을보호하고로그파일의크기를관리할수있도록하기위해로그순환을권장한다. 로그순환은첫번째파일이완료되었거나너무커졌을때로그파일을닫고새로운로그를오픈하는것을의미한다. 로그순환은일반적으로스케쥴링에의해실시되거나 ( 일일 ) 파일크기가특정크기에도달하면수행된다. 로그보호 로그는사용자계정과다른민감한정보를포함하기때문에정보보안의세가지핵심인기밀성, 무결성, 가용성이 손상되지않도록보호할필요가있다. 로그분석및보고로그분석은사소한이벤트에대한로그기록을제한하거나흥미로운이벤트를찾기위한연구이다. 로그보고는로그분석을표시하는방식을의미한다. 시스템관리자의일상적인책임이더라도응용프로그램은반드시지속적으로로그를생성해야하고, 관리자가기록의우선순위를정하는로그도생성해야한다. 로깅은혼동을피하기위해시스템이벤트의감사와, GMT 기반의타임스탬프를함께생성해야한다. 생성 (Create), 변경 (Update), 삭제 (Delete) 와같은그트랜잭션이벤트를검토하는과정에서데이터전송과같은비즈니스실행, 보안이벤트는기록되어야한다. 일반적인오픈소스로깅솔루션 Log4J: Log4net: Commons Logging: http://logging.apache.org/log4j/docs/index.html http://logging.apache.org/log4net/ http://jakarta.apache.org/commons/logging/index.html Tomcat(5.5) 에서자체로깅솔루션 (log4j) 이없다면, Commons Logging 로그하도록한다. 이로그는 catalina.out 파일에기록된다. 라이브러리를통해모든것을 catalina.out 은무한대로확장되며재활용하거나이월시키지않는다. Log4j 는 이월 (Rollover) 기능이있으며, 이기능으로로그의크기를제한한다. Log4j 는또한 port, syslog, 데이터베이스, JMS 등과같은다른곳으로로그데이터전송하는추가기능이있다. 실제로그에참고할수있는 log4j 의 log4j.properties 파일부분이다. # 171
# Configures Log4j as the Tomcat system logger # # # Configure the logger to output info level messages into a rolling log file. # log4j.rootlogger=info, R # # To continue using the "catalina.out" file (which grows forever), # comment out the above line and uncomment the next. # #log4j.rootlogger=error, A1 # # Configuration for standard output ("catalina.out"). # log4j.appender.a1=org.apache.log4j.consoleappender log4j.appender.a1.layout=org.apache.log4j.patternlayout # # Print the date in ISO 8601 format # log4j.appender.a1.layout.conversionpattern=%d [%t] %-5p %c - %m%n # # Configuration for a rolling log file ("tomcat.log"). # 172
log4j.appender.r=org.apache.log4j.dailyrollingfileappender log4j.appender.r.datepattern='.'yyyy-mm-dd # # Edit the next line to point to your logs directory. # The last part of the name is the log file name. # log4j.appender.r.file=/usr/local/tomcat/logs/tomcat.log log4j.appender.r.layout=org.apache.log4j.patternlayout # # Print the date in ISO 8601 format # log4j.appender.r.layout.conversionpattern=%d [%t] %-5p %c - %m%n # # Application logging options # #log4j.logger.org.apache=debug #log4j.logger.org.apache=info #log4j.logger.org.apache.struts=debug #log4j.logger.org.apache.struts=info 로깅에취약한패턴의예.NET 173
다음문제는개발팀이나운영팀에질문을제기하거나조심해야할부분이다. 로깅과감사는사기를방지하기위한탐지방법이다. 업계에서로깅을상당히간과하고있어공격자가들키지않고지속적으로사기행각을벌일수있도록한다. 로깅은윈도우와.Net 이슈까지다룬다 : 다음사항을확인한다 : 1. 윈도우네이티브로그는모든로그기록에타임스탬프값을삽입한다. 2. GMT 는디폴트시간대로설정되어있다. 3. 윈도우운영체제는네트워크타임서버를사용하도록설정할수있다. 4. 기본적으로이벤트로그는이벤트를발생시킨컴퓨터의이름및뷰어의소스필드상의응용프로그램을보여준다. 그밖의요청식별자정보, 사용자명, 목적지와같은추가정보는오류이벤트의본문에포함되어야한다. 5. 민감하거나비즈니스적으로중요한정보는응용프로그램로그에보내지않는다. 6. 응용프로그램로그는웹루트디렉토리에위치시키지않는다. 7. 로그정책은로그심각레벨에따라다르게적용한다. 이벤트로그쓰기.Net 코드를리뷰하는과정에서이벤트로그객체호출과정에서비밀정보를제공하지않아야한다. EventLog.WriteEntry( "<password>",eventlogentrytype.information); 클래식 ASP 웹서버로그사용을위해, 웹서버로그또는윈도우로그에이벤트를추가할수있다. Response.AppendToLog("Error in Processing") 다음은일반적으로윈도우이벤트로그에엔트리를추가하는방법이다. Const EVENT_SUCCESS = 0 Set objshell = Wscript.CreateObject("Wscript.Shell") 174
objshell.logevent EVENT_SUCCESS, _ "Payroll application successfully installed." ASP.NET 의모든이전의기능도대부분클래식 ASP 에적용가능하다. 175
세션무결성을위한코드리뷰 소개 쿠키는세션상태를유지하기위해사용될수있다. 쿠키는응용프로그램을사용하는동안사용자를식별한다. 세션 ID 는사용자식별할때자주사용하는방법이다. 안전한 세션 ID 는최소 128 비트길이로해야하고임의적으로생성되어야한다. 쿠키또한사용자를식별하는데사용될수있는데, 이경우쿠키를사용할때주의해야한다. 쿠키를사용하여 SSO(Sing Sign on) 솔루션을구현하는것을추천하지않는다. 왜냐하면쿠키가이용도로개발되지않았기때문이다. 영구적인쿠키는사용자의하드디스크에저장되며, 쿠키에정의된만료날짜에따라유효하다. 다음은쿠키와관련된코드를리뷰할때의포인트이다. 잠재적으로취약한코드를찾는방법 쿠키객체가세션 ID 확인과는다른다양한속성들로설정된다면, 쿠키는 HTTPS/SSL 로만전송되도록설정된다. 자바에서는다음메소드를통해실행된다. cookie.setsecure() (Java) cookie.secure = secure; (.NET) Response.Cookies("CookieKey").Secure = True (Classic ASP) HTTPONLY 쿠키 이는 IE6 이상에서사용한다. HTTPOnly 쿠키는사용자측스크립트가쿠키에접근하지않도록하여 XSS 에대한 보호기능을제공한다. 이방법은좋지만, 완벽한것은아니다. cookie.httponly = true (C#) 쿠키는 ASP.NET 을통해서만접속해야한다. HTTPOnly 속성은클래식 ASP 페이지에서는지원되지않는다. 쿠키도메인제한 쿠키는 example.com 과같은한도메인에제한된다는것을이해해야한다. 즉, 쿠키는 example.com 과관련이 있다. 만약쿠키가다른도메인과연결되어있다면, 다음코드는이를수행한다 : 176
Response.Cookies["domain"].Domain = "support.example.com"; (C#) Response.Cookies("domain").Domain = "support.example.com" (Classic ASP) 리뷰하는동안, 쿠키가하나이상의도메인에할당된다면, 이를기록하고왜이렇게되는지의문을제기해라. 쿠키에서얻은데이터를사용자에게보여주기쿠키로부터사용자에게보여지는데이터가 HTML 인코딩되는지확인해야한다. 이렇게하면몇가지형태의크로스사이트스크립팅취약점을예방할수있다. LabelX.Text = Server.HtmlEncode(Request.Cookies["userName"].Value); (C#) Response.WriteServer.HtmlEncode (Request.Cookies("userName")) (Classic ASP) Session Tracking/Management Techniques HTML 숨겨진필드 HTML 숨겨진필드는세션을추적하는데사용할수있다. 각각의 HTTP POST 요청마다, hidden 필드는서버로 전달되어사용자를확인한다. 형식은다음과같다. <INPUT TYPE="hidden" NAME="user" VALUE="User001928394857738000094857hfduekjkksowie039848jej393"> 서버측코드는사용된값이유효한지확인하기위해 VALUE 의유효성을확인하는데사용된다. 이와같은 방법은 POST/Form 요청에만사용할수있다. URL 덮어쓰기 URL 덮어쓰기는 URL 마지막에사용자와관계된고유한 ID 를첨부함으로서세션을추적하는방법이다. <A HREF="/smackmenow.htm?user=User001928394857738000094857hfduekjkksowie039848jej393">Click Here</A> 세션관리 / 무결성에대한중요한예제패턴 HTTPOnly Cookie: 사용자측스크립트를통한쿠키접근을예방한다. 모든브라우져가이것을지원하지는않는다. 유효한세션검사 모든 HTTP 요청에대해, 프레임워크는 HTTP 요청 ( 세션 ID 를통한 ) 에관계된사용자가유효한지를확인해야만 한다. 177
인증성공 로그인이성공하면사용자에게새로운세션식별자를발행해야만한다. 구세션 ID 는무효화되어야한다. 이렇게 하면세션고정공격을방지하고브라우저가여러사용자에게동일한세션 ID 를공유하는것을방지한다. 세션 ID 는각브라우져별로다르고, 브라우져가살아있는동안은유효하다. 로그아웃 이또한왜로그아웃버튼이중요한가라는생각으로연결된다. 로그아웃버튼이선택되었을때우리는사용자 세션 ID 를파기해야만한다. 관련문서 http://www.owasp.org/index.php/category:owasp_cookies_database http://msdn2.microsoft.com/en-us/library/ms533046.aspx http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/servlet/http/cookie.html 178
경쟁상태를위한코드리뷰 소개 경쟁상태는 ( 대다수보안이슈와마찬가지로 ) 일부코드가정상적으로동작하지않을때발생한다. 경쟁상태는예기치않은이벤트순서의결과로나타나며, 이로인해코드의유한상태머신이 알수없는상태 로변경되거나, 동일자원에서한개이상의쓰레드가경쟁하는결과가발생한다. 동일한메모리나데이터상에서의다중쓰레드가실행되면무결성문제가발생할수있다. 동작방식 동일한자원을사용하는경쟁작업에서는자원이 Step-lock 상태가아니거나세마포어와같이토큰기반의다중사용자시스템상태가되기때문에쉽게경쟁상태가될수있다. ( 쓰레드 1, T1) 과 ( 쓰레드 2, T2) 2 개의프로세스가있다고가정하고문제가되는코드의 integer X 에 10 을더한다. X 의초기값은 5 이다. X = X + 10 따라서멀티쓰레드환경에서이코드에별도의통제기능이없을경우다음과같은문제가발생한다 : T1 이 Thread 1 의레지스터 X 가된다. T2 가 Thread 2 의레지스터 X 가된다. T1 에 10 을더해 T1 의레지스터가 15 가된다. T2 에 10 을더해 T2 의레지스터가 15 가된다. T1 의레지스터값 (15) 가 X 로저장된다. T1 의레지스터값 (15) 가 X 로저장된다. 초기값 5 에각쓰레드별로 10 을더해야하기때문에실제값은 25 가되어야하지만 T2 가 X 값을가져오기 전에 T1 이 X 로저장되어실제값은 15 가된다. 잠재적인취약한코드를확인하는방법.NET 멀티쓰레드환경을사용하는코드는다음과같다 : 179
Thread System.Threading ThreadPool System.Threading.Interlocked 자바 java.lang.thread java.lang.runnable start() stop() destroy() init() synchronized wait() notify() notifyall() 클래식 ASP 멀티쓰레드는클래식 ASP 에서는직접지원되지않기때문에 COM 객체를사용할때만경쟁상태가존재한다. 경쟁상태에대한취약한패턴 180
정적메소드 ( 객체당하나가아닌클래스당하나 ) 는다중쓰레드에서공유상태일경우특히문제가된다. 예를들어, 아파치에서는특정요청에대한정보를저장하는데스트럿츠정적멤버를사용하면안된다. 동일한클래스의경우다중쓰레드를사용할수있으며, 정적멤버의값은보증할수없다. 클래스인스턴스는오퍼레이션 / 요청별로만들어지기때문에쓰레드가안전할필요는없다. 정적상태는반드시쓰레드가안전해야한다. 1. 정적변수를참조하는값은반드시쓰레드잠금상태가되어야한다. 2. {} 로끝나지않는곳의잠금을해제하면문제가발생할수있다. 3. 정적상태를알려주는정적메소드 관련문서 http://msdn2.microsoft.com/en-us/library/f857xew0(vs.71).aspx 181
추가적인보안고려사항 다음절에서는데이터베이스설정이나개발시발생할수있는특정언어에서발생하는실수와같은여러가지보안고려사항을다룬다. 코드를리뷰할때확인해야할부분이나올바른방식으로사용하는방법에대한조언을포함하고있으며, 코드개발시발생할수있는주요이슈를모아놓은 OWASP 코드리뷰 Top 10 툴에해서도설명한다. 182
자바의지저분한것들 등호 객체등호는 == 연산자를사용하여시험되며, 값등호는.equals(Object) 메소드를사용하여시험한다. 예 : String one = new String("abc"); String two = new String("abc"); String three = one; if (one!= two) System.out.println("The two objects are not the same."); if (one.equals(two)) System.out.println("But they do contain the same value"); if (one == three) System.out.println("These two are the same, because they use the same reference."); 출력값은 : The two objects are not the same. But they do contain the same value These two are the same, because they use the same reference. 물론, 다음경우는다르다 : String abc = "abc" and String abc = new String("abc"); 예를들면, 다음코드를보라 : String letters = "abc"; String moreletters = "abc"; System.out.println(letters==moreLetters); 183
출력값은 : true 이는컴파일러와런타임효율성때문이다. 컴파일된클래스파일에서는 abc 데이터의한세트만저장된다. 이러한상황에서는한개의객체만생성되며, 이객체의값은 true 가된다. 그러나다음을고려하라 : String data = new String("123"); String moredata = new String("123"); System.out.println(data==moreData); 출력값은 : False 123 데이터의한세트가클래스에저장되더라도런타임시에는다르게처리된다. String 객체를생성하기위해명시적으로인스턴스화한다. 그리므로, 이러한경우두개의객체가생성되기때문에값은 false 가된다. == 은항상객체의항등의의미로사용되고객체의값은참조하지않는다. 보다 의미있는 비교를확인하려면항상.equals 을사용한다. 불변객체 / 래퍼클래스의캐싱자바 5 에래퍼클래스캐싱이소개된이후, 다음과같이정수캐시에있는내부클래스인 IntegerCache 에의해생성된캐시를확인할수있다. 예를들면다음코드는캐시를생성한다 : Integer mynumber = 10 or Integer mynumber = Integer.valueOf(10); 정수배열에모두저장되어있는 -128 에서 127 사이의범위에서 256 개의정수객체가생성된다. 이캐싱기능은 정수에서발견된내부클래스인 IntegerCach 를보면확인할수있다 : private static class IntegerCache { 184
private IntegerCache(){} static final Integer cache[] = new Integer[-(-128) + 127 + 1]; static { for(int i = 0; i < cache.length; i++) cache[i] = new Integer(i - 128); } } public static Integer valueof(int i) { final int offset = 128; if (i >= -128 && i <= 127) // must cache { return IntegerCache.cache[i + offset]; } return new Integer(i); } 따라서 Integer.valueOf 를사용하여객체를생성하거나 -128 에서 127 사이의정수에값을직접할당할경우 같은객체가반환된다. 다음예제를참조하라 : Integer i = 100; Integer p = 100; if (i == p) System.out.println("i and p are the same."); if (i!= p) System.out.println("i and p are different."); if(i.equals(p)) System.out.println("i and p contain the same value."); 185
출력값은 : i and p are the same. i and p contain the same value. 객체 i 와 p 는같은객체이기때문에 true 가되며, 값이아니라객체등호에기반하여비교된다. 정수 i 와 p 가 - 128 에서 127 사이에있지않을경우캐시를사용하지않고새로운객체를생성하며, 값을비교할때는항상.equal 메소드를사용해야한다. 정수예시에서는이캐시를생성하지않는다. 다음예제를참조하라 : Integer i = new Integer (100); Integer p = new Integer(100); if(i==p) System.out.println( i and p are the same object ); if(i.equals(p)) System.out.println( i and p contain the same value ); 이러한환경에서의출력값은 : i and p contain the same value == 은항상객체등호에사용되며, 꺼내지지않은값을비교하기위해오버로딩되지않는다. 자바언어스펙 5.1.7 절에서관련문서를참조할수있다. 이에따르면 : 박스안의 p 값이 true, false, a byte, /u0000 에서 /u007f 사이의 char 나 -128 에서 127 사이의 int 또는 short number 일경우 p 의 2 개의박싱형변환은 r1 과 r2 가된다. r1 과 r2 는항상 r1==r2 이다. 이캐싱메커니즘에는다른와퍼클래스 (Byte, Short, Long, Character) 가포함되어있다. Byte, Short, Long 에는정수객체와동일한캐싱원칙이포함되어있다. 캐릭터클래스캐시는 0 에서 127 까지이다. 캐릭터래퍼에는음의캐시가생성되지않으며, Float 객체는캐시가없다. BigDecimal 도캐시를사용하지만다른메커니즘을사용한다. 다른객체에캐싱을위해내부클래스를포함하고있으면 BigDecimal 은 True 가아니다. 캐싱은정적배열에사전정의되어있으며, 0 에서 10 까지 11 개의숫자를커버한다 : // Cache of common small BigDecimal values. private static final BigDecimal zerothroughten[] = { new BigDecimal(BigInteger.ZERO, 0, 0), new BigDecimal(BigInteger.ONE, 1, 0), 186
new BigDecimal(BigInteger.valueOf(2), 2, 0), new BigDecimal(BigInteger.valueOf(3), 3, 0), new BigDecimal(BigInteger.valueOf(4), 4, 0), new BigDecimal(BigInteger.valueOf(5), 5, 0), new BigDecimal(BigInteger.valueOf(6), 6, 0), new BigDecimal(BigInteger.valueOf(7), 7, 0), new BigDecimal(BigInteger.valueOf(8), 8, 0), new BigDecimal(BigInteger.valueOf(9), 9, 0), new BigDecimal(BigInteger.TEN, 10, 0), }; 위에서언급한자바언어스팩 (JLS) 에따르면값은변하지않는래퍼객체에저장된다. 이캐싱은해당값이나 객체가자주사용된다는가정하에생성되었다. 증가값 후 - 증가연산에유의하라 : int x = 5; x = x++; System.out.println( x ); 출력값은 : 5 할당값이증가되기전즉증가후에완료된다. 증가전 (pre-increment) 을사용하면할당전에값을업데이트한다. 예 : int x = 5; x = ++x; System.out.println( x ); 187
출력값은 : 6 가비지콜렉션무효화시키는 finalize() 메소드사용하면, 소멸자 (destructor) 와동일한개념으로원하는코드를정의할수있다. 다음은꼭기억해야할점이다 : "finalize()" 는가비지콜렉터로한번만호출된다. finalize() 가호출된다고보장할수없다. 즉객체가비지가수집될수있다. 무효화시키는 finalize() 를통해객체가삭제되는것을방지할수있다. 예를들면, 객체의레퍼런스를 다른객체로전달한다. 가비지콜렉션의동작은 JVM 에따라차이가있다. 불린 (Boolean) 할당 누구나자바에서 == 와 = 의차이점을인지하고있지만오타나실수를하기도하고또이는대부분컴파일러 에서인식한다. 하지만아래사항을고려하라 : boolean thetruth = false; if (thetruth = true) { System.out.println("theTruth is true"); } else System.out.println("theTruth is false;"); } 할당표현식의결과는할당에대한변수의값이다. 따라서위의결과는항상 thetruth is true 가된다. 이는 불린에만적용되며, 아래예제에서는컴파일되지않기때문에컴파일러에서확인할것이다 : 188
int i = 1; if(i=0) {} i 와정수를 0 과비교하여 (i=0) 대입의결과는 0 이된다. if 선언문때문에불린이예상된다. 조건 else if 집합을주의하고, 다음코드예제를참조하라 : int x = 3; if (x==5) {} else if (x<9) { System.out.println("x is less than 9"); } else if (x<6) { System.out.println("x is less than 6"); } else { System.out.println("else"); } Produces the output: x is less then 9 두번째 else if 가 true 와같더라도 else if 가성공하면나머지조건은처리되지않는다. 189
자바개발시주요보안사례 소개 이절에서는자바애플리케이션과자바코드개발시주요보안프랙티스인주요자바중심의영역에대한내용을 포함하고있다. 자바코드의코드리뷰를할때다음사항을확인해야한다. 개발자는최신보안프랙티스를 적용함으로써모든코드에기본보안기능을포함한 자기방어코드 를적용할수있다. 클래스접근 1. 메소드 2. 필드 3. 변형가능객체 간단하게설명하면, 꼭필요한경우가아니면클래스에 public 필드나메소드를포함시키지않도록한다. Private 하지않은모든메소드, 필드, 클래스는잠재적인공격경로로악용될수있기때문에접근자를제공하여 접근성을제한할수있습니다. 초기화생성자 (constructor) 를호출하지않고객체를할당할수있다. 객체를만들기 (instantiate) 위해생성자를호출하지않아도되며, 초기화되지않은객체를할당하는방법도많이있기때문에초기화에너무치중할필요는없다. 1. 클래스가어떤기능수행하기전에초기화되었는지확인해야한다. 초기화되었을때 TRUE 로설정한불린을추가하고 private 으로만든다. 필요하다면모든비-생성자메소드에의해확인할수있다. 2. 모든변수를 private 으로만들고 setters/getters 를사용한다. 3. 정적변수를 private 으로만들다. 이렇게하면초기화되지않은변수로의접근이제한된다.. FINALITY Final 이아닌클래스는공격자가악의적인목적으로클래스를확장할수있다. 응용프로그램의 USER 객체는 설계상확장될수없기때문에이클래스에 Final 로구현하면악성코드로인해 User 클래스를확장하는것을 190
방지할수있다. Final 이아닌클래스는이유가있을때만사용해야한다. 확장을위해서가아니라, 필요할때만 클래스의확장성을활성화해야한다. 범위패키지범위를사용하면다른프레임워크의클래스를재사용하더라도응용프로그램네이밍에충돌이발생하지않는다. 패키지는디폴트로열려있고봉인되어있지않아악의적인클래스가추가될수도있다. 패키지에악의적인클래스가추가된다면보호된필드의범위에보안에문제가생길수있다. 디폴트로퍼블릭, 프라이빗으로선언되지않은모든필드와메소드는보호되며같은패키지내에서만접근이가능하다. 보안을이유로이기능을사용하면안된다. 내부클래스간단히말하면, 바이트코드로바뀌면내부클래스는같은패키지의외부클래스로 변경 된다. 이는패키지내의모든클래스가이내부클래스에접근할수있다는의미이다. Owner/enclosing/father 클래스의프라이빗필드는외부의내부클래스로접근이가능하기때문에보호필도로변경된다. 하드코딩 패스워드, 사용자 ID 등을하드코딩하지마라. 이는좋지않은설계로디컴파일될수있는위험이있다. 디플로이먼트트리의안전한디렉터리에저장하라. 복제가능성필요하지않으면, 클래스가복제될수없도록클론메소드를못쓰게해야한다. 클로닝은공격자가클래스생성자를실행하지않고도클래스를사용할수있도록한다. 각클래스에다음과같이메소드를정의하라 : public final Object clone() throws java.lang.clonenotsupportedexception { throw new java.lang.clonenotsupportedexception(); } 클론이필요할경우, final 키워드를사용하여오버라이딩이되지않는클론메소드를만들수있다 : public final void clone() throws java.lang.clonenotsupportedexception { super.clone(); 191
} SERIALIZATION/DESERIALIZATION 직렬화 (Serialization) 는 JVM 이 꺼졌을때 객체를저장하는데사용할수있다. 직렬화는객체를쪼개어바이트스트림으로저장한다. 직렬화는공격자가객체의내부상태및프라이빗속성을볼수있도록한다. 객체의직렬화를방지하려면객체에다음코드를추가해야한다. private final void writeobject(objectoutputstream out) throws java.io.ioexception { throw new java.io.ioexception("object cannot be serialized"); } writeobject() 메소드는직렬화절차를시작하는메소드이다. 예외처리하고 final 로만들기위해이메소드를오버라이드함으로써, 객체는직렬화될수없다. 객체의직렬화가발생하면, 일시적으로데이터가드롭된다. 따라서중요정보를 tagging 하여직렬화공격으로부터보호하라. 비직렬화 (Deserialization) 는바이트스트림이정상적인클래스처럼보이도록객체를조합하는데사용할수있다. 비직렬화는공격자가객체의상태를확인하는데사용될수있으며, 객체직렬화와마찬가지로비직렬화는메소드콜 readobject() 를오버라이딩하여예방할수있다. private final void readobject(objectinputstream in) throws java.io.ioexception { throw new java.io.ioexception("class cannot be deserialized"); } 192
클래식 ASP 개발시주요보안사례 개요 클래식 ASP 페이지에는전통적으로내려오는몇가지보안이슈가존재한다. 이번장에서는초급자가실수 하거나잘못된코드에대해서설명하고자한다. 다음예제를통해주요보안이슈가무엇인지확인할수있을 것이다. 모든예제는 ASP 테스트를통해실제발견된사례들이다. ASP 페이지실행순서문제 먼저, ASP 페이지에서의프로세싱레벨에대해설명하고자한다. ASP 페이지는다음의절차에따라실행된다 : 1. 서버측 Includes. 우선인터프리터가현재파일에 include 문의모든파일의텍스트를추가하고하나의 파일인것처럼처리한다. 2. 서버측 VBScript 코드. 그리고 <% and %> 내부의 VBScript 가실행된다. 3. 클라이언트측 JAVA 스크립트 /VBScript 코드. 마지막으로브라우저에서페이지가로드되면자바 스크립트코드가실행된다. 당연한이야기이겠지만, 이순서를준수하지않을경우심각한보안문제가발생할수있다. 다음은예제다. 잘못된파일동적포함 <% If User = "Admin" Then %> <!--#include file="adminmenu.inc"--> <% Else %> <!--#include file="usermenu.inc"--> <% End If 193
%> 이코드는 ASP 페이지에두개파일의컨텐츠를추가한다 ; 서버측 Includes 가먼저실행된후 ASP 코드가 실행된다. If 문에따라페이지가정상적으로표시될수도있지만모든코드가처리될것이다 ; 이로인해경쟁 상태이나원하지않는함수실행이발생할수있다. HTML 및자바스크립트코멘트는 ASP 코드에서반드시실행된다 <!-- <%= "Debug: This is the DB user: " & DBUserName %> --> <script type="text/javascript"> var x = 'Hello, '; //<%= "Debug: This is the DB password: " & DBUserPassword %> alert (x + "Juan"); </script> ASP 를잘다루는개발자는위예제가어떤결과를낳을지쉽게알수있겠지만상당수의개발자들은최종 결과가어떨지알기어렵다. <!-- Debug: This is the DB user: SA --> <script type="text/javascript"> var x = 'Hello, '; //Debug: This is the DB password: Password alert (x + "Juan"); </script> 위예제는주석코드의중요정보가 HTML 또는자바스크립트코멘트로노출되는것을보여준다. 자바스크립트사용하여 ASP 기능사용하기 물론, 이것은불가능하지만, 좀더알아봐야한다. <script> 194
var name; name = prompt ("Enter your UserName:"); <% If name!= "user" Then 'The user is an admin Role = "Admin" Else Role = "User" End IF %> <script> 위코드는매번로그인한사용자에게 Admin 권한을부여한다. 앞에서보았듯이 ASP 코드가먼저실행된다. 또한자바스크립트와 ASP 코드사이의변수는공유되지않는다. 다른예제 : <%@ Language=VBScript %> <script type="text/javascript"> if (confirm('go to yahoo?')){ <% response.redirect "http://www.yahoo.com/" %> }else { <% response.redirect "http://www.altavista.com/" %> } </script> 항상야후로접속되며, 프롬트는절대표시되지않는다 ; <% %> 안의코드가먼저실행된다. 195
RESPONSE.END 로실행중지 본문장이없는상태에서는종료시점에원하지않는코드가실행될수있다. <% If Not ValidInfo Then %> <script> alert("information is invalid"); location.href="default.asp"; </script> <% End if Call UpdateInformationFunction() %> 위예제에서, ASP 코드가먼저실행되고그뒤에자바스크립트가실행되었기때문에 ValidInfo 변수의값과상관없이 UpdateInformationFunction 이항상호출된다. ASP 코드가서버에서실행되고출력값이브라우저로전송된후자바스크립트가실행된다. 따라서서버측의실행을중지하려면 Response.End 가필요하다. 다른문제 MS 자바가상머신에있는자바클래스 이클래스들은 ASP 페이지에서호출될수있기때문에보안적으로안전하지않은지확인해야한다. <html><body> <% Dim date Set date = GetObject("java:java.util.Date") %> 196
<p> The date is <%= date.tostring() %> </body></html> 명시적으로옵션을사용하지않기 변수타입을잘못준경우비즈니스로직에서경쟁상태를발생시킬수있다. 이옵션은사용자에게사용된모든 변수를선언하게하며, 이로인해조금의성능부하가발생할수있다. ISCLIENTCONNECTED 속성 IsClientConnected 속성은마지막 Response.Write 이후클라이언트가서버로부터접속해제되었는지결정한다. 예기치않은접속해제후에도서버가긴페이지의나머지를실행하는것을방지하는데유용하다. 서버와 DB 에 대한 DoS 공격을방지하는데매우유용한속성이다. 197
PHP 개발시주요보안사례 전역변수항상전역변수를명시적으로생성할필요는없다. 명시적으로전역변수를사용하기위해서는 php.ini 파일에있는 "register_globals " 를 on 으로활성화하면된다. PHP 4.1.0 부터 register_globals 의기본값은비활성이다. register_globals 가활성화되었다면, PHP 안에 include 지시어는보안에취약할수있다. <?PHP include "$dir/script/dostuff.php";?> register_globals 이활성화되면 $dir 변수는쿼리스트링을통해다음과같이입력전달될수있다.?dir=http://www.haxor.com/gimmeeverything.php 이것은 $dir 이아래와같이설정되는것과같다. <?PHP include "http://www.haxor.com/gimmeeverything.php";?> URL 에전역변수를추가하면인증을우회하는방법이될수도있다. <?PHP if(authenticated_user()) {$authorised=true; }if($authorised) { give_family_jewels() } 198
?> register_globals 이활성화된상태로페이지가요청받으면, 쿼리스트링안에있는매개변수?authorised=1 는인증기능이사용자가수행할권한이있다고가정한다. register_globals 이활성화되지않으면, 변수 $authorised 는매개변수 $authorised=1 의영향을받지않는다. 초기화 PHP 코드리뷰시, 예를들어 $authorised = false; 과같이초기값이기본적으로보안을준수하는상태인지확인 한다. 오류처리가능하다면, php.ini 를통한누가오류리포팅을오프했는지 "error_reporting" 이오프되었는지확인해야한다. E_ALL 이활성화되었는지확인해야한다. E_ALL 이활성화되면, 모든오류와경고가보고된다. display_errors 는프로덕션에서 off 로설정되어야한다. 파일조작 allow_url_fopen 는 php.ini 에서기본적으로활성화되어있다. 이것은 URL 이로컬파일로취급받도록허용 한다. 악성스크립팅이있는 URL 이포함되었을수도있고, 로컬파일처럼취급되는문제가있다. 문서루트에있는파일 문서루트에반드시 include 파일을저장해야하며, *.inc 파일에직접접근하지못하도록해야한다. 검토도중 *.inc 파일을문서루트에서발견했을경우, http.conf 파일에다음과같이설정되어있는지확인해야한다. <Files"\.inc"> Order allow, deny deny from all </Files> HTTP 요청처리 Dipatch 메소드는모든요청이지나가는 깔때기 로사용된다. 어떤요청도 PHP 에파일에직접접근할수 없으므로, dispatch.php 를거쳐야한다. 모든트래픽이지나가는글로벌입력검증클래스와유사하다. 199
http://www.example.com/dispatch.php?fid=dostuff 보안에관해서는보통이파일의상단에검증부분을구현하게된다. 다른필요한모듈들은다른디렉토리에 include( 또는 require) 를사용할수있다. 메소드포함하기 : dispatch.php 메소드가사용되지않는경우, 각 php 파일상단의 include 를찾아야한다. Include 메소드는상태를설정하여요청을진행시킬수있다. PHP.ini 를확인하고 auto_prepend_file 지시자를찾는것도아이디어가될것이다. 이는모든파일을자동적으로 include 해서참조하는방식이다. 양성입력값검증 입력값검증 : strip_tags(): 문자열에서오는모든 HTML 태그를제거한다. nl2br(): 새로운라인의문자를 HTML 줄바꿈 "br 로변환한다. htmlspecialchars(): 특수문자를 HTML 엔터티값으로변환한다. 200
문자열과정수 소개 : 문자열 (String) 은 C 또는 C++ 에서형식으로정의되어있지않고, 널 (\0) 문자로끝나는간단한연속적인배열로정의되어있다. 문자열의길이는널문자앞까지의총개수이다. C++ 은이러한기능을가지고있는 std::basic_string 및 std::string 같은템플릿클래스를포함하고있다. 이클래스들은몇몇보안문제를해결할수있지만전부는해결하지못한다. W E L C O M E \0 일반적인문자열오류일반적인문자열오류는구현하면서실수하는것으로, 보안과가용성문제들이발생할수있다. C/C++ 에서는버퍼오버플로우와관련하여문자열형식이정의되지않기때문에자바나 C#.NET 프로그램언어에서제공하는편의성이없다. 일반적인문제는다음을포함한다.: 1. 입력값검증오류 2. 경계오류 3. 절단문제 4. 경계밖쓰기 5. 문자열종료오류 6. Off-by-one 오류 (OBOE) 위에서언급한몇몇문제는 Reviewing Code for Buffer Overruns and Overflows 부분에서소개되었다. 201
무한오류 문자열복사 길이제한없는자원에서고정된길이의문자배열로데이터가복사될때발생한다. void main(void) { char Name[10]; puts("enter your name:"); gets(name); <-- 여기서유저가입력한입력값의길이는 Name 배열의길이를초과할수있다.... } STRING 종료오류 널문자로종료하지않을경우시스템오류가발생한다. int main(int argc, char* argv[]) { char a[16]; char b[16]; char c[32]; strncpy(a, "0123456789abcdef", sizeof(a)); strncpy(b, "0123456789abcdef", sizeof(b)); strncpy(c, a, sizeof(c)); } 다음이사용했는지확인해야한다 : strcpy() 대신에 strncpy() 사용 202
sprintf() 대신에 snprintf() 사용 gets() 대신에 fgets() 사용 OFF BY ONE 오류 ( 배열을통한반복문을사용시배열과벡터는 0 부터시작하기때문에배열은 n-1 형식의반복문이되어야한다., 이것은 C/C++ 에서는적용되지않고, Java 및 C# 에서적용된다.) OFF BY ONE 오류는어떠한객체의내용을조작하기위해서객체에정보를복사또는추가하는반복적인기능을수행하는반복문에흔하게발생한다. OFF BY ONE 오류는반복문횟수에관한오류의결과이다. for (i = 0; i < 5; i++) { /* Do Stuff */ } 여기서 i 는 0 값으로시작하고, 그러면 1, 다음은 2, 3, 4 로증가한다. i 값이 5 가됐을때조건식 i<5 는거짓이므로반복문이종료하게된다. 조건식이 i<=5 (5 보다같거나작다 ) 이었다면, 의도하지않았지만반복문은 i 값이 6 이될때까지종료하지않았을것이다. 하나더적게반복해야하기때문에 0 대신에 1 부터횟수를새는것또한비슷한문제를발생할수있다. 이두문제는 OFF BY ONE 오류로반복문에서횟수미만또는초과와연관되어있다. 정수문제 정수오버플로우 정수가최대범위를넘어서증가되거나최소범위이하로감소될때오버플로우가발생한다. 오버플로우는 부호가있을수도있고없을수도있다. 오버플로우가부호비트로계속해서이어지면부호표시가되고, 표현하고자하는값이더이상정화하게표현되지않을때부호표시가안된다. int x; x = INT_MAX; // 2,147,483,647 203
x++; 여기서 x 의값은증가후에 -2,147,483,648 된다. 코드리뷰를할때오버플로우가발생하지않도록어떤조치사항이구현되었는지확인이필요하다. 이것은 절대로도달할수없는값 (2,147,483,647) 에의존하는것과는다른문제다. 이것은지원로직또는증가검사를통해수행할수있다. unsigned int y; y = UINT_MAX; // 4,294,967,295; y++; 여기서 y 값은증가후에 0 이된다. 위사항과같이부호없는 int 값이증가되면서다시 0 값으로돌아가는경우를발견할수있다. 전과마찬가지로, 이런경우가발생하지않도록예방하는보상할수있는보안기능이존재하는지점검해야한다. 정수변환 부호있는정수를부호없는정수로변환할때, 표현오류를방지하기위해서유의해야한다. int x = -3; unsigned short y; y = x; 여기서 y 는부호있는값에서부호없는값으로변환할때루프백효과때문에 65533 값이된다. 204
MYSQL 개발시주요보안사례 소개 코드리뷰의일환으로 MySQL 과같은데이터베이스의보안을평가하기위해코드리뷰이외의단계가필요할수 있다. 다음은그영역을다루는내용이다. 권한 Grant_priv: 사용자가다른사용자에게권한을부여하는것을허용한다. 이기능은 DBA 와데이터 ( 테이블 ) 소유자에대해서적절하게제한되어야한다. Select * from user where Grant_priv = 'Y'; Select * from db where Grant_priv = 'Y'; Select * from host where Grant_priv = 'Y'; Select * from tables_priv where Table_priv = 'Grant'; Alter_priv: 전역, 데이터베이스그리고테이블수준에서데이터베이스구조에대해접근해서변경할수있는 사람을결정한다. Select * from user where Alter_priv = 'Y'; 205
Select * from db where Alter _priv = 'Y'; Select * from host where Alter_priv = 'Y'; Select * from tables_priv where Table_priv = 'Alter'; MYSQL 설정파일 다음사항을점검한다. a)skip-grant-tables : 이옵션은서버가권한시스템을전혀사용하지못하게하는것이다. 모든사용자는모든테이블에접근할수있는권한을가진다. b)safe-show-database : SHOW DATABASES 명령어가실행될때, 이것은사용자가권한을가지고있는데이터베이스만을반환한다. MySQL v4.0.2. 이후로기본설정이다. c)safe-user-create : 이것이활성화되면, 사용자가 mysql.user 테이블에대한 INSERT 권한을가지지않는한 GRANT 명령어로새로운사용자를만들수없다. 사용자권한 어떤사용자가접근해서데이터베이스에대한악성행위를하는지확인할수있다. 최소권한 이핵심이다. Select * from user where Select_priv = 'Y' or Insert_priv = 'Y' or Update_priv = 'Y' or Delete_priv = 'Y' or Create_priv = 'Y' or Drop_priv = 'Y' or Reload_priv = 'Y' or Shutdown_priv = 'Y' 206
or Process_priv = 'Y' or File_priv = 'Y' or Grant_priv = 'Y' or References_priv = Y' or Index_priv = 'Y' or Alter_priv = 'Y'; Select * from host where Select_priv = 'Y' or Insert_priv = 'Y' or Create_priv = 'Y' or Drop_priv = 'Y' or Index_priv = 'Y' or Alter_priv = 'Y'; or Grant_priv = 'Y' or References_priv = Y' or Update_priv = 'Y' or Delete_priv = 'Y' Select * from db where Select_priv = 'Y' or Insert_priv = 'Y' or Grant_priv = 'Y' or References_priv = Y' or Update_priv = 'Y' or Delete_priv = 'Y' or Create_priv = 'Y' or Drop_priv = 'Y' or Index_priv = 'Y' or Alter_priv = 'Y'; MYSQL 기본계정 MySQL 기본계정은 "root"/"root@localhost" 이고패스워드는없다. 다음을이용해서 root 계정존재여부를점검할수있다. SELECT User, Host FROM user WHERE User = 'root'; 원격접근 207
MySQL 은기본설정으로 3306 포트를이용한다. 앱서버가로컬호스트에있다면, my.cnf 파일안에 [mysqld] 부분에 skip-networking 을추가하면이포트를막을수있다. 208
플래쉬개발시보안사례 플래쉬애플리케이션 다음은잠재적인플래쉬리다이렉션의이슈들이다. clicktag TextField TextArea load NetConnection.connect NetServices.createGatewayConnection NetSteam.play XML.send geturl 샌드박스보안모델 플래쉬플레이어는원본에기반해서 SWF 파일들을샌드박스에할당한다. 원본도메인에기반해서인터넷 SWF 파일들은도메인에격리된다. 동일한샌드박스내에서 SWF 파일 2 개는서로통신할수있다. - 다른샌드박스에있는객체들과통신하기 위해서명시적권한이요구된다. Local local-with-filesystem (default) - 이파일시스템은로컬파일만읽을수있다. local-with-networking - 네트워킹기능을내포한로컬 SWF 파일들과상호작용을한다. local-trusted - 로컬파일을읽을수있고, 어떤서버와통신하고어떤 SWF 파일에접근할수있다. 샌드박스는어도비플래쉬플레이어안에서실행되는어도비플래쉬무비가작동될수있게허용해주는제한된 공간으로정의된다. 이것의주목적은클라이언트단말의무결성과보안을보장하는것이다. 또한어도비 플레이어안에서실행되는어도비플래쉬무비의보안을보장하는것이다. 209
크로스도메인권한 : 웹브라우져에서실행되는플래쉬무비는동일한도메인외부의접근을허용하지않는다. 이것은크로스도메인정책파일인 crossdomain.xml 에정의되어있다. 플래쉬는이정책파일을사용해서플래쉬가네이티브도메인이외의서버로부터데이터를불러올수있는권한을허용하기위해서사용된다. SWF 파일이다른원격서버와통신하고싶으면명시적으로권한이주어져야한다. <cross-domain-policy> <allow-access-from domain="example.domain.com"/> </cross-domain-policy> System.security.loadPolicyFile(url) API 는 crossdomain.xml 파일과는다른명식적 URL 에서크로스도메인 정책을불러온다. 자바스크립트접근 AllowScriptAccess 파라미터는플래쉬객체가외부스크립트에접근할때적용된다. 이것은 3 가지값을가질수 있다.: never, same domain, always. <object id="flash007"> <param name=movie value="bigmovie.swf"> <embed AllowScriptAccess="always" name='flash007' src="bigmovie.swf" type="application/x-shockwaveflash"> </embed> </object> 공유객체 공유객체들은사용자세션에관한 100kb 까지의데이터를저장하기위해설계되었다. 공유객체는호스트그리고도메인이름그리고 SWF 무비이름에따라다르다. 이것들은이진형으로저장되고, 기본적으로크로스도메인이아니다. 공유객체들은애플리케이션의요청없이는자동적으로서버에전송되지않는다. 210
공유객체들은웹브라우저캐시외부에저장되어져야한다.: C:\Documents and Settings\<USER>\Application Data\Adobe\Flash Player\#Shared Objects\<randomstring>\<domain> 웹브라우져캐쉬를초기화하는경우에, 플래쉬공유객체는그러한방식으로살아남는다. 공유객체들은클라이언트웹브라우져가아니라플래쉬애플리케이션에의해통제된다. 권한구조 Domain Local 같은샌드박스에서어떠한두개의 SWF 파일은서로통신할수있다. 그들은다른샌드박스에서데이터를 읽기위해서명시적권한이필요하다. local-with-filesystem ( 기본설정 ) 로컬파일들에서만읽을수있다. local-with-networking 다른 local-with-networking SWF 파일과통신한다. Data 를서버로전송한다. ( 예, XML.Send() 을사용해서 ) local-trusted 로컬파일들에서읽고 ; 어떤서버, 스크립트그리고다른 SWF 파일로메시지들을보내거나읽어온다. 211
웹서비스개발보안 웹서비스검토와 XML 부하 웹서비스를검토할때, 먼저모든애플리케이션에관련된일반적인보안통제기능에초점을맞춰야한다. 웹 서비스가가지고있는고유한통제기능도검토되어야한다. XML 스키마 : 입력값검증 스키마는수신된 XML 페이로드가정의되고예측된범위내에있다는것을보장하기위해서사용한다. 스키마는안전한값의목록으로명세화될수있으며, 간단한길이나타입으로정의될수있다. 일부 XML 애플리케이션은스키마가구현되어있지않다. 즉이말은입력값검증은다운스트림으로수행되거나심지어전혀실행되지않는다. 키워드 : Namespace: XML 네임스페이스는글로벌자원식별자 (RI) 에서정한 XML 엘리먼트와속성들의집합이다. 어떤한문서에서, 엘리먼트는다른개체에의해만들어진동일한이름으로존재한다. 동일한이름을가진다른정의들을구별하기위해서, XML 스키마는네임스페이스개념을허용한다. - 자바패키지와유사하다. 스키마는 XML 페이로드데이터의예상되는형식과값과함께그페이로드에있는예상되는유한의파라미터의총량을명세할수있다. ProcessContents 속성은검증된다른네임스페이스에서 XML 을나타낸다. processcontents 속성이 lax 또는 skip 으로설정될때, wildcard 속성과파라미터에대한입력값검증은실행되지않는다. 이속성을위한값은다음이될것이다. strict: XML 검증과네임스페이스와연관된선언을반드시해야한다. Lax: 스키마에대해서 XML 검증을한다. skip XML 검증을하지않는다. 212
processcontents=skip\lax\skip 엘리먼트또는속성의무한발생 특정엘리먼트에예상되는최대발생수가없다는것을명세하기위해, XML 스키마에경계가없는값을사용할 수있다. maxoccurs= positive-integer unbounded 경계없는엘리먼트에대해엘리먼트개수가제공될수있다면, 웹서비스에대량의엘리먼트를제공하는공격을 통해자원고갈문제를일으킬수있다. 네임스페이스약점, 전역요소들, <ANY> 요소와 SAX XML 처리기 <any> 엘리먼트를사용하면확장가능한문서를만들어, 주스키마에선언되어있지않은추가적인엘리먼트들을문서에포함할수있다. 애플리케이션이많은파라미터를받아들일수있다는생각은위험하다. 이렇게하면서비스가용성에문제가생기고, SAX XML 파서의합법적인값의경우에덮어씌여질수있다. <xs:element name="cloud"> <xs:complextype> <xs:sequence> <xs:element name="process" type="xs:string"/> <xs:element name="lastcall" type="xs:string"/> <xs:any minoccurs="0"/> </xs:sequence> </xs:complextype> </xs:element> 여기서 <any> 엘리먼트는임의적으로파라미터가추가될수있게허용한다. 213
<any> 엘리먼트의 ##any 네임스페이스는스키마에서명시적으로정의된것이외에엘리먼트를허용한다. 그래서주어진요청에대해예상된엘리먼트에제어기능이줄어든다. <xs:any namespace='##any' /> 제한적인네임스페이스엘리먼트를정의하지않은스키마는유효한문서내에포함되는애플리케이션에서 예상하지않는임의의엘리먼트를허용한다. 이를통해애플리케이션에의해예상되지않은태그가포함되 XML 인젝션같은공격이발생할수있다. 214
코드리뷰결과보고서작성법 애플리케이션보안 발견사항 은애플리케이션보안팀에서소프트웨어개발조직에게정보를전달하는방법이다. 발견사항은보안취약점, 구조적또는구성상의문제일수도있으며, 모범사례나표준준수를하지않았을수도 있고, 우수사례를따르지않아서발생하는실패사례일수도있다. 훌륭한제목선택작성자는애플리케이션보안보안발견사항을기술할때, 수신자가해당이슈를명확히인지할수있고간결하고설득력있는제목을선택해야한다. 일반적으로좋은문구로제안되는것으로는 비즈니스로직에접근통제추가 또는 XSS 예방을위한출력값인코딩 과같이긍정적인방향으로제목을선택하는것이다. 취약점위치의분명한식별 발견사항은가능한한구체적으로코드와 URL 에서의위치가명확히표기되어야한다. 만약그결과가특정위치 만이아닌전반적인문제들를내포하고있다면, 그취약점의위치들은그문제의실질적인경우에대해많은 예시를통해실질적인사례로제시해야한다. 취약점상세기술 발견사항은누구나아래와같이할수있도록상세히제공해야한다. 취약점의이해할수있도록 발생가능한시나리오의이해할수있도록 발생가능성의핵심요소들과그영향을알수있도록 위험에대한논의 각각의발견사항에정성적인값을할당하고, 이값이할당된이유를서술해야한다. 위험평가방법은다음과같다. 심각고위험중위험저위험 215
할당된위험평가등급의타당성은매우중요하다. 이것은이해당사자들 ( 특히기술적이해가없는 ) 이더잘 이해하고받아들일수있도록한다. 중요한두개의식별포인트는다음과같다. 발생가능성 ( 쉬운발견과실행 ) 사업적 / 기술적영향 조직내에서위험등급에대한표준방법론을가져야한다. OWASP 위험평가방법론은조직의우선순위를맞출수 있도록해주는포괄적인방법론이다. 권고사항제안 대안 필요한노력 잔여위험 참고사항포함 주의 : 만약당신이 OWASP 의자료를사용하는경우반드시 OWASP 의라이선스를준수해야한다. 216
보고서양식예시 아래의양식은소스코드보안성검토결과에대한보고서예시이다. 검토 / 계약참조 : 패키지 / 콤포넌트 / 클래스명 / 행번호 발견사항제목 : 중요성 : 높음 발견사항설명위치위험설명권고사항 HTTPRequest object.getid() com.inc.dostuff.java 취약점이악용 운영환경에투입되기 함수에서입력값검증절차부재 행번호 20, 55,106 되는경우의가능성과사업상 이전에해결되어야 하는중대문제임 입력값검증부재로인해다양한종류의인젝션공격이가능함 com.inc.main.java 행번호 34, 99 영향에대한논의 217
자동화코드리뷰 서문 수동으로소스코드에대한보안취약점을찾는동안검토자들은두가지문제를겪는다. 수동으로검토하는소스코드점검은평균적으로한시간에 100 행에서 200 행가량을검토하는며느린작업이다. 또한, 사람은한번에약일곱가지의항목들을기억할수있는데, 소스코드에는백여개의보안문제가있다. 소스코드분석도구들은한번에수백여가지의다양한보안문제를탐색할수있으며, 사람에비해훨씬많은코드를검토할수있다. 하지만자동화도구를이용하면오탐이나미탐이발생하므로, 자동화도구를사용해도사람에의한검토가필요하다. 코드리뷰도구를사용하는이유 대량의소스코드에서와같이기업에서대규모의소스코드보안성검토작업을할때, 자동소스코드검토기술 은소스코드리뷰절차개선에도움이된다. 교육과문화적인변화 보안수준이높고안전한소스코드를작성하기위한개발자교육은소스코드보안성검토의가장중요한목표이다. 이러한관점에서소스코드를검토하는것은소스코드의품질제고를위한유일한방법이다. 교육과정중에개발자에게위임하여더우수한소스코드를개발할수있도록지식을제공해야한다. 이렇게하기위해서는개발자들이자신의코드와비교할수있는통제된규칙을제공할수있다. 자동화된도구들은이러한기능을제공하며, 또한소스코드리뷰시소요시간을단축시킬수있다. 개발자는보안지식이충분치않아도자동화된점검도구를사용하여직접소스코드의보안수준을점검할수있다. 또한소스코드점검도구의사용에일단익숙해진뒤에는, 자동점검도구를쉽게사용할수있게된다. 218
도구적용모델 개발자에게코드점검도구를사용하게하는것은보안점검컨설턴트가코드를점검하기전에일반적이고단순한실수들을대부분제거할수있도록도와준다. 이러한방법론을통해개발자에게관련지식을쌓게하고코드점검컨설턴트가더애매한취약점을찾도록할수있다. 개발자수용모델 개발자에게자동화도구를사용하도록함 규칙기반도구를통제 보안점검결과와추가탐색 테스트부서모델 테스트부서는기능시험시자동점검포함 보안점검결과와추가탐색 규칙기반도구는내부보안개발정책을준수하고보안부서의통제를받도록함 애플리케이션보안그룹모델 모든소스코드들을애플리케이션보안그룹이검토 수동및자동화솔루션사용 219
OWASP 의 ORIZON 프레임워크 소개이세상엔수많은오픈소스프로젝트가존재하고있으며, 정적코드분석이수행되고있다. 이는바람직한현상이며, 보안문제에대한소스코드테스트가강제화되어가고있다는것을의미한다. 이러한도구들은매우중요한이점이있다. 커뮤니티지원 누구에게나자유롭게소스코드사용가능 비용 반면에이러한도구들은가장가치있는것즉보안지식을공유하지않는다. 모든도구들은보안지식을공유하지않고, 자체적인보안라이브러리와수많은점검항목들을갖고있다. 2006 년도에 OWASP Orizon 프로젝트는정적분석을위해모든오픈소스프로젝트에적용가능한공통적인기반을제공하기위해탄생했다. Orizon 프로젝트는다음을포함한다. 정적분석을수행하는자체보안도구를구축하기위해개발자들이사용할수있는 API 소스코드에적용하도록점검항목이있는보안라이브러리 Orizon 프레임워크를사용하는정적코드분석도구밀크 (Milk) OWASP ORIZON 아키텍처 아래의그림은 OWASP Orizon 버전 1.0 의구조이다. 그림에서보듯이이프레임워크는현장에서정적코드 분석을위해소스코드에서사용하는 API 를외부로확산시키기위한도구들과소스코드분석을수행하는 엔진들로구성되어있다. 220
위의모든요소들은개발자들이이프레임워크를사용하기주저하게만들수있는데, 바로이점이 스카이라인이라고부르는특별한개체가만들어진이유이다. 스카이라인분석으로들어가기전에, 이것은 Orizon 이만들어진모든구성요소들이을이해하는데매우중요하다. 당신의개인비서 : 스카이라인클래스 Orizon 버전 1.0 에서코어라고지정된스카이라인객체는아키텍쳐설계에서가장중요한것이다. 스카이라인의발상배경은매우단순하다. 즉 Orizon 구조가더확대되고일반개발자들이보안도구들을 제작하기위한수많은 API 들을이해하는것이힘들수있어서비스별지원할수있도록한것이다. 스카이라인객체를사용하여, 개발자는 Orizon 프레임워크에서서비스들을요청할수있다. 스카이라인의주요입력값은다음과같다. public boolean launch(string service) 문자열파라미터로요청된서비스를처리하기위해, 호출프로그램은서비스가완수하는경우엔부울값중 참 ( 성공 ) 값을회신받을것이며, 그렇지않을경우엔거짓 ( 실패 ) 의값을회신받을것이다. 서비스명은프레임워크에의해이해되는것과비교된다. private int goodservice(string service) { int ret = -1; if (service.equalsignorecase("init")) ret = Cons.OC_SERVICE_INIT_FRAMEWORK; if (service.equalsignorecase("translate")) 221
ret = Cons.OC_SERVICE_INIT_TRANSLATE; if (service.equalsignorecase("static_analysis")) ret = Cons.OC_SERVICE_STATIC_ANALYSIS; if (service.equalsignorecase("score")) ret = Cons.OC_SERVICE_SCORE; return ret; } 이번첫주요프레임워크배포판의부가특징은사용자들에게명령행옵션을지원한다. 만약호출프로그램이스카이라인을사용해명령행인터페이스로 Orizon 프레임워크에전달되면, 프레임워크는 사전에설정된값으로변경될것이다. 설명을돕기위한다음의예시가있다. public static void main(string[] args) { String filename = ""; OldRecipe r; DefaultLibrary dl; SkyLine skyline = new SkyLine(args); 매우간결하다. 내부적으로코드리뷰세션이생성될때스카이라인생성자는명령행으로부터의이해할수 있었던값을사용한다. 명령행서식은다음의규칙을따른다. -o orizon_key=value 또는긴형식으로, --orizon orizon_key=value 그리고아래는프레임워크에서가지고있는키값이다. 222
"input-name" "input-kind" "working-dir" "lang" "recurse" "output-format" "scan-type"; org.owasp.orizon.cons 클래스는약간의주석문들과함께기본값들의이러한키들과자세한부분을포함한다. 단지부작용은호출프로그램이 -o 플래그를목적을위해사용할수있다. 스카이라인은 org.owasp.orizon package 에포함되어있다. 223
복습사항 : 세션클래스 Owasp Orizon 버전 1.0 의또다른중요기능은코드리뷰세션에대한개념이다. 이전버전들에서의누락되었던이기능들은코드리뷰프로세스의상태를추적할수있다. 세션클래스인스턴스는스카이라인을사용하는명세된모든속성들을포함하고있으며, 요청시속성에접근할수있는속성의소유자이다. 이것은검토되고있는파일들에대한정보를가지고있는 SessionInfo 배열을가지고있다. 이상적으로, 사용자도구는세션을직접호출하지않지만, 인터페이스용으로반드시스카이라인을사용해야한다. 물론, 누구나이제안을받아들이지않을수있다. 스카이라인클래스내에서의 launch() 메소드코드를보면, 어떻게세션인스턴스가서비스들을실행하는지볼수있다. public boolean launch(string service) { int code, stats; boolean ret = false; if ( (code = goodservice(service)) == -1) return log.error("unknown service: " + service); switch (code) { // init service case Cons.OC_SERVICE_INIT_FRAMEWORK: ret = session.init(); break; // translation service case Cons.OC_SERVICE_INIT_TRANSLATE: 224 stats = session.collectstats();
if (stats > 0) { log.warning(stats + " files failed in collecting statistics."); ret = false; } else ret = true; break; // static analysis service case Cons.OC_SERVICE_STATIC_ANALYSIS: ret = session.staticreview(); break; // score service case Cons.OC_SERVICE_SCORE: break; default: return log.error("unknown service: " + service); } return ret; } 내부적으로, 세션인스턴스는서비스들을실행하는세션정보객체들을요구할것이다. 그럼, 정적분석서비스를 실행하는세션클래스메소드를살펴보자. /** * Starts a static analysis over the files being reviewed * * @return true if static analysis can be performed or false 225
* if one or more files fail being analyzed. */ public boolean staticreview() { boolean ret = true; if (!active) return log.error("can't perform a static analysis over an inactive session."); for (int i = 0; i < sessions.length; i++) { if (! sessions[i].staticreview()) ret = false; } return ret; } 세션변수가선언된곳 : private SessionInfo[] sessions; 세션객체위임서비스는최종결과를수집한 SessionInfo 를이용한다. 사실상, SessionInfo 객체는실제작업을수행하는 Orizon 의내부와통신을수행한다. 다음의메소드는 org.owasp.orizon.sessioninfo 클래스로부터가져온것이다. /** * Perform a static analysis over the given file * 226
* A full static analysis is a mix from: * * * local analysis (control flow) * * global analysis (call graph) * * taint propagation * * statistics * * * @return true if the file being reviewed doesn't violate any * security check, false otherwise. */ public boolean staticreview() { boolean ret = false; s = new Source(getStatFileName()); ret = s.analyzestats();... return ret; } 번역팩토리 227
OWASP Orizon 의목표중하나는분석대상프로그램의언어에독립적이어야한다는것이다. 즉, Orizon 에서 다음언어를모두지원해야한다는것이다. Java C, C++ C# perl... 이와같은언어에대한지원이가능한이유는 XML 언어형태로소스코드를설명하는중간언어파일포맷으로변환하고이를통해보안점검을수행하기때문이다. 소스코드를정적분석하기전에 XML 형태로변환되어진다. 1.0 버전부터각소스코드는다음의 4 개 XML 파일로변환된다. 통계정보를가지고있는 XML 파일변수추적정보를담고있는 XML 파일로직분석을통해프로그램의제어흐름정보를분석한 XML 파일글로벌분석을통한호출그래프 XML 파일 이문서가작성되는시점 (OWASP ORIZON v1.0 pre1, 2008 년 11 월 ) 에는자바언어만지원되고있으며, 곧다른언어에대해서도지원이가능할것이다. 변환시점에 org.owasp.orizon.sessioninfo.inspect() 매소드를사용한다. 소스파일의프로그래밍언어에따라적절한변환기가호출된후, scan() 매소드가호출된다. /** * Inspects the source code, building AST trees * @return */ public boolean inspect() { 228
boolean ret = false; switch (language) { case Cons.O_JAVA: t = new JavaTranslator(); if (!t.scan(getinfilename())) return log.error("can't scan " + getinfilename() + "."); ret = true; break; default: log.error("can't inspect language: " + Cons.name(language)); break; } return ret; } 스캔매소드는 org.owasp.orizon.translator.defaulttranslator 클래스에서정의된추상매소드이며, 다음과같이 정의된다. public abstract boolean scan(string in); Every class implementing DefaultTranslator must implement how to scan the source file and build ASTs in this method. Aside from scan() method, there are four abstract method needful to create XML input files. public abstract boolean statservice(string in, String out); public abstract boolean callgraphservice(string in, String out); public abstract boolean dataflowservice(string in, String out); public abstract boolean controlflowservice(string in, String out); 229
All these methods are called in the translator() method, the one implemented directly from DefaultTranslator class. public final boolean translate(string in, String out, int service) { if (!isgoodservice(service)) return false; if (!scanned) if (!scan(in)) return log.error(in+ ": scan has been failed"); switch (service) { case Cons.OC_TRANSLATOR_STAT: return statservice(in, out); case Cons.OC_TRANSLATOR_CF: return controlflowservice(in, out); case Cons.OC_TRANSLATOR_CG: return callgraphservice(in, out); case Cons.OC_TRANSLATOR_DF: return dataflowservice(in, out); default: return log.error("unknown service code"); } } 그래서, 특정언어변역기에 translate() 라는메소드가표시되면, 이것은언어의특정서비스메소드를다시호출 한다. 230
모든번역은 prviate 필드를포함하여, ASTs 특정언어스캐너는입력파일생성에사용된다. 다음과같이선언되어있는 org.owasp.orizon.translator.java.javatranslator 를참조한다. public class JavaTranslator extends DefaultTranslator { static SourcePositions positions; private JavaScanner j;... JavaScanner 는 org.owasp.orizon.translator.java 패키지에있는클래스이며, 메모리 ASTs 에생성된 java 파일을 스캔하기위해 Sun JDK 6 컴파일러 API 를사용한다. Tree 들은 scan() 메소드에의해서생성되며, Java 소스 언어를위해구현된것은아래와같다. public final boolean scan(string in) { boolean ret = false; String[] parms = { in }; Trees trees; JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) return log.error("i can't find a suitable JAVA compiler. Is a JDK installed?"); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); StandardJavaFileManager filemanager = compiler.getstandardfilemanager(diagnostics, null, null); Iterable<? extends JavaFileObject> fileobjects = filemanager.getjavafileobjects(parms); JavacTask task = (com.sun.source.util.javactask) compiler.gettask(null,filemanager, diagnostics, null, null, fileobjects); try { trees = Trees.instance(task); positions = trees.getsourcepositions(); Iterable<? extends CompilationUnitTree> asts = task.parse(); 231
for (CompilationUnitTree ast : asts) { j = new JavaScanner(positions, ast); j.scan(ast, null); } scanned = true; return true; } catch (IOException e) { return log.fatal("an exception occured while translate " + in + ": " +e.getlocalizedmessage()); } } 232
통계수집 통계정보수집을구현하기위해서 DefaultTranslator 의추상메소드인 statserver() 가반드시구현되어야한다. 아래에보이는예제는 JavaTranslator 의메소드이다. 통계정보는 JavaScanner 객체자체에저장되고 getstats() 메소드로호출하여사용할수있다. public final boolean statservice(string in, String out) { boolean ret = false; if (!scanned) return log.error(in + ": call scan() before asking translation..."); log.debug(". Entering statservice(): collecting stats for: " + in); try { createxmlfile(out); xmlinit(); xml("<source name=\"" + in+"\" >"); xml(j.getstats()); xml("</source>"); xmlend(); } catch (FileNotFoundException e) { } catch (UnsupportedEncodingException e) { } catch (IOException e) { ret = log.error("an exception occured: " + e.getmessage()); } 233
ret = true; log.debug("stats written into: " + out); log.debug(". Leaving statservice()"); return ret; } 234
OWASP 코드리뷰 TOP 9 머리말 이절에서는전체코드리뷰프로세스를평가를위해제한적인카테고리의목록을정의하기위해코드리뷰동안 발견할수있는가장심각한보안결함을정리한다. 9 가지취약점카테고리 소스코드보안관점에서, 소스코드의취약점은다양한방법으로관리할수있다. 소스코드의취약성은확실히 "OWASP 탑 10 추천사항 에반영될것이다. 애플리케이션들은소스코드로만들어지기때문에, 다른말로표현하자면소스코드의결함은애플리케이션의취약성이라고말할수있다. 아래카테고리들은 2008 년 10 월에배포된 "Owasp Orizon Project v1.0" 기본라이브러리에포함되어있다. 9 가지소스코드결함카테고리 1. 입력값검증 2. 소스코드설계 3. 정보누출및부적절한오류처리 4. 직접적인객체참조 5. 자원사용 6. API 사용 7. 모범사례위반 8. 세션관리취약점 9. HTTP GET 을이용한쿼리문자열 위내용의 9 개의카테고리중 3 가지는 OWASP 탑 10 과동일하다. 이제소스코드취약점카테고리를좀더자세히그리고심도있게살펴보고자한다. 235
입력값검증 이결함카테고리는 "OWASP Top10 A1" 카테고리의소스코드에해당하는부분이다. 이카테고리는아래의보안취약점군을포함한다. 입력값검증 크로스사이트스크립트 SQL 인젝션 XPATH 인젝션 LDAP 인젝션 CSRF 버퍼오버플로우포맷버그 소스코드설계 소스코드의보안은설계에서시작하며, 선호하는에디터를사용하여코딩을시작하기전에이루어져야한다. 소스코드설계결함의카테고리에서범위및소스코드의구조와밀접하게관련된보안점검사항들을발견할 수있다. 소스코드설계 안전하지않은필드범위안전하지않는메소드범위안전하지않은클래스수정자사용되지않는외부참조중복코드 236
정보누출및부적절한오류처리이카테고리는 "OWASP 탑 10" 중하나와동일하다. 이카테고리는소스코드오류관리, 예외사항, 로깅그리고민감정보에대해서어떻게관리하여야하는지에대한보안점검사항들을포함하고있다. 다음과같은사항들이포함되어있다. 정보누출및부적절한오류처리 예외처리누락일반적인반환값을사용널포인터역참조안전하지않은로깅 객체직접참조이카테고리는 "OWASP 탑 10" 프로젝트에서언급되었던것과같다. 이것은특별제작된매개변수를공급하는응용프로그램내부와공격자가상호작용을할수있는지여부를언급한다. 이카테고리에포함된항목들은아래와같다. 객체직접참조 데이터베이스데이터에대한직접참조 파일시스템에직접참조 메모리직접참조 자원사용량 이카테고리는운영체제가자원을관리할때, 모든안전하지않은소스코드가요청하는것과관련이되어있다. 여기에포함되어있는대부분의취약점들은해커에의해서사용된다면서비스거부와같은결과를초래할수있다. 자원이될수있는것들 : 파일시스템객체 237
메모리 CPU 네트워드대역폭 여기에포함된군은다음과같다 : 자원사용량 안전하지않은파일작성안전하지않은파일수정안정하지않은파일삭제경쟁조건메모리누출안전하지않은프로세스생성 API 사용 이절에서는시스템이나프레임워크에서제공하는 API 를악용할수있는상황에대해서언급한다. 이절에서 다음사항을확인할수있다 : 안전하지않게데이터베이스호출안전하지않게랜덤숫자생성부적절한메모리관리호출안전하지않게 HTTP 세션제어안전하지않게문자열조작 모범사례위반이절에서는이전절에서언급하지않은기타모든보안위반사항을다룬다. 전부는아니지만대부분경고수준의소스코드모범사례를담고있다 238
이번카테고리에언급하는내용은다음과같다. 안전하게않게메모리포인터를사용널포인터참조포인터연산변수엘리어싱안전하지않은변수초기화커멘트와소스코드문서화누락 취약한세션관리 오류발생시세션을뮤효화하지않는경우 HTTP 요청에대해서유효세션인지확인하지않는경우인증성공시신규세션을발행하지않는경우 ( 안전한플래그없이 ) SSL 연결을사용하지않고쿠키를전송하는경우 HTTP GET 으로쿼리스트링사용페이로드가쿼리문자열에포함된경우로깅된다. 이정보는고객의브라우져에서부터서버까지의모든노드에저장된다. 보안에민감한데이터를쿼리스트링과 HTTP GET 으로보내는것은윤리적으로도심각한문제다. SSL 조차이를보호할수없다. 보안에민감한데이터를 URL 이나쿼리문자열로전달하는경우 239
코드리뷰가이드색인및용어.NET, 56, 96.NET Framework, 60.NET 프레임워크 Absolute, 52 절대적 Absolute metrics, 52 절대적지표 ActionErrors, 103 Agile Security Methodology, 21 애자일보안방법론 allow_url_fopen, 199 API usage, 238 API 사용 APIs, API 238 Application security group model, 219 애플리케이션보안그룹모델 ApplicationException, 96 ASP.NET, 25, 60 AST, 231 attack surface, 22 공격접점 Audience, 16 사용자 Authentication, 39, 76 인증 Authorization, 40 인가. A B baseline, 16 기준 buffer overflows, 42 버퍼오버플로우 Checklist, 19 체크리스트 Classic ASP, 79, 111 클래식 ASP client side attacks, 57 클라이언트측공격 Code, 14 코드 code coverage, 55 코드커버리지 C codebase, 14 코드 Common string errors, 201 일반적인문자열오류 Context, 14, 16 컨텍스트 Cookie Management, 40 쿠키관리 Cookie manipulation, 58 쿠키조작 Cookies, 58 쿠키 Countermeasure, 47 대응책 countermeasures, 27 대응방안 Coverage, 22 범위 Crawling code, 56 코드크롤링 critical business impacts, 16 주요사업영향 Cross site request forgery, 236 CSRF cross site scripting, 42 크로스사이트스크립팅 CryptoAPI, 111 cryptography, 110 암호 Cryptography, 41 암호 CWE, 14 Cyclomatic complexity, 54 순환복잡도 Damage, 45 피해 data flow, 37 데이터흐름 Data Flow, 36 데이터흐름 Data flows, 43 데이터흐름 data store, 36 데이터저장소 Data/Input Validation, 40 데이터 / 입력값검증 Decompose, 26, 27 분리 Defect Correction Rate, 55 결함수정율 Defect Density, 53 결함밀도 Defect detection, 55 결함검출 Deployment Descriptor, 24 배치설명서 Deploying code review tools, 218 코드점검도구 DES, 113 Determine and rank threats, 26 위협결정및순위화 Developer adoption model, 219 개발자수용모델 D 240
DFD, 35 Direct object reference, 237 객체직접참조 Discoverability, 발견 45 Discovery, 15 발견 Domain, 210 도메인 DREAD, 27, 45 DREAD score, 46 DREAD 점수 Elevation of Privilege, 39 권한상승 Entropy, 116 엔트로피 Entry points, 29 입력지점 Error Handling, 41, 93 오류처리 Exit points, 42 출력지점 Exploitability, 45 악용가능성 extensible, 213 확장가능한 external connections, 39 외부연결 external entity, 35 외부개체 E F fail securely, 93 실패안정성 false positive, 218 오탐 framework, 23, 24 프레임워크 HTML, 57 HTTP, 39, 199 HTTP GET, 108, 239 Http Request, 57 Http 요청 HTTP request, 85 HTTP 요청 H Importance, 16 중요성 Information leakage, 237 정보누출 Input validation, 235 입력값검증 inspection rate, 55 검사율 integer, 203 정수 Integer, 204 IsClientConnected, 197 I Java, 7, 96, 189 자바 JavaScript, 194, 210 자바스크립트 JCE, 111 JDK, 109 JSP, 107, 108 key indicators, 56 주요지표 J K LDAP Injection, 236 LDAP 인젝션 Least privilege, 206 최소권한 Lines of code, 52 코드라인 local-trusted, 211 Logging/Auditing, 41 로그 / 감사 L M Manual code review, 218 수동코드리뷰 Metric benefits, 52 메트릭의장점 Metrics, 52 메트릭스 Metrics throughout the code review process, 53 코드리뷰프로세스전반에대한측정지표 Microsoft, 26, 45 마이크로소프트 Mitigation, 45 완화 multiple process, 36 다중프로세스 MySQL, 205 N namespace, 213 네임스페이스 NULL pointer, 239 널포인터 Off by one, 203 Orizon, 220, 224, 228 OS Injection, 86 OS 인젝션 Overflows, 203 오버플로우 O 241
OWASP, 7 Owasp Top 10, 235 OWASP 탑 10 Payment Card Industry Data Security Standard, 74 카드결제산업데이터보안표준 (PCI-DSS) PCI, 74 PHP, 198 pointer arithmetic, 239 포인터연산 Possible Attacks, 17 가능한공격 printstacktrace(), 96 Privacy Policy, 12 프라이버시정책 privilege boundary, 36 권한범위 process, 35 프로세스 rank threats, 38 위협결정순위 Ranking of Threats, 45 위협순위화 Redundant code, 236 중복코드 regular expressions, 24 정규표현식 Re-inspection defect Rate, 55 재검토결함율 Relative, 52 상대적 Relative metrics, 52 상대적지표 Reproducibility, 45 재현가능성 Resource usage, 235 자원사용 Risk Density, 53 결함밀도 risk ratings, 216 위험등급 P R Session Integrity, 89 세션무결성 Session management, 42 세션관리 SkyLine, 221 스카이라인 Source code design, 236 소스코드설계 SQL, 57 SQL injection, 43, 57 SQL 인젝션 STRIDE, 26, 38, 39, 37, 42, 44 String Termination, 201 문자열종료 struts, 23 스트럿츠 Surface, 22 접점 Testing Department model, 219 테스트부서모델 Testing Guide, 13 테스팅가이드 Threat Agents, 17 위협요소 Threat analysis, 42 위협분석 threat analyst, 43 위협분석가 Threat List, 39 위협목록 Threat Model, 26 위협모델 Threat Modeling, 26 위협모델링 transaction analysis, 23 트랜잭션분석 Trust, 34 신뢰 Try & Catch, 99 T U unbounded value, 213 경계가없는값 unsigned integer, 204 부호없는정수 Sample Report, 217 보고서예시 SandBox, 209 샌드박스 SAX, 213 SDL, 26 SDLC, 20, 26 Secure Code Environment, 23 보안코드환경 security code review, 14 보안코드리뷰 Security Controls, 39 보안통제 S validator, 19 유효성 V W Waterfall SDLC, 20 폭포수 SDLC web.config, 60 242
X XML, 25, 212 XPATH Injection, 236 XPATH 인젝션 243
참고문헌 1. Brian Chess and Gary McGraw. "Static Analysis for Security," IEEE Security & Privacy 2(6), 2004, pp. 76-79. 2. M. E. Fagan. "Design and Code Inspections to Reduce Errors in Program Development," IBM Systems J. 15(3), 1976, pp. 182-211. 3. Tom Gilb and Dorothy Graham. Software Inspection. Addison-Wesley, Wokingham, England, 1993. 4. Michael Howard and David LeBlanc. Writing Secure Code, 2nd edition. Microsoft Press, Redmond, WA, 2003. 5. Gary McGraw. Software Security. Addison-Wesley, Boston, MA, 2006. 6. Diomidis Spinellis. Code Reading: The Open Source Perspective. Addison-Wesley, Boston, MA, 2003. 7. John Viega and Gary McGraw. Building Secure Software: How to Avoid Security Problems the Right Way. Addison-Wesley, Boston, MA, 2001. 8. Karl E. Wiegers. Peer Reviews in Software. Addison-Wesley, Boston, MA, 2002.