보안 공부/소스코드 보안약점 진단

소스코드 보안약점 진단 - HTTP 응답분할

H.J.World 2021. 12. 24. 10:10
728x90
반응형

소스코드 보안약점 진단 // 소프트웨어 보안약점 진단 // SW 보안약점 진단과 같이 다양한 이름으로 불리는 진단 과업 중 하나이다.

SW개발보안은 해킹 등 사이버공격의 원인인 보안약점을 SW개발단계에서 사전에 제거하고 SW 개발 생명주기의 각 단계별로 수행하는 일련의 보안활동을 통하여 안전한 SW를 개발·운영하기 위한 목적으로 적용하는 개발체계이다.

해당 내용은 KISA에서 발간하는 취약점 진단 가이드 항목을 기준으로 작성한다.


11. HTTP 응답분할

가. 개요

HTTP 요청에 들어 있는 파라미터(Parameter)가 HTTP 응답헤더에 포함되어 사용자에게 다시 전달 될 때, 입력값에 CR(Carriage Return)이나 LF(Line Feed)와 같은 개행문자가 존재하면 HTTP 응답 이 2개 이상으로 분리될 수 있다. 이 경우 공격자는 개행문자를 이용하여 첫 번째 응답을 종료시키고, 두 번째 응답에 악의적인 코드를 주입하여 XSS 및 캐시 훼손(Cache Poisoning) 공격 등을 수행 할 수 있다.

나. 보안대책

요청 파라미터의 값을 HTTP응답헤더(예를 들어, Set-Cookie 등)에 포함시킬 경우 CR, LF와 같은 개행문자를 제거한다.

다. 코드예제

외부입력값을 사용하여 반환되는 쿠키의 값을 설정하고 있다. 그런데, 공격자가 Wiley Hacker₩r₩nHTTP/1.1 200 OK₩r₩n를 lastLogin의 값으로 설정할 경우, 응답이 분리되어 전달되며 분리된 응답 본문의 내용을 공격자가 마음대로 수정할 수 있다.

- 안전하지 않은 코드의 예 JAVA -

//외부로부터 입력받은 값을 검증 없이 사용할 경우 안전하지 않다.
1: String lastLogin = request.getParameter("last_login");
2: if (lastLogin == null || "".equals(lastLogin)) {
3: return;
4: }
// 쿠키는 Set-Cookie 응답헤더로 전달되므로 개행문자열 포함 여부 검증이 필요
5: Cookie c = new Cookie("LASTLOGIN", lastLogin);
6: c.setMaxAge(1000);
7: c.setSecure(true);
8: response.addCookie(c);
9: response.setContentType("text/html");

 

- 안전한 코드의 예 JAVA -

외부에서 입력되는 값에 대하여 null 여부를 체크하고, 응답이 여러 개로 나눠지는 것을 방지하기 위해 개행문자를 제거하고 응답헤더의 값으로 사용한다.

1: String lastLogin = request.getParameter("last_login");
2: if (lastLogin == null || "".equals(lastLogin)) {
3: return;
4: }
// 외부 입력값에서 개행문자(\r\n)를 제거한 후 쿠키의 값으로 설정
5: lastLogin = lastLogin.replaceAll("[\\r\\n]", "");
6: Cookie c = new Cookie("LASTLOGIN", lastLogin);
7: c.setMaxAge(1000);
8: c.setSecure(true);
9: response.addCookie(c);

 

라. 진단방법

Response 헤더에 변수가 사용되는 것을 확인하고(①), 변수가 외부 입력값인지 확인한 후(②), 개행 문자(\r, \n) 제거를 위한 필터링 또는 검증절차가 있는지 확인한다. 외부 입력값에 대한 필터링 절차 가 없다면 취약하다.

1: protected void common(HttpServletRequest request, HttpServletResponse
response) throws Exception {
2: String fileid = request.getParameter(“fileid”);------------------------②
3:
4: BufferedInputStream in = null;
5: String uploadPath = properties.getString(propertyName + “UPLOAD”);
6:
7: try {
8: String fileName = uploadPath + “/” + fileid;
9:
10: response.setContentType(mimetype + “;charset=utf-8”);
11: String fileName = java.net.URLEncoder.encode(fileid, “UTF-8”);
12:
13: response.setHeader(“Content-Disposition”,
14: “attachment; filename=\”” + fileName + “\””);--------------------------①
15: response.setHeader(“Content-Transfer-Encoding”, “binary”);
16:
17: response.getOutputStream().flush();
18: response.getOutputStream().close();
19: }
20: catch(Exception e) {
21: if(in!=null) {
22: in.close();
23: }
24: }
25: finally{ }
26: }

- 정탐코드의 예 -

HTTP 응답분할은 공격자 보낸 조작된 입력값이 헤더에 쓰이고 이로 인해 HTTP 응답이 나누어지게 되는 취약점이다. response.sendRedirect 함수는 URL을 다른 곳으로 보내는 함수인데 그 방식은 헤 더에서 상태 값을 301로 바꾸고 가고자 하는 URL을 헤더에 입력하는 것이다. 이때 url에 공격자 의 입력값이 쓰이게 되면 조작된 입력값으로 인해 응답이 변경된다. 다음의 예제를 살펴보면, 5번째 라인에서 request의 파라미터에서 filename 값을 가져오고 7번째 라인에서 filename값을 이용하여 헤더에 값을 설정하고 있어 취약하다.

1: public voidservice(HttpServletRequest request, HttpServletResponse res) throws 
Serv- letException, IOException {
2: String contextRealPath = request.getSession().getServletContext().getRealPath(“/”);
3: String savePath = contextRealPath + “upfolder”
4: res.setContentType(“utf-8”);
5: String filename = request.getParameter(“file”);
6: res.setContentType(“application/octet;charset=utf-8”);
7: res.setHeader(“Content-Disposition”, “attachment;filename=” + filename);

 

- 오탐코드의 예 -

아래 코드를 살펴보면, 2번째 라인에서 request의 last_login 파라미터에서 가져온 값을 6번 라인 에서 개행문자를 필터링한 후 7번째 라인에서 lastLogin값을 쿠키에 설정하고 있어 취약하지 않다고 판단 한다.

1: String lastLogin = request.getParameter(“last_login”);
2: if (lastLogin == null || “”.equals(lastLogin)) {
3: return;
4: }
5: // 외부 입력값에서 개행문자를 제거한 후 쿠키의 값으로 설정
6: lastLogin = lastLogin.replaceAll(“[₩₩r ₩₩n]”, 
“”); 7:Cookie c = new Cookie(“LASTLOGIN”, 
lastLogin); 8: c.setMaxAge(1000);
9: c.setSecure(true);
10: response.addCookie(c);
11: response.setContentType(“text/html”);
12: ......

 

728x90
반응형