eval은 JavaScript 코드에서 문자열을 실행할 수 있는 기능을 제공하지만, 보안상 위험과 디버깅 어려움, 성능 저하 등의 이유로 사용을 피하는 것이 좋습니다. 대신 new Function()을 사용하여 문자열을 함수로 실행하는 방법을 사용하면 보다 안전하게 코드를 실행할 수 있습니다. 이 문서는 eval을 new Function()으로 변경하는 방법을 안내합니다.


eval 사용 예시

let x = 10;
let code = "x + 5";
let result = eval(code);
console.log(result);  // 15

위 예시에서 eval은 문자열로 제공된 JavaScript 코드를 실행하여 결과를 반환합니다. 그러나 eval은 다양한 보안 위험을 초래할 수 있습니다.


new Function() 사용 예시

new Function()은 문자열을 함수로 감싸서 실행하는 방법입니다. eval보다 상대적으로 더 안전한 방법으로 코드 실행을 제공합니다. new Function()은 다음과 같이 사용할 수 있습니다.

let x = 10;
let code = "x + 5";
let func = new Function('return ' + code);
let result = func();
console.log(result);  // 15

new Function()은 실행할 코드 문자열을 함수로 감싸며, 이 경우에는 return을 명시적으로 추가해야 합니다.


eval을 new Function()으로 변경하는 단계

단계 1: eval로 실행하려는 코드 문자열 추출

먼저 eval에서 사용되는 코드 문자열을 new Function()에서 사용할 수 있는 형태로 변환합니다. 예를 들어, eval에서 x + 5처럼 계산하는 코드가 있다면, 이 코드 문자열을 그대로 new Function()으로 넘길 수 있습니다.

단계 2: eval에서 실행되는 코드에 return 추가

new Function()은 실행하는 코드에서 값을 반환하려면 return 키워드를 사용해야 합니다. 따라서 eval에서 계산된 값을 new Function()으로 변환할 때는 반환값을 명시적으로 지정해야 합니다.

단계 3: 변수 접근 방식 변경

eval은 해당 코드가 실행되는 범위에서 변수를 직접 참조할 수 있지만, new Function()은 별도의 함수 범위 내에서 실행됩니다. 필요한 변수는 new Function()에 인자로 넘겨줘야 합니다.

예시:

eval 사용:

let x = 10;
let code = "x + 5";
let result = eval(code);
console.log(result);  // 15

new Function()으로 변경:

let x = 10;
let code = "x + 5";
let func = new Function('x', 'return ' + code);  // 'x'를 매개변수로 추가
let result = func(x);  // x 값을 전달
console.log(result);  // 15

위와 같이 new Function()은 코드 내에서 외부 변수를 참조하지 않기 때문에, 필요한 변수를 함수의 매개변수로 전달해야 합니다.


변경 시 고려사항

  • 보안: eval은 실행되는 코드가 악의적일 경우 심각한 보안 문제를 초래할 수 있습니다. new Function() 역시 외부 입력을 사용하기 전에 반드시 검증해야 합니다.
  • 디버깅: eval은 디버깅이 어려운 특성이 있습니다. new Function()은 함수로 변환되기 때문에 디버깅이 조금 더 용이할 수 있습니다.
  • 성능: eval은 실행 시에 파싱 및 컴파일 작업이 필요하므로 성능에 영향을 줄 수 있습니다. new Function()은 상대적으로 성능에 영향을 덜 미칩니다.

예외 처리

new Function()을 사용할 때 코드가 잘못된 경우 예외가 발생할 수 있습니다. 이를 처리하기 위해 try-catch 문을 사용할 수 있습니다.

let code = "x + 5";
try {
  let func = new Function('x', 'return ' + code);
  let result = func(10);
  console.log(result);
} catch (e) {
  console.error('Error executing code:', e);
}

결론

  • eval을 사용할 필요가 있을 때 new Function()을 사용하면 보안성과 성능 측면에서 더 안전한 대안을 제공합니다.
  • 코드를 new Function()으로 변경할 때는 변수를 매개변수로 전달하는 점에 유의해야 합니다.
  • eval 사용을 최소화하고, 필요하다면 new Function()을 통해 동적으로 코드를 실행할 수 있는 방법을 적용하는 것이 바람직합니다.

개요

Apache HTTP Server에서 입력값 검증이 미흡하여 발생하는 버퍼오버플로우 취약점(CVE-2021-44790)
공격자가 조작된 요청을 mod_lua*모듈로 처리 할 때 버퍼 오버플로가 가능한 취약점

 

영향받는 버전

Apache HTTP Server 2.4.51 및 이전 버전

 

해결방안

1. 취약점 업데이트 (패치 적용 前 업무시스템의 서비스 영향 검토 후 적용할 것)
    -   2.4.51 및 이전 버전의 경우, 최신 버전(2.4.52) 업그레이드 적용[2]
 
2. 임시 조치방안
    - mod_lua 모듈 非활성화 (디폴트로 비활성화 되어있음)
    ※ 모듈 확인방법 : 소스 트리의 httpd.conf 내 "LoadModule lua_module modules/mod_lua.so" 검색 > 주석 처리

관리자 계정명 관리

 

관리자 계정명 미변경 및 기본유저 로그인 가능할 시 취약하다.

관리자 콘솔 사용시 User name 확인
[4.x / 5.x] - /[Tomcat path]/conf/tomcat-users.xml

 

<tomcat-users> 
<role rolename=""tomcat""/>
  <role rolename=""admin-gui""/>
  <role rolename=""manager-gui""/>
  <role rolename=""role1""/>
  <user username=""autoever"" password=""autoever"" roles=""admin-gui,manager-gui""/>
  <user username=""tomcat"" password=""tomcat"" roles=""tomcat""/>
  <user username=""both"" password=""tomcat"" roles=""tomcat,role1""/>
  <user username=""role1"" password=""tomcat"" roles=""role1""/> </tomcat-users>

[6.x / 7.x / 9.x] - /[tomcat path]/conf/tomcat-users.xml

 

(apt-get 으로 설치한 경우 /etc/tomcat7/tomcat-users.xml에 있을 수 있음)

 

[시스템현황] [ tomcat dir ]\conf\tomcat-users.xml 'tomcat-user' 설정 미존재

 

 

조치사항

 

1. [4.x / 5.x] - 관리자 콘솔 사용시 User name 확인 및 변경

   [6.x / 7.x] – 아래의 설정 파일을 통해 User name 확인 및 변경 설정 파일 : /[Tomcat path]/conf/tomcat-users.xml

 

2. [4.x / 5.x] - 관리자 콘솔의 [User Definition | Users | RoleName]에서 계정명을 설정

 

3. [6.x / 7.x] - 기본 유저와 패스워드를 삭제 또는 주석으로 처리해 주어 기본 유저로의 로그인이 불가능 하도록 권고한다.

 

설정 파일 : /[Tomcat path]/conf/tomcat-users.xml

관리자 콘솔 관리

Default 포트(8080)를 사용하고 있고, 관리자 콘솔 사용시 취약하다.

Tomcat 관리자 콘솔 사용 유무 확인함.
예) http://[Domain]/manager, http://[Domain]/admin/

(단, Tomcat 5.5.x의 버전의 경우 admin을 따로 다운로드 받아 설치하여야 하며
6.0 이상의 버전엔 http://[Domain]/admin/ 자체가 존제하지 않으므로 http://[Domain]/manager 만 확인)

 

 

조치사항

1. Default포트인 8080은 공격자가 유추 할 수 있으므로, 유추할 수 없는 포트로 변경. 번호를 지정하여 사용하기를 권고함 (권장 포트 범위 : 1024~65534)

 

    - 설정 파일 : /[Tomcat path]/conf/server.xml

    - server.xml 파일 변경 후 Tomcat 서버를 Stop하고 다시 start 시켜야 적용됨


2. 필요 시에만 관리자 콘솔 운영을 권고함, 필요한 경우에 한하여 관리자 콘솔을 사용하고 불필요한 경우 프로세스를 종

 

XSS란?

XSS(cross-site scripting)는 웹페이지에 악의적인 스크립트 코드를 주입할 수 있는 취약점이다.

 

XSS(Cross Site Scripting) 방지를 위해 널리 쓰이는 훌륭한 lucy-xss-servlet-filter는 Servlet Filter 단에서 < 등의 특수 문자를 &lt; 등으로 변환해주며, 여러 가지 관련 설정을 편리하게 지정할 수 있어 정말 좋다.

그런데 그 처리가 form-data에 대해서만 적용되고 Request Raw Body로 넘어가는 JSON에 대해서는 처리해주지 않는다는 단점이 있다. 그래서 JSON을 주고 받는 API 서버의 경우에는 직접 처리를 해줘야 한다.

 

즉, Lucy는 RequestParameter관련한 지원만 해준다.

 

 

그래서 이를 보완하기 위해서 여러가지 방법이 있겠지만, 가장 많이 사용되는 방법인 Request를 Wrapping 하여 적용하도록 한다. (기존에 Lucy XSS Filter를 사용하고 있다는 가정하에 작성)

 

준비물 : 2개의 Java Class, web.xml, Lucy XSS Filter

 

# Lucy XSS Filter는 Maven Central Repository 에 배포되어 있다. pom.xml 에 아래와 같이 의존성을 선언한다.

1
2
3
4
5
<dependency>
    <groupId>com.navercorp.lucy</groupId>
    <artifactId>lucy-xss</artifactId>
    <version>X.X.X</version>
</dependency>
cs

 

 

RequestWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
 
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
 
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
 
import com.nhncorp.lucy.security.xss.XssFilter;
 
public class RequestWrapper extends HttpServletRequestWrapper {
    private byte[] b;
 
    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        XssFilter filter = XssFilter.getInstance("lucy-xss-sax.xml");
        b = new String(filter.doFilter(getBody(request))).getBytes("UTF-8");
    }
 
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bis = new ByteArrayInputStream(b);
        return new ServletInputStreamImpl(bis);
    }
 
    class ServletInputStreamImpl extends ServletInputStream {
        private InputStream is;
 
        public ServletInputStreamImpl(InputStream bis) {
            is = bis;
        }
 
        public int read() throws IOException {
            return is.read();
        }
 
        public int read(byte[] b) throws IOException {
            return is.read(b);
        }
    }
 
    public static String getBody(HttpServletRequest request) throws IOException {
        String body = null;
       BufferedReader br= null;
       StringBuilder sb= new StringBuilder();
        try {
            InputStream inputStream = request.getInputStream();
            if (inputStream != null) {
               br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = br.read(charBuffer)) > 0) {
                   sb.append(charBuffer, 0, bytesRead);
                }
              
            } else {
               sb.append("");
            }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (br!= null) {
                try {
                   br.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        body = sb.toString();
        return body;
    }
}
 
cs

 

실제 필터링 기능을 수행하는 Java class이다. 

주의할 부분은 해당 작업을 수행할 경우 한글이 깨져서 chain.doFilter(requestWrapper, response);가 수행될 때 Json 오류가 날 수 있다.

그러므로 br= new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 항목에 인코딩 설정을 명시해서 해당 오류를 피해 가도록 한다.

 

 

 

RequestBodyXSSFIleter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class RequestBodyXSSFIleter implements Filter {
    private List<String> extUrl;
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
       RequestWrapper reqWrapper = null;
        String path = ((HttpServletRequest) req).getServletPath();
 
        try {
            if (!extUrl.contains(path)) {
              
               reqWrapper = new RequestWrapper(request);
               chain.doFilter(reqWrapper , response);
            } else {
                chain.doFilter(request, response);
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String excludePattern = filterConfig.getInitParameter("extUrls");
       extUrl = Arrays.asList(excludePattern.split(","));
    }
 
    @Override
    public void destroy() {
    }
}
 
cs

 

requestBody에 XSS Filter를 적용할 경우 Multipart(일반적으로 파일 업로드) 일 때 파일이 손상되는 일이 발생한다.

이를 방지하기위해 파일을 송신하는 URL의 경우 web.xml의 init-param을 이용하여 필터링을 제외할 수 있다.

 

RequestBodyXSSFIleter의 init시 filterConfig에서 해당 파라미터에 접근하여 제외할 URL목록을 콤마(,)로 구분하여 작성 후 필터를 적용하지 않는 방법으로 우회할 수 있다.

 

 

web.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <!-- Xss Filter Start -->
    <filter>
        <filter-name>xssEscapeServletFilter</filter-name>
        <filter-class>com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>xssEscapeServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter>
        <filter-name>RequestBodyXSSFilter</filter-name>
        <filter-class>com.your.pkg.path.filter.RequestBodyXSSFIleter</filter-class>
        <init-param>
            <param-name>extUrls</param-name>
            <param-value>/linkUrl1,/linkUrl2,/linkUrl2</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>RequestBodyXSSFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- Xss Filter End -->
cs

 

서버 정보 노출 및 에러코드의 노출을 방지하기 위해 대부분의 사이트가 HTTP 403, 404 등 HTTP 에러 발생 시 별도의 에러 페이지로 리다이렉트 시키고 있다.

 

하지만 헤더정보를 통해 에러정보를 노출 시키고 있다. 

 

따라서 Error Page에서 Http Status를 강제로 고정시키는 처리가 필요하다. 

 

리다이렉트 되는 에러페이지에 <%response.setStatus(200);%> 입력 시 에러 페이지로 리다이렉트와 동시에 헤더 정보내 노출되는 에러코드 노출을 방지할 수 있다.



1
2
3
4
5
6
7
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<% response.setStatus(200); %>

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
cs

 

+ Recent posts