본문 바로가기
△/SecureCoding

상대 디렉터리 경로 조작

by KkingKkang 2022. 11. 16.
728x90

- 외부 입력을 통하여 디렉터리 경로 문자열 생성이 필요한 경우, 외부 입력값에 대해 경로 조작에 사용될 수 있는 문자를 필터링하지 않으면, 예상 밖의 접근 제한 영역에 대한 경로 문자열 구성이 가능해져 시스템 정보누출, 서비스 장애 등을 유발 시킬 수 있다. 

- 즉, 경로 조작을 통해서 공격자가 허용되지 않은 권한을 획득하여, 설정에 관계된 파일을 변경할 수 있거나 실행시킬 수 있다. 

- 외부의 입력이 직접 파일이름을 생성할 수 없도록 한다. 불가피하게 직접 사용하는 경우, 다른 디렉터리의 파일을 접근할 수 없도록 replaceAll() 등의 메소드를 사용하여 위험 문자열(",/,\)을 제거하는 필터를 거치도록 한다. 

- 외부에서 받아들인 데이터 중 미리 정의된 케이스를 제외하고는 모두 무시하도록 한다. 

 

안전하지 않은 코드 ▼

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

 

안전한 코드 ▼

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("/user/local/tmp/"+name);
        if (file != null) file.delete();
   }
}

 

안전하지 않은 코드 2 ▼

import java.io.*;
import java.net.URLDecoder;
import java.sql.*;
import java.util.regex.*;

import javax.servlet.*;

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);
        
        }
   	}
 }

 

안전한 코드 2 ▼

import java.io.*;
import java.net.URLDecoder;
import java.sql.*;
import java.util.regex.*;

import javax.servlet.*;

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 doFile = new File(userHomePath + fileName);
            String filePath = doFile.getAbsolutePath();
            
            if(userHomePath.equals(filePath.substring(0, userHomePath.length()))==false) {
            //error
            }
            
            byte [] buffer = new byte [BUFFER_SIZE];
            FileInputStream inputStream = new FileInputStream(fileName);
            inputStream.read(buffer);
        
        }
   	}
 }

 

먼저 외부에서 입력받은 데이터경로(userHomePath + fileName)을 가지고 파일을 열어 doFile로 저장해둔다.

그 다음 doFile의 절대경로값을 알아낸 후 (getAbsolutePath()) 이것을 원래 입력받은 file 경로(userHomePath)와 비교하여 같지 않으면 파일을 처리하지 않고 그대로 프로세스를 종료한다. 

 

 

728x90

' > SecureCoding' 카테고리의 다른 글

HTTP 응답 분할  (0) 2022.11.16
절대 디렉터리 경로 조작  (0) 2022.11.16
크로스사이트 요청 위조  (0) 2022.11.16
신뢰 되지 않는 URL 주소로 자동 접속 연결  (0) 2022.11.15
위험한 형식 파일 업로드  (0) 2022.11.15

댓글