Recent Posts
Recent Comments
Link
06-30 12:53
Today
Total
관리 메뉴

삶 가운데 남긴 기록 AACII.TISTORY.COM

JAVA 보안 Path Traversal 본문

DEV&OPS/Java

JAVA 보안 Path Traversal

ALEPH.GEM 2022. 8. 5. 17:48

 

Path Traversal 디렉토리 경로 조작

상대 디렉토리 경로 조작(Relative Path Traversal)
외부 입력으로 디렉터리 경로 문자열 생성이 필요한 경우 외부 입력을 필터링 하지 않으면 시스템 경로 조작이나 시스템 정보 유출, 장애, 권한 획득 등을 유발할 수 있습니다.

외부 입력에 대해서 다른 디렉터리 파일에 접근 할 수 없도록 replaceAll() 등을 이용하여 위험한 물자열(", / \ 등)을 제거해서 방어합니다.

외부 입력은 받더라도 내부 처리는 미리 정의해 놓은 데이터(경로)를 사용합니다.

 

안전하지 않은 예

public void accessFile(Properties request){
...
    String name = request.getProperty("filename");
    if(name != null){
        File file = new File("/usr/local/tmp/" + name);
        file.delete();
    }
...
}

위에서 name 파라메터로 ../../../root/  이나 ../../../etc/passwd 등 허가되지 않은 경로 넘기면 해당 경로에 접근 할수도 있습니다.

 

안전한 코드의 예

public void accessFile(Properties request){
    String name = request.getProperty("user");
    if(name != null && !"".equals(name)){
        name = name.replaceAll("/", "");
        name = name.replaceAll("\\", "");
        name = name.replaceAll(".", "");
        name = name.replaceAll("&", "");
        name = name + "-report";
        File file = new File("/usr/local/tmp/" + name);
        ...
    }
}

 

안전하지 않은 예

public class DocumentService extends HttpServlet {
    private final String READ_DOCUMENT = "read_document";
    private final String USER_ID_PARAM = "user_id";
    private final String FILE_NAME_PARAM = "file_name";
    private final int BUFFER_SIZE = 256;
    ...
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String command = request.getParameter("command");
        ...

        if (command.equals(READ_DOCUMENT)) {
            String userId = request.getParameter(USER_ID_PARAM);
            String fileName = request.getParameter(FILE_NAME_PARAM);

            byte [] buffer = new byte [BUFFER_SIZE];
            FileInputStream inputStream = new FileInputStream(fileName);
            inputStream.read(buffer);
            ...
        }
        ...
    }
    ...
}

경로에 대한 확인하는 코드를 추가하고 먼저 외부에서 입력받은 경로를 가지고 파일을 열어  docFile로 저장하고 그 저장된 파일의 절대 경로를 알아낸 후(getAbsolutePath()) 이것을 원래 입력받은 파일 경로(userHomePath)와 비교하여 같지 않으면 처리하지 않고 에러처리 하는 방식으로 방어합니다.

 

안전한 예

public class DocumentService extends HttpServlet {
    private final String READ_DOCUMENT = "read_document";
    private final String USER_ID_PARAM = "user_id";
    private final String FILE_NAME_PARAM = "file_name";
    private final int BUFFER_SIZE = 256;
    ...
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String command = request.getParameter("command");
        ...
        if (command.equals(READ_DOCUMENT)) {
            String userId = request.getParameter(USER_ID_PARAM);
            String fileName = request.getParameter(FILE_NAME_PARAM);
            fileName = URLDecoder.decode(fileName);
            
            String userHomePath = getUserHomeDir(userId);

            File docFile = new File(userHomePath + fileName);
            String filePath = docFile.getAbsolutePath();

            if(userHomePath.equals(filePath.substring(0, userHomePath.length()))==false) {
                // Error 처리
                return;
            }
            byte [] buffer = new byte [BUFFER_SIZE];
            FileInputStream inputStream = new FileInputStream(filePath);
            inputStream.read(buffer);
            ...
        }
        ...
    }
    ...
}

 

 

 

 

Absolute Path Traversal (절대 경로 조작)

외부 입력이 파일 시스템의 경로를 직접 제어할 수 있게 하면 시스템 파일도 접근 가능해지기 때문에 안전하지 않습니다.

외부 입력을 통해 파일이름의 생성 및 접근을 허용하면 안되고, 접근이 허용된 파일의 리스트에서 선택하도록 프로그램을 작성해야 합니다.

 

안전하지 않은 예

public class DocumentService extends HttpServlet {
	private final String APPLY_STYPLE_COMMAND = "apply_style";
	private final String USER_ID_PARAM = "user_id";
	private final String STYLE_FILE_NAME_PARAM = "styple_file_name";
	private final int BUFFER_SIZE = 256;

	//생략
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String command = request.getParameter("command");
		//생략
		if (command.equals(APPLY_STYPLE_COMMAND)) {
			String userId = request.getParameter(USER_ID_PARAM);
			String styleFileName = request.getParameter(STYLE_FILE_NAME_PARAM);

			String userHomePath = getUserHomeDir(userId);

			byte[] buffer = new byte[BUFFER_SIZE];
			FileInputStream inputStream = new FileInputStream(userHomePath + styleFileName);
			inputStream.read(buffer);
			//생략
		}
		//생략
	}
	//생략
}

외부 입력(userId)로부터 직접 파일을 생성하는 경우 공격에 노출 됩니다.

 

안전한 예

public class DocumentService extends HttpServlet {
	private final String APPLY_STYPLE_COMMAND = "apply_style";
	private final String USER_ID_PARAM = "user_id";
	private final String STYLE_FILE_NAME_PARAM = "styple_file_name";
	private final int BUFFER_SIZE = 256;
	private Hashtable<String, String> styleFileNames;

	//...
	public DocumentService() {
		styleFileNames = new Hashtable<String, String>();
		styleFileNames.put("Normal", "NormalStyle.cfg");
		styleFileNames.put("Classic", "ClassicStyle_1.cfg");
		styleFileNames.put("Gothic", "ClassicStyle_2.cfg");
		//...
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String command = request.getParameter("command");
		//...

		if (command.equals(APPLY_STYPLE_COMMAND)) {
			String userId = request.getParameter(USER_ID_PARAM);
			String styleName = request.getParameter(STYLE_NAME_PARAM);

			String userHomePath = getUserHomeDir(userId);
			String styleFilePath = userHomePath + styleFileNames.get(styleName);

			byte[] buffer = new byte[BUFFER_SIZE];
			FileInputStream inputStream = new FileInputStream(userHomePath + styleName);
			inputStream.read(buffer);
			//...
		}
		//...
	}
	//...
}

외부 입력(userID)로부터 값을 받은 후 미리 정해진 styleFileNames 와 매칭시켜 실제적인 파일명으로 사용합니다.

그 후 경로값고 합쳐서 완전한 절대 경로 파일을 만든 후 생성합니다.

 

 

 

 

 

 

참고

http://cwe.mitre.org/data/definitions/23.html

 

CWE - CWE-23: Relative Path Traversal (4.8)

div.collapseblock { display:inline} CWE-23: Relative Path TraversalWeakness ID: 23Abstraction: BaseStructure: Simple The software uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize

cwe.mitre.org

http://cwe.mitre.org/data/definitions/22.html

 

CWE - CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (4.8)

div.collapseblock { display:inline} CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')Weakness ID: 22Abstraction: BaseStructure: Simple The software uses external input to construct a pathname that is intended to identif

cwe.mitre.org

 

https://www.owasp.org/index.php

 

OWASP Foundation, the Open Source Foundation for Application Security | OWASP Foundation

OWASP Foundation, the Open Source Foundation for Application Security on the main website for The OWASP Foundation. OWASP is a nonprofit foundation that works to improve the security of software.

owasp.org

 

http://cwe.mitre.org/top25/

 

https://cwe.mitre.org/top25/

 

cwe.mitre.org

 

http://cwe.mitre.org/data/definitions/36.html

 

CWE - CWE-36: Absolute Path Traversal (4.8)

div.collapseblock { display:inline} CWE-36: Absolute Path TraversalWeakness ID: 36Abstraction: BaseStructure: Simple The software uses external input to construct a pathname that should be within a restricted directory, but it does not properly neutralize

cwe.mitre.org

 

http://cwe.mitre.org/data/definitions/22.html

 

CWE - CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') (4.8)

div.collapseblock { display:inline} CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')Weakness ID: 22Abstraction: BaseStructure: Simple The software uses external input to construct a pathname that is intended to identif

cwe.mitre.org

 

 

 

 

 

 

 

 

728x90