맞는데 왜 틀릴까..?

Java/Secure Coding

[Secure Coding] 민감-데이터의 수명을 제한하라

안도일 2023. 7. 24. 22:34

메모리에 있는 민감-데이터(sensitive data)는 오염되기 쉽다.

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

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

 

공격자의 민감-데이터 엑세스

 

동일한 시스템에서 응용 프로그램을 수행할 수 있는 공격자는 응용프로그램이 다음과 같을 때 민감-데이터에 엑세스할 수 있다.

 

  1. 사용 후에 내용이 삭제되지 않거나 garbage-collection 되는 객체에 민감-데이터를 저장하여 사용할 때
  2. 운영체제에 의해 디스크로 스왑아웃될 수 있는 메모리 페이지를 포함할 때 (메모리 관리 작업이나 최대절전모드를 위해)
  3. OS 캐시나 메모리에 있는 데이터의 복사본을 가지고 있는 버퍼(bufferedReader)에 민감-데이터를 보유할 때
  4. 제어흐름이 민감한 변수의 수명을 제한하지 않도록 허용하는 리플렉션(reflection)에 기반할 때
  5. 디버깅 메시지, 로그 파일, 환경 변수 혹은 쓰레드와 코어 덤프를 통해 민감-데이터를 노출할 때

 

최대절전모드(hibernation)

최대절전모드가 되면 RAM이 내용을 디스크 파일로 swap out 시킨 후 전원을 차단한다.
다시 부팅될 때 디스크로부터 RAM으로 다시 swap in 된다.

완벽한 완화책에는 기반하고 있는 운영체제와 자바 가상 머신의 지원이 필요하다.
예를 들어, 민감-데이터를 디스크로 swap out 하는 것이 문제라면 swapping과 최대절전모드를 허용하지 않는 안전한 운영체제가 필요하다.

 

 

부적절한 민감-데이터 사용 코드

 

 

부적절한 코드 - InputStreamReader 객체를 wrap 하도록 BufferedReader를 사용하고, 민감-데이터를 파일로부터 읽는 코드

 

 

  • BufferedReader.readLine() 메서드는 파일로부터 읽은 민감-데이터를 String 객체로 반환하는데, 이 객체는 데이터가 더 이상 필요하지 않게 되더라도 오랫동안 유지될 수 있다.
  • BufferedReader.read(char [], int, int) 메서드는 char 배열을 읽고 유지할 수 있지만, 프로그래머가 배열에 있는 민감-데이터를 사용 후 수동으로 지워야 한다.

 

 

 

솔루션 - 파일로부터 민감-데이터를 읽기 위해 직접 할당된 새로운 I/O를 사용

 

 

 

  • ByteBuffer는 Java NIO에서 사용되는 바이트 버퍼 클래스로, allocateDirect() 메서드를 사용하여 직접 할당된 바이트 버퍼를 생성한다.
  • 16*1024 바이트 (16KB) 크기의 직접 할당된 바이트 버퍼를 생성한다. 직접 할당된 바이트 버퍼는 JVM의 힙 메모리가 아닌 운영체제의 메모리에 할당된다.
  • 즉, 코드에서 데이터를 ByteBuffer에 읽어오고, 읽은 데이터를 따로 저장하는 변수나 처리하는 로직이 없으며, ByteBuffer의 clear() 메서드를 호출해 다음 읽기 작업을 준비한다.
  • 이로 인해 ByteBuffer에 읽은 데이터는 사용 후 곧바로 삭제할 수 있으며, 데이터는 여러 장소에 캐시 되거나 버퍼링 되지 않고 오직 시스템 메모리에만 존재한다.
  • 다이렉트 버퍼는 가비지 수집되지 않기 때문에 버퍼 데이터의 수동 삭제가 필수적임을 명심하자.