저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

'보안 정책'에 해당되는 글 2건

  1. 2001.06.11 안전한 코드를 위한 보안 정책: Part 2
  2. 2001.06.04 안전한 코드를 위한 보안 정책: Part 1
안전한 코드를 위한 보안 정책에 대해서 살펴본다.

코드의 보안 강화 방법

지난 '안전한 코드를 위한 보안 정책: Part 1'에서는 안전한 코드를 위한 정책으로서 제품의 요구 사항과 위험관리, 에러 처리, 객체에 대한 접근 규약, 접근과 승인 등에 대한 내용을 살펴보았다. 이번 Part 2에서는 계속해서 안전한 코드를 위한 보안 정책에 대해서 살펴보도록 하자.

코드의 구분

여러분은 어플리케이션에 알맞은 컴포넌트 또는 객체를 사용함으로써 보안 구멍에 따른 피해를 최소화할 수 있다. 코딩할 때는 가능한 한 많이 고룁된 유닛(즉, 다른 요소와의 연관성이 매우 적은 컴포넌트나 객체)을 사용해야 한다. 특히, 보안과 관련된 코드는 어플리케이션에 알맞게 설계된 보안 API를 사용해야 하며, 그렇게 함으로써 여러분은 보안 정책을 틈새없이 제어할 수 있다. 예를 들어, 불필요하게 다양한 기능을 제공하는 보안 API를 사용할 경우에는 필요로 하지 않는 기능에 의한 보안 구멍이 생길 수 있으며, 또한 너무 적은 기능을 제공하는 보안 API를 사용할 경우에는 어플리케이션에서 필요로 하는 보안 기능을 충족시킬 수 없게 된다.

또한, 인증된 코드를 하나의 아카이브 파일에 넣어야 한다. 예를 들어, 보안 구멍을 노리고 있는 공격자들은 인증된 클래스를 연결하는 새로운 애플릿이나 라이브러리를 생성할 수도 있다. 비록 인증된 코드를 하나의 아카이브 파일에 넣는 것이 이러한 문제를 완벽하게 해결하지는 못하지만, 문제를 해결하는 데 도움을 줄 수는 있을 것이다.

암호화

여러분이 작성한 코드는 매우 깨기 어려운 코드일 수도 있지만, 그 코드에 있는 문제점은 항상 공격의 대상이 될 수 있다. 특히 네트워크를 통해서 데이터를 주고 받는 경우에는 더더욱 그렇다. 예를 들어, POP3를 생각해보자. POP3는 메일 서버로부터 메일을 읽어올 때 사용되는 프로토콜이다. POP3는 사용자를 인증하기 위해서 사용자 아이디와 암호를 입력하도록 하고 있다. 하지만 이 때 입력하는 아이디와 암호는 어떤 처리도 되지 않은 평범한 텍스트로 전송되기 때문에 중간에서 누구든지 손쉽게 그 내용을 훔쳐볼 수 있는 가능성이 있다.

텔넷 역시 이러한 보안 문제를 갖고 있으며, 오늘날 가장 많이 사용되는 HTTP 프로토콜 역시 같은 보안 문제를 안고 있다. 이러한 문제점을 해결할 수 있는 가장 간단한 방법은 주고 받는 데이터를 암호화하는 것이다. 예를 들어, 텔넷의 경우 SSH을 사용하여 데이터를 암호화하고 있고, HTTP 프로토콜의 경우는 HTTPS를 통해서 암호화를 할 수 있게 되어있다. 여러분이 작성하는 어플리케이션 역시 네트워크를 통해서 보안을 유지해야 하는 데이터를 주고 받을 경우 암호화하는 것을 고려해봐야 한다. 암호화를 할 때의 주의점은 암호화 기법이 노출되어서는 안 된다는 점이다. 예를 들어, 비밀키/공개키를 사용하는 경우 비밀키가 노출될 경우 암호화하여 주고 받는 모든 데이터를 매우 간단하게 분석할 수 있게 된다.

주고 받는 데이터 뿐만 아니다. 회원이 입력하는 기밀 정보-예를 들어, 암호나 신용카드 번호-를 데이터베이스나 파일에 저장해야 하는 경우 암호화하는 것이 좋다. 비록 특정 사용자만 기밀 데이터에 접근할 수 있도록 보안 장치를 했다 하더라도 보안 장치는 언제든지 깨질 수 있으며, 따라서 기밀 데이터는 암호화하여 저장하는 것이 안정성을 더욱 높이는 방법이다.

입력 검사와 클라이언트 콜

입력의 검사는 매우 중요하다. 클라이언트는 변경될 수 있고, 쿠키 역시 변경될 수 있으며, DNS와 IP 주소는 스푸핑 될 수 있다. 공격자는 여러분이 작성한 바이너리 데이터를 변경할 수도 있다. 여러분이 사용하는 표준 라이브러리나 운영 체제가 안전하다고 가정해서는 안 된다.

가능하다면 이러한 종류의 모든 외부 데이터 입력은 피해야 한다. 항상 모든 클라이언트의 보안 검사를 해야 하며, 에러 검사는 필수적이다. 또한 입력 가능한 값의 집합을 정의해야 하며, 가능하다면 운영 체제까지 이어지는 하위 레벨 호출은 피해야 한다.

디컴파일러에 대한 방어

기계어를 디컴파일하여 프로그래밍 언어로 변환하는 일은 좀처럼 쉬운 일이 아니다. 예를 들어, 어셈블리어를 C/C++ 언어나 또는 델파이에서 사용하는 오브젝트 파스칼로 변환하려고 시도하는 것 자체가 고통스러운 일이다. 하지만, 자바의 경우는 얘기가 좀 다르다. 자바의 클래스 파일 포맷을 살펴보면 컨스턴트 풀(constant pool)이라는 것이 있는데 이것은 소스 코드에 대한 많은 정보를 포함하고 있으며, 디컴파일러는 이 정보를 이용하여 클래스 파일로부터 원본에 가까운 소스 코드를 추출해내기도 한다.

특히 최근에는 순수하게 자바로만 구현되는 제품이 증가하면서 디컴파일에 대한 방어를 할 수 있도록 코딩을 해야 할 필요성이 증가하고 있다. 디컴파일에 대한 내용은 IBM의 Developerworks에 있는 How to lock down your Java code 를 참조하기 바란다.

오픈 소스의 검토

최근 많은 프로젝트가 오픈소스로 진행되고 있다. 오픈 소스로 프로젝트를 진행할 경우 해커들이 매우 간단하게 어플리케이션의 약점을 발견할 수 있다는 단점이 있지만, 그와 함께 많은 사람들에 의해 보안 구멍을 빠르게 보완할 수 있다는 장점도 있다. 센드메일의 경우 초기 버전은 보안에 많은 문제점이 있었지만 지금은 많은 부분에서 문제점이 해결되었다. 이는 모두 센드메일의 소스 코드가 공개되었기 때문에 가능한 것이었을 것이다.

결론

Part 2에서는 지난 Part 1에서 언급하지 않았던 몇 가지 보안 정책에 대해서 추가적으로 살펴보았다. 개발자들은 항상 머리속에 자신이 개발한 어플리케이션에 보안 문제가 발생할 수 있다는 것을 염두해두어야 하며, 따라서 어플리케이션 개발할 때에는 먼저 보안 정책을 세워둠으로써 보다 안전한 어플리케이션을 개발할 수 있는 토대를 만들어야 할 것이다.

관련링크:
Posted by 최범균 madvirus

댓글을 달아 주세요

안전한 코드를 위한 코딩 보안 정책에 대해서 살펴본다.

보안 정책

오늘날, 웹 어플리케이션을 포함한 대부분의 소프트웨어에서 보안은 반드시 제공해야 하는 기능으로 자리잡고 있다. 안전한 네트워크와 운영체제를 위한 검사 목록이 있으며, 보안 검사를 전문적으로 하는 기업에 의뢰를 맡기기도 한다.

하지만, 보안을 위한 검사 목록을 작성하고 다른 기업에 의뢰를 맡긴다 해도 보안 문제의 근본적인 원인은 해결할 수 없게 된다. 왜냐면 보안 문제의 근본적인 원인은 소프트웨어에 있기 때문이다. 실제로 외부에서 보안의 구멍을 뚫고 둘어오는 경우는 대부분 소프트웨어의 약점을 통해서 이루어진다. 모든 해커는 소프트웨어의 문제점을 이용하여 보안에 구멍을 뚫을 수 있고, 그러한 구멍은 모든 소프트웨어에서 발생할 수 있다. 예를 들어, 리눅스나 유닉스 시스템에서 SMTP 프로토콜을 이용하여 메일을 주고 받을 때 많이 사용되는 센드메일은 예전부터 보안에 많은 문제점이 있었으며, 이를 이용하여 시스템을 해킹한 사례가 많았다.

해커들의 공격으로부터 소프트웨어를 방어할 수 있는 유일한 방법은 방어 프로그래밍을 비롯한 소프트웨어 개발 보안 정책을 정의하는 것이다. 하지만, 아쉽게도 보안 문제를 고려한 개발 프로세스와 좋은 제품을 위한 개발 프로세스는 서로 상충하는 경우가 많다. 보안을 고려하여 설계된 소프트웨어는 소수에 불과하며, 대부분의 제품은 보안을 고려하지 않은 채로 개발이 시작되는 경우가 허다하다. 실제로, 오늘날에 충분한 시간을 갖고서 소프트웨어를 개발하는 것은 무리가 있으며, 이 때문에 제품을 빨리 만들려고 하는 프로그래머와 시간과 비용이 많이 드는 견고한 보안 정책을 세우는 설계자 사이에 심각한 딜레마를 유발하기도 한다.

이 글에서는 2회에 걸쳐 소프트웨어를 개발할 때 필요한 보안 정책에 대해서 살펴보기로 하자.

정책

소프트웨어에서의 보안은 보안 정책(policy)을 정하는 것에서부터 시작한다. 보안 정책은 개발자가 제품의 요구 사항을 따르는 데 도움을 주며, 코딩 표준과 개발 지침을 따르게끔 만들어준다. 특히, 이제 간신히 개발할 수 있을 정도의 실력을 가진 초보 프로그래머나 코더들에게 있어 안전한 코딩 정책은 매우 유용하다.

보안 정책은 모든 개발자들이 숙지해야 하는 것으로서, 모든 제품에 있어서 근본적인 요소이다. 개발자들은 보안 정책을 학습함으로써 제품에 표준적인 보안 체계를 제공할 수 있게 된다. 비록 코드 보안 정책이 작성할 제품에 따라서 크게 다르지만, 일반적으로 다음에 제시할 내용을 바탕으로 제품의 코드에 추가적인 보호 계층을 제공할 수 있을 것이다.

1. 제품의 요구 사항과 위험 관리

모든 소프트웨어 제품은 보안 요구 사항을 갖고 있다. 따라서 제품을 개발할 때에는 항상 제품의 보안과 관련된 부분을 염두해야 한다. 실제 프로젝트에서 보안과 비용은 동전의 양면에 비유할 수 있다. 보안에 신경을 쓰면 비용이 증가하게 되고, 비용을 줄이다 보면 보안이 허술해지는 트레이드 오프가 존재하는 것이다. 때때로, 제품의 보안 구멍을 남겨둬야 하는 경우도 발생하며, 이에 따라 비즈니스에 위험 부담을 허용하기도 한다.

일반적으로, 처음부터 보안을 염두해두고 시스템을 설계해야한다. 예를 들어, e-커머스에서 데이터를 주고 받는 데 초점을 둘 경우, 주고 받는 데이터를 암호화 할 것을 고려해야 한다. 또한 사용자가 웹을 통해서 입력한 신용카드 번호를 단순히 HTTP 프로토콜을 사용하여 입력 받을 지, 또는 HTTPS 프로토콜을 사용하여 암호화해서 입력 받을지를 프로젝트 초기에 결정하는 것이 좋다.

2. 에러 처리, 실패, 버그, 에러 상태

코딩 정책에 있어서 또 하나 중요한 것이 있다면 에러 처리에 대한 전략을 포함하고 있어야 한다는 점이다. 예를 들어, 자바는 예외(exception)를 지원하고 있다. 정책에는 예외가 어떻게 어디서 발생하는 지에 대한 목록이 포함되어 있어야 한다. 프로그램을 어떻게 테스트 할 것인지 그리고 실제로 어떻게 예외를 방어할 것인지에 대한 내용도 문서에 포함되어야 한다. 기타 try/catch 블럭에서 finally를 어떻게 구현할 지에 대한 표준도 정의되어 있어야 한다.

한 가지 일반적인 문제점인 프로그램의 실행이 실패할 때 어떤 상황이 발생하느냐에 관한 것이다. 만약 프로그램이 실패 이후에 불안전한 상태로 빠지게 된다면, 해커들은 실패가 발생하는 순간을 기다릴 것이다. 예를 들어, 버퍼 오버 플로우를 이용하여 해킹한 사례도 있다. 따라서 프로그램은 실행이 올바르게 되지 않고 실패할 경우에 시스템이 불안전한 상태로 빠지지 않는 방법을 갖고 있어야 한다.

3. 객체에 대한 접근 규약

보안 정책에는 언제 어떻게 객체를 사용할 지에 대한 내용도 정의되어 있어야 한다. private이 아닌 모든 클래스, 메소드, 객체 또는 변수는 공격을 위한 진입 지점이 된다. 따라서 기본적으로 모든 것들을 private으로 작성해야 한다. 만약 클래스, 메소드, 변수 또는 객체가 private이 아닐 경우, 왜 그렇게 했는지에 대한 내용을 정책 문서에 기록해야 한다.

자바 컴파일러는 이너 클래스(inner class)를 일반적인 클래스로 변환하며 따라서 이너 클래스 역시 보안 정책에서 다뤄야 하는 항목중의 하나이다. 일반적으로 이너 클래스는 같은 패키지에서 접근할 수 있으며, 또한 이너 클래스는 그 이너 클래스를 포함하고 있는 클래스의 모든 필드/메소드(심지어 포함하고 있는 클래스의 필드와 메소드가 private 이라 하더라도)에 접근할 수 있다. 따라서 이너 클래스에 대한 접근 정도를 알맞게 정해야 한다.

논-파이날(non-final) 클래스 역시 위험하다. 왜냐면 언제든지 알 수 없는 방법으로 그 클래스들을 상속할 수 있기 때문이다. 만약 논-파이날 클래스가 필요하다면 왜 그렇게 했는지에 대한 내용을 문서화해야 한다.

4. 민간함 정보

패스워드, 알고리즘, 암호화 키와 같은 정보는 유출되서는 안 되는 정보이다. 이러한 정보는 하드 코딩 되어서는 안 되며, 영구 메모리나 관리자 이외에는 접근할 수 없는 설정 파일에 저장하는 것이 좋다. 예를 들어, JDBC URL의 사용자 이름과 암호 부분을 하드 코딩했다고 해 보자. 이러한 정보는 자바 디컴파일러를 통해서 매우 손쉽게 유추해낼 수 있게 되며, 이 경우 데이터베이스에 저장되어 있는 데이터의 값이 원하지 않는 상태로 변경될 수 있게 된다.

5. 기존 소프트웨어와의 연동

필요할 경우 기존 소프트웨어와의 연동에 대한 표준을 정해야 한다. 만약 기존 소프트웨어가 다른 인크립션을 지원하거나 또는 더 적은 보안 표준을 지원할 경우 이것은 특히 중요하다. 기존 제품과 새로운 제품 사이의 신뢰도 정도를 반드시 언급해야 한다.

6. 접근(Access)과 승인(Authentication)

일반적으로, 퍼미션(permission)은 절대적으로 필요한 경우에만 부여해야 한다. 퍼미션을 부여할 때는 항상 최소한의 권한부터 부여해야 하며, 작업을 마칠 수 있는 시간 동안만 권한을 유지해야 하며, 또한 작업이 끝나면 그 권한을 다시 반환해야 한다.

퍼미션 승인은 주로 사용자 체크를 통해서 이루어지며, 사용자 체크의 대부분은 암호 기반의 메커니즘을 사용하고 있다. 따라서 프로그래머는 암호화 키나 암호를 코드내에 남겨두어서는 안 되며, 사용이 끝난 이후에은 그러한 정보를 메모리나 임시 저장 매체로부터 삭제해야 한다.

7. 문서화

문서화는 코딩, 디버깅을 위해서 중요하며, 특히 나중에 발생할지도 모를 법정 솟ㅇ이나 저작권 보호에 있어서 매우 유용하다. 예를 들어, 아파치 그룹에서 나오는 모든 제품은 비록 무료이긴 하지만 각 코드마다 저작권 정보를 표시하고 있으며, 이를 통해 저작권 보호를 받고 있다.

결론

Part 1에서는 코드를 보호하기 위한 보안 정책을 살펴보았다. 2부에서는 계속해서 안전한 코드를 작성하기 위한 몇 가지 코딩 보안 정책에 대해서 더 살펴보도록 하자.

Posted by 최범균 madvirus

댓글을 달아 주세요