저번에, 경로 조작 공격을 이 글에서 다루었습니다. 글이 난이도에 비해서 꽤 길었는데요. 요약하면 이거였습니다. 클라이언트의 입력을 곧이 곧대로 믿지 말라. 이것에 대해서 조금 더 찾아보면, 방지책으로 절대 경로를 쓰라고 되어 있습니다. 이 답글이나, 이 문서에서도 강조하고 있는 부분이기도 합니다. 데이터 파일들은 특정한 경로 안에 있을 것이기 때문입니다.

 

 

[관련글]

사용자의 입력값과 path traversal 공격

 


 File 클래스를 보면, getAbsolutePath와 getCanonicalPath가 있습니다. 아래 예제를 보겠습니다.

 

 

 테스트 케이스는 하나입니다. ..\\.idea입니다. 이것은 프로젝트 폴더의 상위 디렉토리로 이동해서 .idea로 이동하겠다는 의미입니다. 출력 결과만 보도록 하겠습니다.

 

 

 Absolute Path는 \..\이 들어갔습니다. 이는, 상위 경로로 이동했음을 의미합니다. 그런데, Canonical Path는 .idea의 절대 경로가 나와 버립니다. 이 둘의 차이는 간단합니다. AbsolutePath 메서드의 결과는 같은 파일에 대해서 여러 개가 나올 수 있다는 점입니다. 예를 들어서, 현재 프로젝트가 군청색으로 표시한 것을 루트로 잡고 있다고 해 보겠습니다.

 

 

 그러면 군청색에서 data 폴더로 접근하는 방법은 뭐가 있을까요? 단순히 현재 위치에 있는 data 폴더로 가도 될 겁니다.

 

 

 그런데, 2번 위로 올라간 다음에, b 폴더, c 폴더를 거쳐서, data로 오는 방법도 있습니다.

 

 

 또는, 한 번 위로 올라간 다음에 c, data를 거치는 방법도 있습니다. 아니면 이런 방법도 있을 겁니다.

 

 

 data, de를 거쳤다가 다시 상위 폴더로 올라오는 방법. 생각보다 많은 가짓수가 있습니다. getAbsolutePath 메서드는 이러한 경우를 다 출력해 줍니다. 예를 들어, 현재 base가 a/b/c였는데, data를 거친 다음에 de를 거친 다음에 상위 폴더로 올라온 경우에는 base에다가 /data/de/..를 덧붙일 겁니다.

 

 일례로 예제 1의 프로그램은 C:\Users\chokw\IdeaProjects\test2가 base였습니다. 그리고 File 객체 f를 생성하기 위해 인자로 줬던 path가 "..\.idea"였습니다. 이 때, f.getAbsolutePath의 리턴값은 "C:\Users\chokw\IdeaProjects\test2\..\.idea"였어요. 반면에, f.getCanonicalPath의 리턴값은 "C:\Users\chokw\IdeaProjects\.idea"였어요. 여기서 중요한 차이점은 내가 상위 폴더로 얼마나 이동을 하건, CanonicalPath는 절대 경로로만 표현이 된다는 점입니다. 중간에 symlink나 바로가기를 타지 않는다고 가정하면, 상위 폴더로 이동하지 않고 올 수 있는 가장 짧은 경로로 표현이 된다는 것 정도로 이해하면 좋을까요?

 


 그러면 어떻게 Path Traversal 공격을 막을 수 있을까요? 제가 링크한 문서에서는 2가지 방법을 소개하고 있는데요. 이 중에, 한 가지 방법을 써 보도록 하겠습니다.

 

 

 먼저, basePath는 데이터 파일이 저장되는 디렉토리입니다. 여기에서는 프로젝트 내의 data 폴더로 잡았습니다. 다음에 10번째 줄에서는, dataFile이 basePath인 프로젝트 내의 data 폴더에 저장이 된 파일을 불러올 거라고 가정하고 입력을 받고 있어요. 그런데, 악의적인 사용자는 "..\..\..\..\..\..\..\..\..\boot.ini" 이런 식으로도 입력을 할 수 있을 겁니다.

 

 아니면, mysql과 같은 설정 파일을 볼 수도 있을 겁니다. 이것을 어떻게 막으면 좋을까요? dataPath의 CanonicalPath의 접두어가 data 폴더의 CanonicalPath인지 검사하면 될 겁니다.

 

 

 만약에 그렇다면, dataPath의 CanonicalPath의 리턴값이 노란색이나 연노란색 부분 중 하나라는 의미입니다. 트리로 따지면, data의 자식이라는 의미입니다. 그렇지 않으면, data 파일이 data 폴더 내에 없을 겁니다.

 

 

 군청색 부분에 있을 겁니다. 그 경우를 걸러내면 됩니다.

 

 

 해당 부분을 걸러내는 코드는 위와 같습니다. 12번째 줄에서 걸러내고 있습니다.

 

 


 간단하게 test를 해 보겠습니다.

 

 

 먼저 ..\..\..\1.txt를 입력해 봅시다. 그러면, not valid data path라고 출력이 되면서 Exception이 발생합니다.

 

 

 1.txt가 입력되면, 정상적으로 처리가 됩니다.