자바 시큐리티에 대한 고찰임 영 주
서울특별시 관악구
서울대학교 물리학과
E-mail : cogito@newton.snu.ac.kr, cogito@plaza.snu.ac.kr
본 논문은 자바 언어가 가져올 수 있는 시큐리티 문제에 대해서 고찰하고 자바 실행 가능 웹브라우져(Java Enabled Web Browser이하 JEWB)에서의 보안 취약점들의 이용 가능성과 자바의 시큐리티 메커니즘들에 대해서 평가한다. 실행가능 내용(Excutable Content 이하 EC)에 대해서 우선 논의한 후에, 이 논문은 EC의 잠재적 취약성과 그에 대해 제안된 자바의 메커니즘에 대해서 그리고 마지막으로 이러한 메커니즘들의 효과에 대해 분석하고자 한다.Keywords: Java , Security , WWW
그러나,자바 애플릿의 증가된 실행 능력은 또한 잠재적인 시큐리티 문제의
소지를 안고 있다. 사용자가 웹을 항해하는 동안, 사용자가 애플릿이 자신들의
파일을 지우거나 그들의 사적인 정보를 네트워크를 통해 흘려보낼 가능성에 대한
불안감을 느낄 필요가 없어야 하는 것이다.
문제의 핵심은 컴퓨터상에서 프로그램의 실행시 호스트의 특정한 자원에 대한
접근을
프로그램이 해야만 한다는 데 있다. EC의 경우에 실행되고 있는 프로그램은
신뢰될 수 없다.
자바 코드를 다운로드해서 실행하는 웹브라우져가 신뢰할 수 없는 프로그램에
대해서
자원에 대한 접근을 제어하지 못한다면, 해커가 호스트를 침입한 것과
마찬가지로 시스템에 손상을 입힐 수 있는 것이다. 불행하게도, 자원에 대한
접근을 완전히 금지하는 것등의 단순한 솔루션은 존재하지 않는다. 이유는
프로그램이 자원에 대한 접근을 허용하는 첫번째 이유가 유용한 프로그램이
그러한 자원들에 대해서 반드시 접근해야 하기 때문이다. 예를 들면 에디터에서
파일저장 기능이 없다면 이는 유용한 프로그램이라고 할 수 없는 것이다.
그러므로, 유용하면서도 안전한 EC를 원한다면, 자원에 대한 접근은 매우
주의깊게 통제되어야만 한다. 이하에서는 우선 고려해야 할 자원에 대해서
설명하고 충분한 안전장치가 없을 경우 발생할 수 있는 몇 가지 가상적
시나리오에 대해서 고찰한다.
주어진 자원의 몇몇 요소들은 다른 것들에 비해 전체 접근을 해용하기 때문에
더욱
"위험"하다. 예를 들면 파일 시스템에 대해 알려지지 않은 프로그램이 전체적
접근을
허용하는 보안 정책을 유용하다고 판단할 수는 없다. 반대로, 대부분의
보안정책은
디스플레이 장치에 대해서는 전체적 접근을 허용하는것을 제한하지는
않는다.(물론, 다른 자원들에 대해서는 적절히 통제를 받는다는
가정하에서이다.)
EC(Excutable Content)를 제공하는 자바의 방식은 JEWB가 자바 인터프리터와
런타임
라이브러리를 보유하게 하는 것이다. 이러한 웹브라우져는 애플릿이라고
불리우는 자바 프로그램들을 다운로드할 수 있고 자바인터프리터가 이를
실행하게 만든다. 이러한 모델과 함께, 세가지 기본적언 계층이 존재하는데:
자바 언어, 표준 자바 라이브러리 그리고 웹브라우져이다. 시스템 전체의
시큐리티는 이러한 세 계층의 개개의 시큐리티에 기본적으로 의존하는
구조이다.
C++과 마찬가지로 자바는 객체들의 변수와 메쏘드에 대해서 접근을 제어할
능력을
가지고 있다. 이러한 접근 제어는 신용할 수 없는 코드에 대해 객채가
부적절하게 사용되지 않는다는 보장을 가능하게 한다. 예를 들면, 자바
라이브러리는 파일 객체에 대한 정의를 포함하는데, 파일 객체는 읽기용으로
public 메쏘드(누구나 호출 가능) 가지고 있고 또한 읽기용으로 저수준의
private 메쏘드(객체 메쏘드에 의해서만 호출가능한)를 가지고 있다. public
호출은 우선 시큐리티에 대한 체크를 수행하고 난 다음에 private 읽기를
호출한다. 자바는 신뢰되지 않은 코드가 파일 객체를 안전한게 조정하는 것을
public 메쏘드에 대한 접근만을 허용함으로써 보장하는 것이다. 그러므로,
접근제어능력은 프로그래머들이 라이브러리에 대한 접근제어를 정확히
명시함으로써 언어에 시큐리티가 보장된 라이브러리 작성을 가능하게 한다.
접근제어를 보장하는 다른 능력은 파이널(final)로서 클래스나 메쏘드를
선언하는 것이다. 이것은 악의적인 프로그래머가 핵심적인 라이브러리 클래스를
서브클래스로 사용하거나, 한 클래스의 메쏘드를 오버라이딩하는 것을 막아준다.
그러므로, 자바는 실제 메쏘드가 어떤 객체에 관계되었을때 객체의 컴파일시
타입에 맞게 쓰여진 파이널 메쏘드임을 보장한다. 이는 또한 객체의 행동의
특정한 부분이 수정되지 않았음을 보장하는 것이다.
자바는 또한 타입에 안전하게 설계되었다. 이것은 컴파일시 타입과 변수의
실행시 타입의 호환성이 보장됨을 의미한다. 이는 cast가 컴파일과 실행하는
경우에 그들이 유효한지를 확인하기 위해서 모두 체크됨을 의미한다. 이는 접근
제어를 비껴가기 위해서 객체에 대한 접근을 가장하는 것을 예방해 준다. 이미
보여진 File에 대한 예에서 보듯이, 이는 악의적인 코드가 File 객체에 대해
캐스팅을 하는 것에서 악의적인 코드의 MyFile 타입이 File타입과 동일한 형태를
지니지만 모든 메쏘드가 public인것을 막아준다.
라이브러리의 접근 제한은 기본적으로 세가지 메커니즘에 의존한다. 첫번째는
자바
언어의 오브젝트 메쏘드와 시스템 자원에 대한 접근 제한을 공급하는 방식으로서
이루어지고 두번째는 특정한 ClassLoader가 특정한 코드를 로드하는 방식으로
이루어진다. 마지막 메커니즘은 글로벌 SecurityManager가 특정한 작용의
유용성을 검사하는 명백한 호출을 사용함으로써 이루어진다.
ClassLoader
자바 실행은 새로운 클래스를 로드하는데 명백한 두가지 방식을 가진다.
기본적인 방식은 로컬 호스트의 파일에서 클래스를 로드하는 것이다. 이 방식은
ClassLoader를 포함하지 않는다. 네트워크를 이용하는 등의 방식으로 클래스를
로딩하는 것은 관련된 ClassLoader를 요구한다. (예를 들면 특화된 방법을
지니는 ClassLoader 클래스의 서브타이프) ClassLoader는 클래스의 원시
데이터를 내부의 클래스를 대표하는 데이터 구조로 변환하는 역할을 한다.
자바 애플릿들이 가능한한 포터블하기 위해서, 자바 컴파일러는 머신 코드를
컴파일하지 않고 대신에 아키텍쳐에 무관한 가상 기계용 바이트 코드를
컴파일한다. 자바 인터프리터는 이러한 바이트코드를 인터프리트해서 프로그램을
실행한다. 그러므로, 애플릿은 소스코드나 머신 코드가 아니라 바이트코드
형태로 전달된다. 이것은 ClassLoader가 바이트코드만을 다룰 수 있음을
의미한다.
클래스파일 검사(Class File
Verification)
컴파일러가 타입을 검사하지만 "위험한" 컴파일러를 사용함으로써 공격을 받을
수 있는 가능성이 여전히 있다. 핫자바(tm)브라우저와 같은 어플리케이션은
소스코드를 전송받은 후 컴파일을 하지 않는다; 이런 어플리케이션은 이미
컴파일된 클래스파일들을 전송받는다. 핫자바 브라우저는 그 바이트 코드가 믿을
만한 자바컴파일러에서 생성되었는지 또는 인터프리터를 공격하려는 적으로부터
생성되었는지 확인할 방법이 전혀 없다.
외부에서 유입된 모든 클래스파일들은 검사기에서 확인되어야 한다. 검사기는 그
클래스 파일이 올바른 포맷으로 이루어져 있는지 확인한다. 바이트코드에 대한
"구조적 제한"의 세트를 구성하는 간단한 논리 확인자를 사용함으로써
바이트코드를 검사할 수 있다.
바이트코드 검사기는 인터프리터의 퍼포먼스를 향상시키기도 한다. 각
인터프리트된
명령어에 대해서 수행되어야 했을 실행시간 확인을 하지 않아도 된다. 오히려
인터프리터는 이러한 확인이 이미 수행되었다고 간주할 수 있다. 각각에 대한
확인은 그다지 크게 부담되지 않을 수 있어도 각 바이트코드 명령어의 실행에
대한 몇가지 기계 명령어가 없어질 수 있다.
예를 들어 인터프리터는 코드가 다음 제한들을 가능한한 준수한다는 것을
고려해서
작동할 수 있게 된다.
다른 언어들도 자바의 클래스포맷으로 컴파일될 수 있다. 바이트코드검사기는
자바언어에만 제한되지 않음으로써 사용자가 파이어월 건너에서 어떠한 코드도
안전하게
불러들일 수 있도록 해 준다.
클래스파일 포맷
각 자바 클래스파일은 분할된 상태로 네트워크를 통해 전송되어진다.
클래스파일은
간단히 보면 8비트 데이터의 흐름이다. 모든 16비트나 32비트의 값들은 각기 둘
혹은 넷의 8비트 바이트들로 변형된 상태로 읽혀진 후 마지막에 가서 하나의
전체로 합쳐진다.
기본 포맷
하나의 클래스파일은 다음을 포함한다:
클래스의 각 필드와 메쏘드에 대해서 클래스파일의 바이트는 필드나 메쏘드의
이름과 그 유형을 나타낸다. 필드나 메쏘드의 타입은 시그너처(signature)라고
불리는 스트링에 의해서 나타내어진다. 필드는 필드의 초기값을 알려주는
추가적인 속성을 가질 수 있다. 메쏘드는 그 메쏘드를 실행시킬 코드를 알려주는
추가적인 속성을 가질 수 있다.
실제로는 메쏘드가 중첩된 코드 속성을 가질 수 있다. 코드라는 속성은
인터프리터를
통해 실행될 바이트코드라는 것을 나타낸다. 메쏘드는 또한 그 메쏘드의
기계코드를 구현한 SPARC-CODE나 386-CODE와 같은 속성을 가질 수 있다. 핫자바
브라우저는 이 머신코드가 구조적으로 안전한 것인지 판별할 수 없기 때문에
신뢰할 수 없는 출처에서 나온 모든 메쏘드의 기계모드를 무시한다.
핫자바 브라우저에서는 현재 네트워크를 통해서 전송되는 어떠한 클래스파일도
신뢰할
수 없다고 간주한다. 핫자바 브라우저는 로컬 클래스 파일에서 불러들여진
기계코드만을 실행한다. 어쨌거나 클래스포맷은 작성자가 클래스파일에 전자
서명을 남길 수 있도록 한다. 앞으로의 브라우저들은 신뢰할 수 있는 출처에서
나온 전자 서명된 코드를 좀 더 신뢰하게 될 것이다.
바이트코드와 가상기계
코드 속성은 가상기계의 기계언어에서 메쏘드를 실행시키기 위한 정보를
제공한다. 각
메쏘드에 대한 정보는 다음을 포함한다:
자바 가상기계는 여섯가지의 원시 유형을 정의한다:
자바 가상기계는 또한 몇가지의 배열 유형을 정의한다: 이 유형들은 integers,
longs, single floats, double floats, handles, booleans, bytes (8-bit
integers), shorts (16-bit integers) 그리고 Unicode 문자들의 배열을
포함한다. 핸들의 배열은 그 배열이 잡을 수 있는 객체의 클래스를 표시하는
추가적인 유형필드를 갖고 있다.
각 메쏘드 활성화는 구분된 Expression-Evaluation 스택과 로컬 레지스터의
세트를 갖고 있다. 각 레지스터와 각 스택 위치는 하나의 integer, single
float, handle 또는 return address를 잡을 수 있어야 한다. longs와 double
floats는 두 연속적인 스택 위치나 두 연속적인 레지스터에 맞아 들어야 한다.
가상기계 명령어들("opcodes")은 낮은 숫자가 매겨진 레지스터의 인덱스를
사용하면서 레지스터에서 longs와 double floats를 가리켜야 한다.
스택과 레지스터의 객체들은 (반드시) 태그된 것은 아니다. 가상기계 명령어
조합은
옵코드들이 다른 원시 데이타 유형에서 작동하도록 한다. 예를 들어 ineg, fneg,
lneg 그리고 dneg의 각 negate는 그 스택의 가장 위쪽에 있는 아이템들이지만 각
스택의 가장 위쪽의 아이템이 각각 순서대로 integer, single float, long 또는
double float이라고 받아들인다.
바이트코드 명령어들은 몇가지 범주로 나뉠 수 있다:
각 바이트코드는 0 또는 추가적인 오퍼랜드 정보의 바이트가 뒤에 따라 오는
1바이트
옵코드로 이루어져 있다. 두 가지의 "테이블 검색" 명령어 에 대한 예외를
제외하고서는 모든 명령어들은 옵코드에 근거한 정해진 길이를 갖게 된다.
검사 프로세스(The Verification
Process)
검사기는 4가지의 과정을 통해 작동한다.
과정 1
첫번째 과정은 가장 간단한 과정이다. 이 과정은 그 클래스가 인터프리터로 처음
읽혀졌을 때 일어난다.
이 과정은 클래스파일이 클래스파일의 포맷을 갖추고 있는지 확인한다. 첫번째
몇
바이트가 올바른 매직 넘버값을 갖고 있어야 한다. 모든 인식된 속성이 적절한
길이이어야 한다. 클래스파일은 잘려지거나 끝 부분에 추가적인 바이트가
있어서는 안 된다. 상수풀은 알아볼 수 없는 정보를 갖고 있어야 안 된다.
과정 2
두번째 과정에서는 검사기가 클래스파일의 포맷에 대해서 좀 더 깊이 검사를 해
본다.
검사기는 바이트코드를 검사하지 않고 수행할 수있는 모든 검사를 수행한다.
과정 2에서 찾아지는 에러들은 다음의 것들이다:
필드와 메쏘드 레퍼런스들이 검사될 때에 이 과정은 주어진 필드와 메쏘드가
실제로
주어진 클래스에 존재하는지 확인하지 않는다는 것을 잊으면 안된다; 이
과정에서는 유형 시그너쳐가 실제 존재하는 클래스를 가리키는지 여부도
확인하지 않는다. 그보다는 그저 그 시그너쳐가 규칙에 맞는 시그너처로
"보여야" 하는 것이다. 좀 더 자세히 확인하는 것은 과정 3이나 4에서
이루어진다.
과정 3
이 과정은 클래스 검사에서 가장 복잡한 과정이다. 각 메쏘드에 대한
바이트코드들이
검사된다. 데이타흐름 분석이 각 메쏘드에 대해서 수행된다. 프로그램 상의
주어진
어떠한 위치에서, 그 지점으로 도달하기 위해 어떠한 코드경로가 잡혀지든
검사기는 항상 다음의 항목들을 확인한다:
이 과정에 대한 좀 더 자세한 정보는 바이트코드 검사기(The
Bytecode Verifier)섹션에 나와 있다.
과정 4
효율을 높이기 위해서 과정 3에서 수행될 수 있었던 몇가지 검사들이 실제로 그
코드가 실행될 때까지 미루어진다. 검사기의 과정 3은 그 클래스파일이 반드시
로딩되어야 될 때까지 클래스파일을 로딩하지 않는다.
예를 들어 만일 어느 메쏘드가 유형 foobarType의 객체를 돌려주는 또다른
메쏘드를
호출하고 그 객체가 같은 유형의 필드로 곧바로 할당된다면 검사기는 유형
foobarType이 존재하는지 확인하는 수고를 하지 않는다. 그러나 그 객체가 유형
anotherType의 필드로 할당된다면 foobarType가 anotherType의 서브클래스인지를
확인하기 위하여
foobarType와anotherType 둘 다의 정의(definition)가 로드되어야 한다.
어떤 클래스를 레퍼런스하는 명령어가 처음으로 실행되면 검사기는 다음의
것들을
한다:
명령어가 처음으로 메쏘드를 호출하거나 필드를 억세스하거나 변경하면 검사기는
다음의 것들을 한다:
검사기의 이 과정은 스택 객체의 유형은 조사할 필요가 없다. 그 조사는 과정
3에서 이미 수행되었다.
조사가 수행된 이후에 바이트코드 스트림의 명령어는 다른 형태의 명령어로
대치된다.
예를 들어 옵코드 new는 new_quick로 대치된다. 이 또다른 형태의 명령어는 이
명령어에 대한 조사가 이미 수행되었고 다시 조사할 필요가 없다는 것을
나타낸다. 과정 3에서 이 _quick명령어가 나타나는 것은 잘못된 것이다.
SecurityManager는 조건에 맞게 자원에 접근을 허용하는데 극도로 유연하고
강력한
방식을 보장해 주고 있다. 접근을 체크하는 SecurityManager의 메쏘드는 조건적
접근 제어 정책을 구현하는데 필요한 인자들로 넘겨지는데, 이는 코드의
출처(로컬이나 네트워크) 결정하는 실행 스택을 체크하는 능력을 가지는 것과
마찬가지이다.
잠재적으로 위험한 시스템 자원을 생성할 가능성이 있는 라이브러리 코드에 대한
표준적인 접근 방식은 위험하지 않은 연산들에 대해서만 접근을 허용하고 제한된
기반에서만 접근가능한 시스템 호출에 대해 시큐리티 검사를 수행하는
것이다.(SecurityManager를 사용)
SecurityManager는 핵심적인 시스템 자원에 대한 접근을 통제한다. 이것은
JEWB의
구현자가 SecurityManager를 서브클래싱하고 특정한 메쏘드를 오버라이딩하거나
새로운 버젼을 시스템SecurityManager로써 설치하는 것에 의해 특정한 보안
정책을 구현하는 것을 가능하게 해준다. 서브클래스된 SecurityManager는 보안
정책을 구현하기 때문에, 웹브라우져의 SecurityManager의 버젼이 정확히 구현된
것이 매우 중요하게 된다. 극단적으로, JEWB가 시스템 SecurityManager를
설치하지 않았을 경우에는, 애플릿은 로컬 자바 에플리케이션과 같은 접근
권한을 가지게 될 것이다.
웹 브라우져의 시큐리티 정책은 SecurityManager의 수단들이 매우 유연한
인터페이스를
제공하기 때문에 임의적으로 복잡해질 수 있다. 프로그램될 수 있다면 어떠한
시큐리티
정책도 사용될 수 있는 것이다. 예를 들어, 시큐리티 정책은 SecurityManager가
어떤
사용자가 어떤 접근을 시도했는지에 대해서도 조사할 수 있게 한다.
자바가 제공하는 executable content에 대한 보안 모델에 대한 분석은 두
단락으로 행해질
것이다. 첫번째 단락에서는, 자바의 고수준 설계가 논의될 것이다. 두번째
단락에서는,
구현의 보다 특정한 부분의 유용성에 대해서 논의될 것이다.
자바의 보안 모델은 거의 전적으로 다운로드된 바이트코드를 검사하는 능력에
의존한다,
그 능력은 의도되지 않은 자원에 대한 접근을 금지할 수 있도록 분류하고
라이브러리를 쓸
수 있는 것을 의미한다. 또한, 웹 브라우져의 개발자들이 우수한 보안 정책을
구현하고
코드를 쓸 수 있는 것을 의미한다.
자바 프로그램을 컴파일된 바이트코드 형태로 변환하기로 한 결정은 시큐리티
측면에서는 의문을 불러일으키는 사항이다. 시스템은 자바 소스코드가 바이트
코드 대신에
쓰일 수 있다면 더욱 안전할 것이다. 바이트코드의 사용은 바이트코드의 검증
과정을 필요로
한다. 만일 자바소스코드가 쓰였다면, 코드의 안전성은 소스를 직접적으로
인터프리팅하거나 자바코드를 로컬 상에서 신뢰할 수 있는 컴파일러를
사용함으로써
보장될 수 있었을 것이다. 이것은 시큐리티에 대한 단순한 접근일 수 있는데
이는 자바
컴파일러는 이미 신뢰할 수 있기 때문이다.(자바 실행 시스템은 로컬
바이트코드에
대해서는 검사를 수행하지 않는다.) 다른 언어로 된 프로그램(바이트코드)이
호환성이
있는가에 대한 체크를 수행하는 프로그램에 대한 첨가는 시스템에 또다른
실패의 가능성을
더한다.
보안성있는 라이브러리를 작성하는 것
우수한 라이브러리를 작성하고 검증하는 과정은 자바의 시큐리티에 있어 가장
중요하다고 하는데에는 이견이 있을 수 없다. Drew Dean과 Dan Wallach가 쓴
Security Flow in
the HotJava Web Browser라는 논문에는 핫자바가 라이브러리 구현상의 에러로
인해 붕괴될
수 있는 좋은 예들을 보여주고 있다. Dean과 Wallach는 핫자바 1.0 alpha3
라이브러리의
구현상의 약점을 지니고 있음을 지적한다. 그들은 많은 수의 변수와 메쏘드가
퍼블릭으로
접근 가능하며, 시큐리티 체크를 하지 않아서, 시큐리티의 구멍을 허용하는 것을
증명했다.
이러한 종류의 문제들이 자바의 베타 버젼 라이브러리들에서는 해결이
이루어졌지만,
그러한 에러들은 정확한 검증이 단순한 작업이 아님을 보여주는 것이다.
그러므로 자바의 시큐리티는 상당히 큰 코드들의 정확한 구현에 의존한다.
이러한 상황은
자바의 설계가 매우 유연한 시큐리티 모델을 제공하고자 한 결과이다.
프로그래머에게
시스템 시큐리티에 대한 조작을 가능하게 함으로써, 자바 제작자들은 잠재적인
보안의
취약성을 노출하지만 유연함을 제공했다.
자바 시큐리티의 유효성을 검사하기 위해서는 언급된 각각의 자원들에 대해서
제어하는
적절한 방법이 있는가에 대한 검사를 하는 것이 필요하다.
자원들에 대한 접근 제어에 대한 분석을 바탕으로, 자바가 2.2에서 언급된
다양한 공격에
대해서 어떻게 방어할 수 있는가를 고려해 본다.
1. 소개(Introduction)
자바는 썬마이크로시스템 사에서 개발된 간결하고 객체지향적이고, 플랫폼에
무관한
실행이 보장되는 프로그래밍 언어이다. 이러한 특징 중 가장 중요한 것은
플랫폼에 무관한 실행 즉 포터블 하다는 것이다. 포터블하다는 것은
네트웍상에서 프로그램들 또한 동적으로 로드되고 로컬하게 실행된다는
것이다.
특히, 애플릿이라고 하는 작은 프로그램들이 로드되고 사용자의 웹브라우져에서
실행되는 동안 사용자는 웹을 "서핑"할 수 있다.(핫자바가 자바언어로 쓰여진
그러한 브라우져이고, 네스케이프 2.0은 그러한
자바애플릿을 지원한다.) 이러한 개념들이 매우 강력한 것은 틀림없지만, 새로운
보안
문제를 초래하는 것 또한 확실하다. 자바언어와 실행 시스템들은(여기에는
라이브러리, 컴파일러, 바이트코드 인터프리터등이 포함됨) 선사가 자바의
안전성을 주장했듯이 이러한 보안상의 문제들을 해결하기 위한 시도를 하고
있다.1.1. Excutable Content에 대한 고찰
EC는 실행 가능한 코드를 데이타와 함께 보낼 수 있다는 개념이다. EC는 웹에
강력한
상호작용성을 부여할 수 있기 때문에 주목을 받고 있다. 지난 수년간 웹의
사용은 폭발적으로 증가했는데, 여기에는 웹에 기존의 응용프로그램을 웹에 맞게
수정하려는 시도 역시 증가해왔다. 폼과 스크립트를 통해서 많은 기능을 웹이
추가해 왔지만, 이러한 방법은 이미 한계를 보이고 있으며, 사용자가 로컬
호스트상에서 프로그래밍언어로 짜여진 프로그램을 웹 브라우져를 이용해 실행할
수 있게 될 경우 웹브라우져의 능력은 기존의 어플리케이션들과 필적하게
된다.
2. 문제점들
자바 시큐리티에 대한 논의에 앞서, EC에 의해 발생될 수 있는 문제점들에 대한
이해가 선행되어야만 한다. EC의 장점은 소프트웨어의 실행 능력과 종류의
다양성의 증가에서 비롯된다고 할 수 있다.
2.1.어떠한 것들이 제어되어야 하는가?
실행될 프로그램을 위한 안전한 환경의 중요한 부분은 자원을 구분하여 이러한
자원들에 대해 특정한 형태로 제한된 접근을 허용하는 것이다. 도표 1은 그러한
자원들의 부분적인 예를 보여주는데, 자원의 이용가능성에 의한 공격의 형태도
마찬가지로 분류하고 있다. 가능한 네 가지 공격의 종류는:
이 도표가 가능한 모든 공격을 망라한 것이 아니라는 것에 주의해야 한다. 이는
단지
주어진 자원에 대한 공격에 대해 예를 들고 있는 것에 불과하다. 예를 들면,
스푸핑프로그램은(사용자에게 실제와 다르게 보이는 프로그램) 원래의
프로그램과 같은 자원을 사용하는 것처럼 사용자를 속이기 위해 모든 자원을
공격을 위해 사용하고자 할 것이다.
자원
은폐
이용가능성
무결성
불쾌감 유발
파일 시스템
V
V
V
V
네트워크
V
V
메모리
V
V
V
V
출력 장치
V
입력 장치
V
V
V
프로세스 제어
V
V
사용자 환경
V
V
V
시스템 호출
V
V
V
V
2.2. 시나리오들
여기에서는 악의적인 프로그램이 수행할 수 있는 공격의 유형을 표시하는 몇가지
시나리오에 대한 예를 보이고자 한다. 공격의 분류는 이미 언급된 것과
마찬가지이다. 물론 가능한 모든 공격이 포함된 것은 아니고, 단지 발생할 수
있는 문제에 대한 감을 제시하기 위한 것이다.
3. 자바의 시큐리티 메커니즘
자바는 프로그래밍언어이다. 일단 자바가 웹과 무관한 어플리케이션으로
개발환경으로
쓰일 수도 있고 애플릿개발용으로도 쓰일 수 있다는 사실을 기억해야 한다.
그러므로 필자의 자바 시큐리티에 대한 논의는 실제로 EC에 대한 자바 언어의
사용에 대한 것이다.
3.1. 자바 언어에 대한 고찰
자바는 C++과 비슷한 객체 지향 언어이다. 시큐리티 관점에서 본 중요한 언어적
특징은 변수와 메쏘드에 대해서 클래스 내부에서 접근 제어를 사용하는 것, 타입
정의들의 안전성, 언어의 데이터 형으로서 포인터의 부재, 가비지 콜렉션의
사용(자동적으로 메모리를 재분배), 분리된 네임스페이스의 사용등이다.
3.2. 라이브러리들
스탠다드 자바 실행 환경은 다양한 유용한 라이브러리들로 가능해지는데, 이는
파일
시스템에 접근하거나, 네트워크에 접근하는것, 윈도우 툴킷이나 이외에 다양한
툴을
포함한다. 라이브러리의 정확한 분류는 매우 중요하다. 언어 자체는 안전한
라이브러리를 제공할 능력을 지니지만, 라이트러리 코드가 분류되지않고 정확히
쓰여지지 않을 경우 시스템이 안전할 수는 없다. 라이브러리가 자바 실행시의
2.1에서 언급한 시스템 자원에 대한 접근을 가능하게 하는 한 부분이기 때문에,
라이브러리의 정확한 구현은 핵심적인 중요성을 지닌다.
검사기는 자바컴파일러와는 독립적이다. 현재의 컴파일러에 의해 생성되는 모든
코드를 체크하지만 검사기는 현재의 컴파일러가 생성할 수 없는 코드들도
확인한다. 구조적인 기준에 만족하는 바이트코드의 어떠한 조합이라도 검사기에
의해 확인될 것이다.
상수 풀은 여러가지 데이터의 상이한
조합이다. 상수풀의 각 데이터는 다음 중 하나가 될 수 있다:
클래스파일의 다른 어떤 부분도 스트링, 클래스, 필드 또는 메쏘드에 대한
레퍼런스를
만들어내지 않는다. 이러한 모든 레퍼런스는 상수풀의 인덱스들에 의해서
이루어진다.
이 바이트코드는 자바 가상기계를 위한 것이다.
이 테이블의 각 값들은 바이트코드, 예외 유형 그리고 예외
핸들러에
대한 오프셋에 시작오프셋, 종료오프젯을 부여한다. 만일 표시된
유형의 예외가 시작오프셋과 종료오프셋에서 표시된 코드 안에서
발생한다면 그 예외에 대한 핸들러는 주어진 핸들러 오프셋에서
발견될 것이라는 것을 그 값이 의미한다.
3.3. Security Manager
현재의 자바 버젼에서는, SecurityManager는 상세히 언급되어 있지 않다.
그럼에도, 자바 베타 버젼과 함께 배포된 검사코드에서 그리고 어떠한 문서가
존재하는지 읽음으로서, SecurityManager의 개발 목적에 대해서 추론할 수 있다.
SecurityManager는 특정한 종류의 행동을 검사하기 위해 호출되도록 설계된
다수의 메쏘드를 포함한다. SecurityManager 클래쓰는 직접적으로 사용되지
않는다. (각각의 체크는 보안상의 예외를 검사하는 것을 기본으로 한다.),
대신에 서브클래스가 되고 시스템 SecurityManager로서 설치되도록 되어 있다.
서브클래스가 된 SecurityManager는 지정된 시큐리티 정책을 실행하는데 사용될
수 있다.
public boolean mkdir(String path) throws IOException {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkWrite(path);
}
return mkdir0();
}
시큐리티 체크의 예시. 이 예는 기본적인 접근 방식을 보여준다: public
메쏘드
mkdir은 시스템SecurityManager를 체크(체크가 통과되지 않을 때는 예외를
생성하는)하고 다음에 저수준의 private 메쏘드인 mkdir0을 호출한다.3.4. Java Enabled Browser(자바 가능 브라우져)
웹 브라우져 또한 시스템의 보안에 있어서 중요한 역할을 한다. 웹 브라우져는
다운로드된 자바 코드를 실행하는 보안 정책을 정의하고 구현한다. JEWB는 자바
인터프리터와 실행 시간 라이브러리와 SecurityManager 및 다양한 ClassLoader를
포함할 것이다. 시큐리티 관점에서 본다면, SecurityManager의 웹 브라우져상의
구현이
ClassLoader의 구현보다 더욱 중요하다.
4.분석
4.1. 설계
왜 바이트코드인가?
물론 바이트 코드를 사용하는데는 많은 이유가 있다. 우선, 그것은 확실한
추상화를
보장하는데 이는 자바 프로그램에 대한 역분해 공학을 예방한다. 이것이
사실이긴 하지만,
바이트코드가 역컴파일하는 것이 불가능한 것은 아니다. 그리고 소스 코드를
직접
다루는다른 코드 추상화 기술들이 존재한다. 다음으로, 바이트코드의 표현은
크기가
줄어들게 한다. 현재로는 이것이 사실은 아니다. 현재의 모든 예에서,
HotJava브라우져의
소스코드를 포함해서, 소스와 바이트코드는 거의 크기에 있어서 일치한다.
세번째로,
바이트코드 검사 과정은 컴파일 과정보다 빠를 수 있다. 그러므로 프로그램을
다운로딩하고
실행하는데 계산상 많은 시스템 자원을 사용할 필요가 없고 낮은 latency를
제공한다. 이러한
논의는 공평하게 강요적인데, 자바팀이 계산에 많이 의존하는 프로그램에
대해서는 "Just in
Time"컴파일러를 사용할 수도 있다고 암시한 바가 있지만, 컴파일이 예방적이지
않음을
의미한다. 마지막 논의는 바이트 코드 검사기가 전형적인 컴파일러보다 덜 복
잡한
프로그램이어서, 정확성의 검사가 단순한 과정이라는 것이다. 사실 컴파일러는
모든
바이트코드가 신뢰성 있는 바이트코드 검사기로 검사될 수 있기 때문에 신뢰성을
가질
필요가 없다.(로컬 코드는 효율성을 이유로 해서 컴파일 시에 단 한번만 검사될
수 있다.)
시큐리티 문제는 라이브러리가 적절히 작성되었다고 해도 자바가 가능한
웹브라우져의
프로그래머가 정확히 SecurityManager에서 그들을 정확히 구현하고 명시해야
한다는 사실
때문에 더욱 어려워진다. SecurityManager는 기존의 더욱 확대된 메커니즘들에
비해서
유연한 시큐리티 정책을 수립하는데 특정하며 캡슐화된 방법을 가능하게 한다는
점에 있어
분명한 발전이다. 그럼에도 자바 시스템의 시큐리티에 대해 윕 브라우져가
직접적인 조작을
할 수 있는 사실은 명세와 구현에 있어 에러의 확률을 증가시킨다. 자바 자체는
매우 엄격한
검사를 수행하지만, 자바 가능한 브라우져가 자바의 내장 시큐리티에 의존하면서
그다지
엄격하지 않을 수 있는 것은 분명하다.4.2구현
이러한 자원들 중 일부에 대한 제어는 빠져 있다. 우선, 현재의
SecurityManager는 상위
레벨 윈도우에 대한 생성의 제어에 대한 메쏘드를 가지고 있지 않다.(그들이
안전하지
않음을 표시할 수 없음을 제외하고서라도), 또한 표시될 수 있는 것이나 들을 수
있는 사항에
대한 제어도 빠져 있다. 다음으로, 사용자의 입력에 대한 제어를 통제하는
메커니즘이
존재하지 않는다. 다양한 입력 장치에 대해서 보다 특정한 시큐리티 정책을
사용할 필요가
있는 상황이 분명히 존재한다. 마지막으로, 애플릿은 현재 새로운 객체를
생성함으로써
임의의 메모리 공간을 할당할 수 있다. 메모리 할당의 문제는 직접적인 위협을
제공하지
않기 때문에 평가하기가 어렵다. 그러한 문제는 브라우져가 자바가 사용가능한
메모리의
양을 제한할 수 있기 때문에 대단한 것은 아니다. 브라우져는 또한 현재의 자바
애플릿을
죽이는 메쏘드를 공급할 수 있는데, 이는 메모리를 회복가능하게 한다.4.3시나리오들
주어진 분석은 자바가 보다 위험한 형태의 공격을 예방하는데 효과적임을
보여준다.
불쾌감 유발 공격은 자바를 사용하지 않는 현재의 웹 브라우져에 또한 가능함이
언급하고자
한다. 서비스 거부 공격에 대해서는 안전히 예방하기란 매우 어렵다. 10개
이상의 윈도우를
생성하는 것을 금지하거나 100킬로바이트 이상의 메모리 할당을 금지하는
시큐리티 정책을
생각해 볼 수는 있지만, 이는 매우 임의적이다. 대신에, 유저가 애플릿이나
애플릿이 사용할
수 있는 모든 자원에 대해 권한을 가지는 웹브라우져가 더 나은 대안이라고
생각한다.
다행스럽게도 그러한 메커니즘은 구현이 가능할 것이다.