- HTTP 요청에 들어 있는 인자값이 HTTP 응답헤더에 포함되어 사용자에게 다시 전달 될 때 입력값에 CR(Carriage Return)이나 LF(Line Feed)와 같은 개행문자가 존재하면 HTTP응답이 2개 이상으로 분리될 수 있다.
- 이 경우 공격자는 개행문자를 이용하여 첫 번째 응답을 종료시키고 두 번째 응답에 악의적인 코드를 주입하여 XSS 및 캐시 훼손(cache poisoning) 공격 등을 수행할 수 있다.
CR = \r
LF = \n
- 외부에서 입력된 인자값을 사용하여 HTTP 응답헤더(Set Cookie 등)에 포함시킬 경우 CR, LF등을 제거하거나 적절한 인코딩 기법을 사용하여 변환한다.
안전하지 않은 코드 ▼
throws IOException, ServletException {
response.setContentType("text/html");
String author = request.getParameter("authorName");
Cookie cookie = new Cookie("replidedAuthor", author);
cookie.setMaxAge(1000);
response.addCookie(cookie);
RequestDispatcher frd = request.getRequestDispatcher("cookieTest.jsp");
frd.forward(request, response);
}
안전한 코드 ▼
throws IOException, ServletException {
response.setContentType("text/html");
String author = request.getParameter("authorName");
if (author == null || "".equals(author)) return;
String filtered_author = author.replaceAll("\r","").replaceAll("\n","");
Cookie cookie = new Cookie("replidedAuthor", filtered_author);
cookie.setMaxAge(1000);
cookie.setSecure(true);
response.addCookie(cookie);
RequsetDispatcher frd = request.getReqeustDispatcher("cookieTest.jsp");
frd.forward(request, response);
}
외부에서 입력되는 값에 대하여 널 여부를 체크하고, replaceAll을 이용하여 개행문자 \r \n을 제거하여 헤더값이 나누어지는 것을 방지한다.
▶ RequestDispatcher란?
- 클라이언트로부터 최초에 들어온 요청을 JSP/Servlet 내에서 원하는 자원으로 요청을 넘기는(보내는) 역할을 수행하거나, 특정 자원에 처리를 요청하고 처리 결과를 얻어오는 기능을 수행하는 클래스이다.
안전하지 않은 코드2 ▼
public class ShowRequestHeaders extends HttpServlet {
private final String CHANGE_PASSWORD_CMD = "change_password";
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String command = request.getParameter("command");
if(command.equals(CHAGE_PASSWORD_CMD)) {
Statement stmt = con.createStatement();
String userId = request.getParameter("user_id");
String newPasswd = request.getParameter("new_password");
String oldPasswd = request.getParameter("old_password");
String query = "UPDATE USER_INFO SET id = " + userId + ",passwd = " + newPasswd +
"Where passwd = " + oldPasswd;
stmt.executeUpdate(query);
}
}
}
안전한 코드 2 ▼
public class StatementInfo {
public Statement statement;
public Array<String> parameterNames;
}
public class ShowRequsetHeaders extends HttpServlet {
private final String CHAGE_PASSWORD_CMD = "change_password";
private final String CHAGE_PASSWORD_QUERY_STR = "UPDATE USER_INFO SET id = ?, password = ?" WHERE password = ?;
private Hashtable<String, StatementInfo> queryStatements;
public void initilize() {
queryStatement.put(CHAGE_PASSWORD_CMD, new StatementInfo(con.prepareStatement(CHAGE_PASSWORD_QUERY_STR),"user_id","new_password","old_password");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
String command = request.getParameter("command");
Statement statement = queryStatement.get(command).statement;
for(int parameterIdx = 0; parameterIdx < queryStatement.get(command).parameterName.size(); parameterIdx++ ) {
statemnet.setString(parameterIdx, queryStatement.get(command).parameterNames[parameterIdx];
}
statement.excuteQuery();
}
}
query문을 pre-compile 해두고, 암호 변경의 요청이 있을 때마다 인자 값을 적용하여 사용한다.
pre-compiled 방식을 사용하면 query문을 새로 작성하지 않기 때문에 query를 변조하는 악의적인 사용을 방지할 수 있다.
'Web Security > SecureCoding' 카테고리의 다른 글
보호 메커니즘을 우회할 수 있는 입력값 변조 (0) | 2022.11.18 |
---|---|
정수 오버플로우 (0) | 2022.11.17 |
절대 디렉터리 경로 조작 (0) | 2022.11.16 |
상대 디렉터리 경로 조작 (0) | 2022.11.16 |
크로스사이트 요청 위조 (0) | 2022.11.16 |
댓글