- 외부 입력을 통하여 디렉터리 경로 문자열 생성이 필요한 경우, 외부 입력값에 대해 경로 조작에 사용될 수 있는 문자를 필터링하지 않으면, 예상 밖의 접근 제한 영역에 대한 경로 문자열 구성이 가능해져 시스템 정보누출, 서비스 장애 등을 유발 시킬 수 있다.
- 즉, 경로 조작을 통해서 공격자가 허용되지 않은 권한을 획득하여, 설정에 관계된 파일을 변경할 수 있거나 실행시킬 수 있다.
- 외부의 입력이 직접 파일이름을 생성할 수 없도록 한다. 불가피하게 직접 사용하는 경우, 다른 디렉터리의 파일을 접근할 수 없도록 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)와 비교하여 같지 않으면 파일을 처리하지 않고 그대로 프로세스를 종료한다.
반응형
'Web Security > SecureCoding' 카테고리의 다른 글
HTTP 응답 분할 (0) | 2022.11.16 |
---|---|
절대 디렉터리 경로 조작 (0) | 2022.11.16 |
크로스사이트 요청 위조 (0) | 2022.11.16 |
신뢰 되지 않는 URL 주소로 자동 접속 연결 (0) | 2022.11.15 |
위험한 형식 파일 업로드 (0) | 2022.11.15 |
댓글