[여기보기] 링크 설정과 파일 다운로드/업로드 관리에서 중요한 것은 꺾이지 않는 마음

🧐 | 2023-10-19

[여기보기]는 “여기서 보안의 기본을 챙기고 가자”의 약자로, 개발 과정에서 꼭 최소한으로 챙기면 좋을 보안 기초 설정을 앞으로 하나씩 공유할 예정입니다. 기초 내용이 주를 이루겠지만, 혹시라도 빼먹고 계신 것이 없는지 가끔 한 번씩 둘러봐 주세요.

안녕하세요, 넷마블 보안실 보안개발팀 이석진입니다.

[여기보기] 적에게 내 WAS의 디렉터리와 파일을 알리지 말라, WAS 디렉터리 인덱싱 및 상위 디렉터리 접근 제한에서는 불필요한 디렉터리 인덱싱과 상위 디렉터리 접근 제한을 다루었습니다. 그런데 WAS에는 보안 설정을 점검하지 않는다면 불필요한 시스템 권한을 획득하거나 시스템의 과부하를 발생시킬 수 있는 요소가 또 있습니다. 운영체제의 중요 시스템 파일에 접근해 보안 문제가 발생하는 심볼릭 링크 사용과 다운로드나 업로드를 반복해 서버에 과부하가 발생하거나 시스템 권한을 획득하게 만드는 파일 다운로드와 업로드 문제입니다.

여러 번 강조하고 싶은 부분이지만 WAS 관리에 중요한 것은 꺾이지 않는 마음으로 보안 문제가 생기지 않도록 확인하고 또 확인하는 것입니다. 이번에는 WAS에서 심볼릭 링크 사용을 제한하는 방법과 파일 다운로드와 업로드를 제한하는 설정을 살펴볼 것입니다.

심볼릭 링크와 alias 사용 제한하기

윈도우에서 프로그램을 실행할 때 직접 exe 파일을 클릭해서 실행할 때는 거의 없을 것입니다. 바탕 화면, 작업 표시줄 등에 있는 바로 가기 아이콘을 클릭해서 사용할 것입니다. WAS 역시 IIS는 바로 가기 아이콘, 리눅스는 심볼릭 링크(Symbolic link)라는 기능으로 기존 WAS에 없는 파일 시스템에 접근이 필요할 때 바로 가기와 같은 개념을 지원합니다.

그런데 바로 가기 아이콘이나 심볼릭 링크는 복잡한 경로를 단순화시켜 원하는 기능에 접근할 수 있도록 하는 편의성을 제공하지만 잘못 사용한다면 운영체제의 중요 시스템 파일에 접근할 수 있는 보안 문제가 발생합니다. 예를 들어 리눅스 시스템의 루트 디렉토리(/)에 심볼릭 링크를 부여하면 웹 서버 구동 사용자 권한(nobody)으로 모든 파일 시스템의 파일에 접근할 수 있게 되어 “/etc/passwd” 파일과 같은 민감한 파일을 누구나 열람할 수 있는 부작용이 있습니다. 또한 아파치 HTTP 서버나 톰캣에 있는 Alias도 경로 설정의 편의성을 주지만 잘못 사용하면 시스템 권한을 열람하게 되는 부작용이 있습니다.

심볼릭 링크(Symbolic link, 소프트 링크)

내용은 존재하지 않으나 원본 데이터와의 링크가 있어서 해당 데이터를 가져와서 전달하거나 사용할 수 있는 개념입니다. 당연하겠지만 링크로 설정한 위치에 원본 데이터가 없으면 사용할 수 없습니다. C 프로그래밍 언어의 포인터와 같은 개념입니다.

조치 방안

시스템에 접근할 수 있는 위치에 있는 IIS의 바로 가기 아이콘이나 WAS에서 심볼릭 링크나 Alias 기능을 사용하지 못하도록 합니다.

IIS 7.0 이상

[윈도우] + [R] 키를 입력해 ‘실행’ 창을 연 후 ‘InetMgr.exe’를 입력하고 [확인] 버튼을 클릭합니다. IIS 관리자가 실행되면 왼쪽 창에서 [사이트] → [Default Web Site]를 선택한 후 오른쪽 [Default Web Site 홈]에서 [디렉터리 검색]을 선택합니다. 오른쪽에 있는 기본 설정을 선택하면 ‘사이트 편집’ 창이 나타납니다. [실제 경로] 부분의 값((보통은 C:\inetpub\wwwroot)을 확인한 후 해당 경로에 바로 가기 아이콘이 있다면 모두 삭제해줍니다.

아파치 HTTP 서버

설정 파일(apache2.conf 혹은 httpd.conf)에 있는 option 지시자의 FollowSymLinks를 제거합니다.

<Directory />
        # Options FollowSymLinks 삭제
        AllowOverride None
        Require all denied
</Directory>

<Directory /usr/share>
        AllowOverride None
        Require all granted
</Directory>

<Directory /var/www/>
        # Options Indexes FollowSymLinks 삭제
        AllowOverride None
        Require all granted
</Directory>

다음 사항도 점검하기 바랍니다.

  • conf-enabled, mods-enabled, sites-enabled 디렉터리에서 불필요한 심볼릭 링크가 설정되어 있다면 rm 명령어를 사용해 삭제해줍니다.
  • 설정 파일 중 Alias <접근 경로> "<원본 시스템 경로>" 형식의 설정 내용을 찾습니다. 그리고 시스템 보안에 위협이 될 수 있는 경로를 삭제해줍니다.

참고 링크: 아파치 HTTP 서버 공식 문서 – Apache Core Features

톰캣

설정 파일(server.xml 혹은 /Catalina/localhost/host-manager.xml, /Catalina/localhost/manager.xml 등)에 allowLinking="true" 옵션을 allowLinking="false"로 변경합니다. 기본값이 false이므로 해당 설정을 삭제해도 무방합니다.

<Context path="" reloadable="false" privileged="true"
         docBase="/home/iamironman/test/WebContent" workDir="" allowLinking="false"
         crossContext="true" />

참고 링크: 톰캣 공식 문서 – The Resources Component

NGINX

설정 파일(nginx.conf 혹은 sites-avaliable/default)의 root의 경로 설정이나 기타 불필요한 시스템 경로가 설정되었는지 확인합니다.

server {
    # 중간 생략
    root /var/www/index.html; # /var 이외의 별도 디렉터리를 만들어서 변경

    # 이후 생략
}

다음 사항도 점검하기 바랍니다.

  • modules-enabled, sites-enabled 디렉터리에서 불필요한 심볼릭 링크가 설정되어 있다면 rm 명령어를 사용해 삭제해줍니다.

불필요한 다운로드와 업로드 막기

보통 WAS를 운영할 때 파일 다운로드와 업로드 기능이 필요하지 않다면 막는 것이 좋습니다. 그런데 WAS의 특성상 완전히 막는 것은 어려울 때가 많습니다. 또한 대용량의 파일을 다운로드나 업로드는 WAS의 서버 자원을 사용하므로 다운로드나 업로드를 반복한다면 서버에 과부하가 발생할 수 있습니다. 또한 업로드하는 파일이 악성 코드라면 이 코드를 이용해 시스템 권한에 접근할 수 있는 상황도 발생합니다.

불필요한 다운로드와 업로드란?

내부 정책에 맞지 않는 다운로드와 업로드를 뜻합니다. 이를 막는 예로는 5MB 이상의 대용량 파일이나 확장자를 화이트리스트 방식으로 제한하는 것이 있습니다.

조치 방안

웹 프로세스의 서버 자원을 미관리(다운로드 및 업로드 용량 미제한)하는 상황을 점검하고 다운로드 및 업로드 용량을 제한해야 합니다.

IIS 7.0 이상

[윈도우] + [R] 키를 입력해 ‘실행’ 창을 연 후 ‘InetMgr.exe’를 입력하고 [확인] 버튼을 클릭합니다. IIS 관리자가 실행되면 왼쪽 창에서 [사이트] → [Default Web Site]를 선택한 후 오른쪽 [Default Web Site 홈]에서 [요청 필터링]을 더블 클릭해 실행합니다.

‘요청 필터링’ 항목이 열리면 오른쪽에 있는 [기능 설정 편집]을 클릭했을 때 열리는 ‘요청 필터링 설정 편집’ 창에서 파일 용량을 의미하는 [허용되는 최대 콘텐츠 길이(바이트)] 항목의 값을 30000000(약 30MB)으로 설정합니다.

또한 [사이트] → [Default Web Site]를 선택한 후 오른쪽 [Default Web Site 홈]에서 [ASP]를 더블 클릭합니다. 그리고 [제한 속성] 아래 항목 중 파일 다운로드 용량을 뜻하는 [응답 버퍼링 제한]의 값을 4194304(4MB), 파일 업로드 용량을 뜻하는 [최대 요청 엔터티 본문 제한]의 값을 200000 (200000byte)로 설정합니다.

아파치 HTTP 서버

설정 파일(apache2.conf 혹은 httpd.conf)을 열고 LimitRequestBody 속성 값을 5000000(약 5MB)으로 설정합니다. 참고로 LimitRequestBody 속성은 클라이언트 및 아파치 HTTP 서버의 HTTP 요청 전체 크기를 제한하는 속성이며, 값의 범위는 0~2147483647(약 210MB)입니다.

<Directory />
  LimitRequestBody 5000000
</Directory>

기본값은 0이며 제한 없음을 의미합니다.

참고 문서: 아파치 HTTP 서버 공식 문서 – Apache Core Features – LimitRequestBody Directive

톰캣

설정 파일(server.xml)을 열고 maxSwallowSize 속성 값을 5000000(약 5MB)으로 설정합니다. 참고로 maxSwallowSize 속성은 톰캣의 최대 요청 보디 바이트 수(전송 인코딩 오버헤드 제외)입니다.

<Connector port="" protocol="HTTP/1.1" connectionTimeout=""
           redirectPort="" maxSwallowSize="5000000" />

톰캣 7 버전 이상의 기본값은 2097152(2MB)입니다. 또한 0보다 작은 값으로 제한 설정을 하지 않아야 합니다.

참고 링크: 톰캣 9 공식 문서 The HTTP Connector – Common Attributes

NGINX

설정 파일(nginx.conf 혹은 sites-avaliable/default)을 열고 client_max_body_size 값을 50m으로 설정합니다. 참고로 client_max_body_size는 클라이언트 요청 보디의 최대 허용 크기를 설정합니다. 요청의 크기가 구성된 값을 초과하면 413(요청 엔티티가 너무 큼) 오류가 클라이언트에 반환됩니다. 브라우저에서 이 오류를 올바르게 표시할 수 없다는 점에 주의해야 합니다.

server {
    # 중간 생략
    client_max_body_size 50m;

    # 이후 생략
}

값을 0으로 설정하면 클라이언트 요청 보디 크기 확인이 비활성화됩니다.

참고 문서: NGINX 공식 문서 – Module ngx_http_core_module

스프링 부트

application.yml 혹은 application.properties 설정 파일에 최대 파일 용량을 의미하는 max-file-size와 최대 요청 용량을 의미하는 max-request-size 속성을 추가합니다.

application.yml의 설정 예는 다음과 같습니다.

# application.yml
spring:
  servlet:
    multipart:
      max-file-size: 50MB
      max-request-size: 50MB

application.properties 설정 예는 다음과 같습니다.

# application.properties
spring.servlet.multipart.maxFileSize=50MB
spring.servlet.multipart.maxRequestSize=50MB

참고 문서: 스프링 부트 공식 문서 – Uploading Files

Node.js

Express 프레임워크에서 사용하는 body-parser라는 미들웨어를 사용합니다. 그리고 app.js 혹은 index.js 파일에 다음 설정을 추가합니다.

const express = request('express');
const bodyParser = require('body-parser');

// body의 크기 설정
app.use(bodyParser.json({limit: '50mb'}));

// URL의 크기 설정
app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));

참고로 기본값은 100kb입니다.

참고 문서: body-parser README

중요한 것은 꺾이지 않는 마음입니다.

요즘 리그 오브 레전드 월드 챔피언십이 진행 중입니다. 작년에는 데프트 선수가 ‘중요한 것은 꺾이지 않는 마음’이라는 신념으로 모두가 할 수 없을 것이라고 생각했던 월드 챔피언십 우승을 일구어 냈습니다. 그리고 올해는 쵸비 선수가 리그 3연속 우승을 달성하면서 월드 챔피언십 우승에 도전 중입니다. 또한 많은 프로게이머의 우상과도 같은 페이커 선수도 최근 몇 년은 자국 리그 및 월드 챔피언십 우승 문턱에서 수없이 좌절했음에도 계속 도전하고 있습니다. 세 선수의 공통점은 수많은 우승 실패에도 좌절하지 않고 다시 도전해 결국 우승을 거두었고 그 이후에도 계속 도전한다는 점입니다.

[여기보기]에서 소개하는 WAS 보안성 검토도 결국은 꺾이지 않는 마음으로 계속 문제가 되는 보안 요소를 살핀다는 점에서는 같다는 느낌을 받습니다. 여러분도 귀찮다고 혹은 어렵다고 지나가지 말고 이 글을 읽고 WAS의 철벽 보안에 한 걸음 더 다가가는 하루가 되길 바라겠습니다.