V-logue

[Node.js] Helmet을 통해 Node의 보안을 강화해보자 본문

발자취/Node.js

[Node.js] Helmet을 통해 Node의 보안을 강화해보자

보그 2022. 6. 21. 14:47

Helmet은 express사용시 헤더의 설정을 바꿔주면서, 드러나면 해킹에 취약하게 될 부분들을

잡아주는 그런 패키지다.

 

사용법은 무척 간단한데,

일단 Helmet을 설치해주고, 미들웨어를 넣어준다.

참고로, csp, expectCt, hpkp, noCache, referrerPolicy는 따로 설정을 해줘야

사용할 수 있고 app.use만으로는 돌아가지 않는다.

npm install helmet
app.use(helmet());

Helmet을 이용하면 HTTP 헤더를 적절히 설정하여 몇 가지 잘 알려진 웹 취약성으로부터 앱을 보호할 수 있다.

사실 Helmet은 보안 관련 HTTP 헤더를 설정하는 다음과 같은 더 작은 크기의 미들웨어 함수 9개의 모음이다.

 

참고로 helmet 5버전부터는 따로 설정을 해야 외부이미지, 아이프레임이 제대로 표시된다.

app.use(
  helmet({ contentSecurityPolicy: false,
          crossOriginEmbedderPolicy: false,
          crossOriginResourcePolicy: false }),
);

 

 

csp는 Content-Security-Policy 헤더를 설정하여 XSS(Cross-site scripting) 공격 및 기타 교차 사이트 인젝션을 예방합니다. (options)

이제 csp를 사용하면, 웹사이트의 http 응답에 CSP헤더가 추가된다. CSP헤더가 존재할 경우, 브라우저는

CSP 헤더에 언급되지 않은 리소스들을 로드하지 않는다.

Helmet의 기본 csp설정은 '자신'의 웹사이트에 존재하는 리소스들만 허용한다.

한 마디로 다른 url에서 긁어온 모든 리소스를 막아버리기 때문에 따로 csp에 그 리소스를 긁어오는

사이트들을 허용하게 설정해줘야 한다는 것이다.

예를 들면 이렇다.

https://blog.uniony.me/nodejs/helmet/ 유년님의 블로그 발췌

CSP는 XSS(Cross site script) 취약점에 의해서 외부의 스크립트가 주입되어 실행되는 것을 차단하기 위해서

인라인 스크립트(Inline script)를 사용하지 못하게 할 수 있다.

인라인 스크립트가 뭐냐면,

태그 내에 직접 자바스크립트 명령어를 작성하는 방법을 인라인 자바스크립트라고 한다.
이벤트 핸들러 속성을 지정해서 자바스크립트를 실행하도록 하는 고전적인 방식으로

onclick이 인라인 자바스크립트 방식이다. 
허나 HTML 문서와 분리하는 것을 권장하기 때문에 onclick을 사용하는 inline JavaScript 방식은 자주 사용하지 않는다.

<button id="btn" onclick="doSomething()">

대충 이런 식의 코드를 inline Script라고 부르는데,

CSP 헤더에 ‘unsafe-inline’을 추가하면, 인라인된 스크립트의 실행이 허용된다.

그러나 이는 해커가 웹사이트의 inline 스크립트를 주입하여 보안상의 위협을 가할 수 있게 한다.

일반적인 설정없이 인라인 이벤트 핸들러(Inline Event Handler)를 사용하는 것은

CSP(Contents Security Policy)를 위반하는 문제가 있게된다.

(javascript 별도의 파일로 분리해야 CSP에 위배되지 않는다. <script>태크도 인라인 스크립트에 해당한다.)

 

이제 이런 inline Scrip를 없애기 위해서는,

기존에 작성했던 인라인 스크립트를 개별 파일로 옮기고, js 파일 자체를 script 태그의 src 속성으로 추가하면 된다.

onclick 속성과 같이, 태그 내부에서 자바스크립트를 실행하는 속성들은

js 파일에서 addEventListener() 함수로 대체할 수 있다.

<button id="btn" onclick="doSomething()">
// 이랬던 코드를

document.getElementById("btn").addEventListener('click', doSomething);
// 이런식으로 바꿔주면 된다.

그리고 또, nonce라는 속성이 존재한다.

웹페이지를 로드할 때마다 무작위로 생성된 nonce 속성을 인라인 스크립트에 부여하고, 이를 CSP 헤더에 추가한다.

응답(response) 마다 다른 nonce 값이 설정되므로, 제 3자가 인라인 스크립트를 주입하기 어려워진다.

// nonce 생성
app.use((req, res, next) => {
  res.locals.cspNonce = crypto.randomBytes(16).toString("hex");
  next();
});

// helmet 설정 예
app.use(
  helmet.contentSecurityPolicy({
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", (req, res) => `'nonce-${res.locals.cspNonce}'`]
    },
  })
);

HTML에서 script 태그에 nonce 속성 추가

<script nonce="{cspNonce Value}">
  alert('Hi');
</script>

그리고 마지막으로, hash 사용이 있다.

각각의 인라인 스크립트의 hash 값을 CSP에 추가합니다. ‘inline-unsafe’ 속성을 제거한 채로 브라우저에서 웹페이지를 로드할 경우 에러 메시지가 뜨는데, 메시지 내부에 해당 인라인 스크립트의 해시값을 얻을 수 있다.

인라인 스크립트마다 고유한 해시값을 가지는데, CSP의 scriptSrc옵션에 

그 해시값을 추가하면 된다. 만약 여러개가 존재하고 사용하길 바란다면,

전부다 추가해야 한다.

hidePoweredBy는 X-Powered-By 헤더를 제거합니다. (Default)

참고로, helmet을 사용하지 않더라도 사용해야 하는 요소가 존재하는데

적어도 X-Powered-By 헤더는 사용하지 않도록 설정해야 한다. 아래에 설명이 나와 있는데,

 

Helmet의 사용을 원치 않는 경우에는 적어도 X-Powered-By 헤더를 사용하지 마십시오. 공격자는 이 헤더(기본적으로 사용하도록 설정되어 있음)를 이용해 Express를 실행하는 앱을 발견한 후 특정한 대상에 대한 공격을 실행할 수 있습니다.

따라서 우수 사례는 다음과 같이 app.disable() 메소드를 이용해 이 헤더를 끄는 것입니다.

app.disable('x-powered-by')

helmet.js를 사용하는 경우에는 사용자를 대신하여 helmet.js가 위의 작업을 실행합니다.

 

라고 한다. ㅎㅎㅎ;

 

hsts는 서버에 대한 안전한(SSL/TLS를 통한 HTTP) 연결을 적용하는 Strict-Transport-Security 헤더를 설정합니다. (Default)

htst는 프로토콜 다운그레이드 공격(Protocol downgrade attack)과 쿠키 하이재킹(Cookie hijacking)으로부터

보호하기 위해 사용된다.

https를 통해 웹 브라우저에 접근할 수 있는 경우 브라우저에게 

신뢰할 수 없는 http사이트의 사용을 막는 효과를 가져온다.

ieNoOpen은 IE8 이상에 대해 X-Download-Options를 설정합니다. (Default)

inNoOpen은 신뢰할 수 없는 웹 어플리케이션이나 브라우저에서의 이제 불순한 의도를 가지고

시작되는 무슨 일련의 동작이나 행동을 막기위해 신뢰할 수 없는 앱이나 페이지에서의

다운로드를 막기위해 사용된다.

noCache는 Cache-Control 및 Pragma 헤더를 설정하여 클라이언트 측에서 캐싱을 사용하지 않도록 합니다. (options)

noCache는 여러 헤더(CaChe-Control, Surrogate-Control, Pragma, Expries)를 설정해서 

궁극적으로 Client-Side Caching을 비활성화 시키는데 그 의미를 두고 있다.

캐싱(Caching)이란 저장한다는 뜻이다.

컴퓨팅에서 캐싱은 오랜 시간이 걸리는 작업의 결과를 저장해서 시간과 비용을 절감하는 기법을 말한다.

 

noChche는 성능상의 이점이 있지만, 그에 따른 단점도 존재하기 때문에 꼭 필요할때만 사용하도록 하자,

 

noSniff는 X-Content-Type-Options 를 설정하여, 선언된 콘텐츠 유형으로부터 벗어난 응답에 대한 브라우저의 MIME 가로채기를 방지합니다. (Default)

noSniff는 사용하기로 한 Content-Type을 벗어나는 브라우저의 동작을 제어한다.

브라우저는 일반적으로 content나 mime snipping을 통해서 데이터를  추론해서 해석하곤 하는데,

일반적으로 파일을 올바르게 해석하는 데 필요한 정확한 메타데이터 의 부족을 보완하는 데 사용된다.

Content-Type에 사용되는 주요 Mime은 다음과 같다.

text/plain
text/html
image/jpeg
image/png
audio/mpeg
audio/ogg
audio/*
video/mp4
application/octet-stream

 구분은 다음과 같다.

text: 모든 종류의 텍스트를 포함하는 모든 문서
image: 모든 종류의 이미지(gif와 같은 애니매이션 이미지는 포함)
audio: 모든 종류의 오디오 파일
video: 모든 종류의 비디오 파일
application: 모든 종류의 이진 파일

브라우저가 데이터를 추측하고 처리하기 때문에,

해커의 공격에 사용될 수 있는 부분이 있어 Default로 사용되고 있다.

frameguard는 X-Frame-Options 헤더를 설정하여 clickjacking에 대한 보호를 제공합니다. (Default)

서버의 허락없이, frame이나 iframe 태그를 넣는 것을 방지한다. 이게 어떤 문제를 발생시키냐면

clickJacking문제를 발생시킬 수 있다.

 

frame은 기본적으로 브라우저 화면을 여러개로 분할해서 여러 페이지를 한 화면안에 구성할 때 사용하는데,

지금은 일부 사이트를 제외하면 사용이 점차 줄어들고 있고, 사용하지 않도록 권고 하는 기능이다.

iframe은 inline frame으로서 페이지에 frame을 넣을때 사용한다.

iframe은 여전히 사용하고 있는 기능 중 하나인데, 배너나 플러그인 형태로 지원되고 있다.

 

클릭재킹(ClickJacking)은 여러 개의 투명 또는 불투명한 레이어를 사용하여

사용자가 시각적으로 볼 수 없는 다른 페이지의 버튼이나 링크를 클릭하도록 사용자를 속이는 공격이다.

유사한 기술을 사용하여 키 스트로크도 탈취될 수 있다.

스타일시트, iframe 및 텍스트 상자의 세심하게 조작된 조합을 통해 사용자는

사용자가 전자 메일 또는 은행 계정의 암호를 입력하지만 대신 공격자가 제어하는 보이지 않는

프레임에 입력한다고 믿게 할 수 있다.

 

frameguard는 X-Frame-Options header를 설정함으로써,

frame에 사이트를 넣을 수 있는 사람을 제한한다. 

Deny, SameOrigin, Allow-From중에 하나를 선택해서 사용할 수 있다.

xssFilter는 X-XSS-Protection을 설정하여 대부분의 최신 웹 브라우저에서 XSS(Cross-site scripting) 필터를 사용하도록 합니다. (Default)
expectCt는 잘못 발급된 SSL인증서를 완화한다. (options)
hpkp는 Public Key Pinning 헤더 추가. 위조된 인증서를 이용한 중간자 공격을 방지 한다. (options)
referrerPolicy는 Referrer-Policy 헤더를 설정하여 민감한 정보 유출을 예방한다. (options)
dnsPrefetchControl는 DNS Prefetching을 비활성화 합니다. (Default)

dnsPrefetchControl은 일반적으로 브라우저가 성능 향상을 위해 페이지 링크에 대한 DNS 레코드(Record)를

미리 추출(Prefetch)하는데, 사용자가 링크를 클릭하는 순간 IP가 알려져 버리기 때문에

DNS서비스가 과도하게 사용될 수 있다는 점과(트래픽 초과), 보안문제(내가 링크를 클릭하는 순간,

어느 페이지에 있다는 것을 누군가 알아낼 수도 있다.)로 사용된다.

 

보안에 대한 필요성이 상당히 높은 경우,

성능의 저하를 감수하고서라도 사용할 때 dnsPrefetchControl을 사용하게 된다.

 

 

어.. 대충 이런 장점이 있다고 한다. 출처는 여기

 

프로덕션 환경의 Express를 위한 보안 우수 사례

프로덕션 우수 사례: 보안 개요 “프로덕션 (production)” 이라는 용어는 소프트웨어 라이프사이클 중 애플리케이션 또는 API가 최종 사용자 또는 소비자에게 정식으로 제공되는 단계를 말합니다.

expressjs.com

 

그리고 위에서 나온 몇가지 용어를 설명하자면 ,

 

SSL (Secure Socket Layer) 보안 소켓 계층

 : 웹사이트와 브라우저 ( 혹은 두 서버 ) 사이에 전송된 데이터를  암호화하여 인터넷 연결을 유지하는 표준 기술, 이는 해커가 정보 및 금융 정보를 포함한 전송되는 모든 정보를 열람하거나 훔치는 것을 방지한다.

 

TLS: 전송 계층 보안(Transport Layer Security, TLS) 

TLS는 가장 최신 기술로 더 강력한 버전의 SSL 그러나 SSL이 더 일반적으로 사용되는 용어이기에, 여전히 보안 인증서는 SSL이라 불린다. 

 

 XSS (Cross Site Scripting) 공격

 - 사이트에 스크립트를 넣는 기법. 공격에 성공하면 사이트에 접속한 사용자는 그 삽입된 코드를 실행하게 되며 의도치 않은 행동을 하게 된다. ( 이때 예를 들어 쿠키나 세션 토큰 등의 민감한 정보를 탈취 )

 

Strict-Transport-Security

 : 웹 사이트를 접속할 때 강제적으로 https프로토콜로만 접속하게 하는 기능.

 

찾아보니 이렇다고 한다. ㅎㅎㅎ...

 

참조

https://blog.uniony.me/nodejs/helmet/

 

Express 웹사이트 보안 강화하기 [Helmet, CSP]

Express로 만들어진 웹 사이트의 보안을 강화하기 위해 Helmet 미들웨어를 사용합니다.

blog.uniony.me

https://blog.naver.com/cck223/221019399455

 

Node JS 서버 보안 설정

몇 주전, 사드 보복으로 중국쪽에서 한국 회사들 서버 털고 있다는 이야기가 뉴스에 나왔습니다. 또, 랜섬...

blog.naver.com

https://m.blog.naver.com/on21life/221949525422

 

npm - 'HelmetJS' 모듈 이란 무엇인가 *작성중

웹 보안 라이브러리 HelmetJS Helmet 모듈(module) 은 정보보안(Information Security) 을 위해서 서...

blog.naver.com

 

Comments