본문 바로가기
자바 시큐어 코딩

민감-데이터의 수명을 제한하는 자바시큐어코드

by 웹하는빡통 2020. 3. 30.

※ 귀찮아도 한번 읽고 보자!

 

자바 시큐어 코딩 chapter1의 안전성부분은 자바 프로그래밍 언어와 런타임 시스템은 안전성을 염두에 두고 설계되었다.

예를 들어 프로그래머가 명시적 포인터를 사용하지 않도록 하며 널 포인터를 참조하면 예외(exception)를 발생시킨다. 

이와 유사하게 배열이나 문자열의 범위를 벗어나 엑세스해도 예외가 발생된다.

자바는 타입에 대해 엄격하게 처리하는 언어이다 선술타입과 변환에서와 같이 모든 암묵적 타입 변환에 대해 플랫폼을 독립적으로 잘 정의되어 있다.

 

자바 가상 머신(JVM:Java Virtual Machine)바이트코드가 자바 언어 규격을 준수하면서 수행되도록 보장하기 위해 바이트코드 검증기를 내장하고 있다.(Java SE 7에서는 언어에서 정의한 검사가 적절히 이루어져 우회할 수 없도록 한다.)

 

자바 클래스 로더 메커니즘JVM으로 클래스가 로드될 떄 신뢰된 시스템 클래스와 신뢰가 불분명한 클래스를 식별할 수 있다. 외부 소스로부터 온 클래스들이 디지털 서명되어 있으면 권한을 부여받을 수 있다.  이 디지털 서명은 클래스 로더가 검사하여 클래스를 확인하는데 도움을 준다. 또한 자바는 프로그래머가 시스템 정보, 파일, 소켓과 프로그래머가 사용하고자 하는 다른 보안에 민감한 자원에 대해 엑세스를 제어할 수 있도록 확장성 있고 섬세한 보안 메커니즘을 제공한다. 이 보안 메커니즘은 런타임 보안 관리자(rentime security manager)가 보안 정책을 집행하도록 요구할 수 있다. 

 

보안관리자와 보안 정책은 보통 커맨드-라인 인자를 이용하여 지정하지만, 프로그램으로 설치될 수도 있다. 그렇게 함으로써 기존의 보안 정책에서 허용하지 않는 동작도 실행할 수 있도록 해준다. 클래스 로더 메커니즘이 제공하는 식별 방법을 이용하여 시스템 자바 클래스 외의 클래스에게까지 자원 엑세스 권한이 확장될 수 있을 것이다. 

 

기업 자바 응용프로그램은 신뢰할 수 없는 입력을 수용해야 하고, 복잡한 서브시스템과 상호작용해야 하기 때문에 공격당하기 쉽다. 만약 응용프로그램 안에 사용된 컴포넌트들이 공격당하기 쉬운 경우라면 응용프로그램에 대한

인젝션 공격(XSS, XPath와 LDAP 인젝션 등)이 가능하다. 이를 완화하는 효과적인 전략은 번역되기 전에 입력을 화이트리스트화하고 출력을 인코딩하거나 이스케이핑하는 것이다. 

 

이 장에서는 자바 기반 응용프로그램에 대하여 안전성을 보장하기 위한 가이드라인을 기술한다. 

 

 

01. 민감-데이터의 수명을 제한하라.

메모리에 있는 민감-데이터(Sensitive data)는 오염되기 쉽다.  동일한 시스템에서 응용프로그램을 수행할 수 있는 공격자는 응용프로그램이 다음과 같을 때 민감-데이터에 접근 할 수 있다. 

 

1. 사용 후에 내용이 삭제되지 않거나 가비지 수집(garbage-collection)되는 객체에 민감-데이터를 저장하여 사용할 때.

 

2. 운영체제에 의해 디스크로 스왑아웃될 수 있는 메모리 페이지를 포함할 때(예로 메모리 관리 작업이나 최대절전모드(하이버네이션)를 위해) -

 

※최대절전모드(hibernation)가 되면 RAM이 내용을 디스크 파일로 스왑아웃 시킨 후 전원을 차단한다. 그리고 다시 부팅될때 디스크로부터 RAM으로 다시 스왑인된다. 

스왑아웃: 메모리에 있는 데이터를 보조기억장치에 저장.

스왑인: 다시 메모리로 읽어들이는것을 말함.

 

3. OS 캐시나 메모리에 있는 데이터의 복사본을 가지고 있는 버퍼(BufferedReader)에 민감-데이터를 보유할 때 

 

4. 제어흐름이 민감한 변수의 수명을 제한하지 않도록 허용하는 리플렉션에 기반할 때

 

5. 디버깅 메시지, 로그파일, 환경 변수 혹은 쓰레드와 코어 덤프를 통해 민감-데이터를 노출할 때.

 

이럴듯 메모리가 사용 후 삭제되지 않는 데이터를 포함한 경우에 민감-데이터 누출 가능성이 높아진다.

노출의 위험을 제한하기 위해 프로그램은 민감-데이터의 수명을 최소화해야 한다. 

 

완벽한 완화책(즉, 메모리 데이터를 간단하게 보호하는 방법)에는 기반하고 있는 OS와 자바 가상 머신의 지원이 필요하다.

 

 

부적절한 코드.

해당 예제는 콘솔로부터 사용자 이름과 패스워드 정보를 읽어서 String 객체에 패스워드를 저장한다.

이 인증정보는 가비지 수집기가 String에 관련된 메모리를 수거할 때까지 노출되어 있기 때문에 취약하다. 

 

※ throws IOException 모든 특이사항은 던져(throw)버린다는 말로 즉 익셉션(예외)가 발생하면 해당 클래스에서 벗어나게 된다는 것이다. 쉽게 말해 자바에서는 런타임시 발생하는 여러가지 예외들을 처리하는 별도의 메커니즘을 가지고있는데  throws 키워드는 실행시간에예외가 발생했을 경우 해당 예외를 직접처리하지 않고 다른 곳에서
처리하도록 예외를 던지겠다 라는 의미임. 

 

※ 예외처리: 런 타임 오류를 처리하도록 설계된 기능으로 

 예측 가능한 오류, 일반적이지 않은 오류, 완전하게 예측하지 못하는 오류이런 모두를 잡아내는

 구체적인 방안을 제공한다. 

 

적절한 코드.  

해당 코드는 민감-데이터 수명제한 관련해서 적절한 솔루션으로 작성된 코드로

c.readline이 아닌 c.readPassword() 메소드를 사용하여 String 객체가 아니라 일련의 문자로

패스워드를 반환한다. 결과적으로 프로그래머는 사용 후 곧바로 배열에서 패스워드를 지울 수 있다. 

 

부적절한 코드(2). 

또 다른 예제로 InputStreamReader 객체를 wrap하도록 BufferedReader를 사용하므로써 민감-데이터를 파일로부터 읽을 수 있도록 한다.

Stream : 바이트 단위의 입출력(스트림은 바이트 단위는 바이트 단위로 연결하고 캐릭터 단위는 캐릭터 단위로 연결하는 것이 원칙임)

Reader/Writer : 캐릭터 단위의 입출력

InputStreamReader: 바이트 스트림을 문자스트림으로 변환.

OutputStreamReader: 문자 스트림을 바이트 스트림으로 변환.  

 

br.readLine() 메소드는 민감-데이터를 String 객체로 변환하는데. 이 객체는 데이터가 더 이상 필요하지 않게 되더라도 오랫동안 유지될 수 있다. 

 

적절한코드(2).

해당 예제는 파일로부터 민감-데이터를 읽기 위해 직접 할당된 NIO(New Input/Output)를 사용한다. 

이로써 데이터는 사용 후 곧바로 삭제될 수 있으며, 여러 장소에 캐시되거나 버퍼링되지 않는다. 데이터는 오로지 시스템 메모리에만 존재하게 된다. 

 

※ 다이렉트 버퍼는 가비지 수집이 되지 않아 버퍼 데이터의 수동 삭제가 필수적임!!

댓글