iamkanguk.dev

[NestJS] 자네 혹시 helmet이 뭔지 알고 쓰나? 본문

Framework/NestJS

[NestJS] 자네 혹시 helmet이 뭔지 알고 쓰나?

iamkanguk 2023. 11. 29. 16:03

최근에 프로젝트를 하는 도중에 보일러 플레이트를 조금씩 만져보고 있는데.. 내가 놓치고 있던 부분이 있었다.

그냥 아무생각 없이 app.use(helmet()) 을 사용하고 있던 것이다.

 

정확히 helmet이 무엇이고 어떤 기능을 하는지를 놓치고 있는 것 같아서 이렇게 정리해보려고 한다.

참고로 Nest에서 helmet을 적용하는 것은 진짜 일도 아니다. 위처럼 app.use로 적용해주면 끝이다.

 

 

이 포스팅은 [Project] 프로젝트 삽잘기30 (feat helmet 구성) 글을 주로 참고했습니다! 좋은 글이니 한번씩 들어가셔서 읽어보시면 좋을 것 같습니다.
 

[Project] 프로젝트 삽질기30 (feat helmet 구성)

들어가며 NestJS로 개발하면서, 외부로부터 오는 해커들의 공격에 어떻게 대응할 수 있을지 고민하곤 했습니다. 그때 helmet이라는 라이브러리를 알 수 있었습니다. NestJS에서 helmet을 보다 잘 활용

overcome-the-limits.tistory.com

 

Helmet 이란?

Helmet은 웹서버를 외부의 공격으로부터 보호해주는 대표적인 Node 보안 모듈이다. Helmet 모듈은 다양한 HTTP Header를 자동으로 설정해줘서 서버 애플리케이션의 보안을 강화해준다.

// helmet install
npm install helmet

 

참고로 helmet은 express의 미들웨어 모듈이고 여러 미들웨어 모듈을 합쳐놓은 미들웨어 패키지 모듈이다. 다시 말해서, express 기반 애플리케이션에서 HTTP Response Header를 설정하는 여러 개의 작은 미들웨어 함수 유형 모음이라고 생각하면 된다.

 

// main.ts
import helmet from 'helmet'

...
app.use(helmet());
 
// 다양한 옵션들을 적용할 때 사용할 수 있는 기능들
app.use(helmet.contentSecurityPolicy());
app.use(helmet.crossOriginEmbedderPolicy());
app.use(helmet.crossOriginOpenerPolicy());
app.use(helmet.crossOriginResourcePolicy());
app.use(helmet.dnsPrefetchControl());
app.use(helmet.expectCt());
app.use(helmet.frameguard());
app.use(helmet.hidePoweredBy());
app.use(helmet.hsts());
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());
app.use(helmet.originAgentCluster());
app.use(helmet.permittedCrossDomainPolicies());
app.use(helmet.referrerPolicy());
app.use(helmet.xssFilter());

 

Helmet의 기본설정과 추가설정

기본 설정

(1) dnsPrefetchControl

도메인이 미리 로딩되는 Prefetch에 대해 컨트롤하기 위해 X-DNS-Prefetch-Control 헤더를 설정한다. 대부분의 브라우저에서는 성능을 향상시키기 위해 페이지의 링크에 대한 DNS Record를 미리 추출한다. 그렇게 되면 사용자가 링크를 클릭할 때 대상에 대한 IP가 이미 알려져 있다는 것이다.

 

이로 인해서 DNS Service가 과도하게 사용될 수 있고, 개인정보 보호문제 등이 야기될 수 있다. 따라서 보안 요구가 높은 경우에는 성능 저하를 감수하면서 DNS Prefetch를 비활성화 시킬 수 있다.

 

(2) frameguard

X-Frame-Options 헤더를 설정해서 Click-jacking 공격을 방지한다. Click-jacking은 사용자가 자신이 클릭하고 있다고 인지하는 것과 다른 것을 클릭하도록 하여 속이는 해킹 기법이다. 속이기 위해서 보이지 않는 레이어에 보이지 않는 버튼을 만드는 방법이 있다.

 

(3) hidePoweredBy

응답 헤더에 있는 X-Powered-By에 서버 소프트웨어가 표기되는데 이를 숨겨준다. 이 정보는 악의적으로 활용될 가능성이 높기 때문에 helmet을 통해서 제거해 주는 것이 좋다.

 

참고로 필자는 main.ts 부분에 app.disable('x-powered-by') 라고 프로젝트 시작 전에 선언해주는 편이었다. 하지만 helmet 라이브러리를 적용하면서 이 부분은 제거해도 괜찮을 것 같다.

 

helmet을 적용하지 않았을 때의 Response Header

 

실제로 Postman을 가지고 테스트 해봤을 때 helmet 라이브러리를 사용하지 않은경우 X-Powered-By가 노출되는 것을 확인할 수 있었다. 이제 helmet 라이브러리를 적용해보고 스샷을 찍어보겠다.

 

helmet을 적용하고 난 후의 Response Header

 

Helmet 라이브러리를 적용하니까 이전과 다르게 뭔가 여러개가 빡빡 나오는 것을 볼 수 있다. 하지만 확실한건 x-powered-by 노출을 막아준다는 것을 확인할 수 있다.

 

(4) hsts

Strict-Transport-Security 헤더를 설정해준다. 이 헤더는 서버에 대한 안전한 연결을 적용시켜주는 헤더이다. 안전한 연결이라 함은 SSL 또는 TLS를 통한 HTTP 연결을 말한다. 그래서 브라우저에게 HTTPS 만을 통해 특정 사이트에 Access 할 수 있도록 요청한다.

 

브라우저는 Default로 보통 HTTP로 먼저 접속을 시도하게 되는데 이 때 HTTPS를 지원하는 사이트였다면 301/302 Redirect로 HTTP 응답을 해서 HTTPS롤 적용해서 사이트에 접근시켜줍니다.

 

하지만 해커가 중간에 Proxy 서버를 세팅함으로써 본인과 해커 사이에서는 HTTP 통신을 하고, 해커와 웹사이트와는 HTTPS 통신을 하게 된다면 사용자의 개인정보가 HTTP 통신을 통해 해커에게 전달되는 현상이 야기될 수 있습니다.

 

위의 시나리오를 SSL Stripping 이라고 하며, 이런 공격을 방지하기 위해 HSTS를 설정한다고 합니다.

 

(5) ieNoOpen

X-Download-Options 헤더를 설정해서 IE8 (Internet Explorer) 이상에서만 사용할 수 있도록 설정한다.

 

(6) noSniff

X-Content-Type-Options 헤더를 설정해서 선언된 콘텐츠 유형으로부터 벗어난 응답에 대한 브라우저의 MIME Sniffing을 방지한다. MIME은 Multipurpose Internet Mail Extensions의 약자로 클라이언트에게 전송된 문서의 다양성을 알려주기 위한 포맷이다. 참고로 브라우저는 리소르를 내려받을 때 MIME 타입을 보고 동작하기 때문에 정확한 설정이 중요하다.

 

MIME Sniffing은 브라우저가 특정 파일을 읽을 때 파일의 실제 내용과 Content-Type에 설정된 내용이 다르면 파일로부터 형식을 추측하여 실행하는 것인데 공격자에게 악용이 될 가능성이 있다고 한다.

 

(7) xssFilter

X-XSS-Protection 헤더를 0으로 설정하면서 XSS 공격 스크립트를 비활성화해서 예방할 수 있다.

 

추가설정

(1) contentSecurityPolicy (CSP)

콘텐츠 보안 정책 설정 및 구성을 통해 의도하지 않은 내용이 페이지에 삽입되는 것을 방지해준다. 이 헤더를 설정해주면서 XSS나 Cross-site injection을 방지해준다. 참고로, 다른 사이트의 script를 불러오는 것도 막기 때문에 helmet 적용 전 별도로 설정이 필요하다.

 

(2) crossOriginEmbedderPolicy (COEP)

Cross-Origin-Embedder-Policy 헤더를 require-corp로 설정한다. COEP는 교차 출처 삽입 정책이라고도 부르며, 원본 간 리소스를 문서에 포함하도록 해주는 헤더이다. require-corp 옵션 또한 다른 옵션들에 대해서는 링크를 확인해보면 더욱 자세하게 알 수 있다.

 

(3) crossOriginOpenerPolicy (COOP)

Cross-Origin-Opener-Policy 헤더를 설정한다. COOP는 top-level 문서가 cross-origin 상태의 문서와 browsing context group을 공유하지 못하도록 제한해주는 헤더이다.

 

(4) crossOriginResourcePolicy (CORP)

Cross-Origin-Resource-Policy 헤더를 설정한다. CORP는 교차 출처 리소스 정책이라고도 부르며, 브라우저가 지정된 리소스에 대한 출처 또는 사이트 간 요청을 차단하지 않는다는 요청을 하는 헤더이다.

 

(5) exprectCt

Expect-CT 헤더를 설정해서 SSL 인증서 오발급을 예방해준다.

 

(6) originAgentCluster

Origin-Agent-Cluster 헤더를 설정해서 Origin 간 문서를 별도 Agent Cluster로 분리한다.

 

(7) permittedCrossDomainPolicies

X-Permitted-Cross-Domain-Policies 헤더를 설정해서 Cross-Domain-Content-Policy를 설정한다. 이 헤더는 일부 클라이언트에 도메인 간 콘텐츠 로드에 대한 도메인 정책을 처리한다.

 

(8) referrerPolicy

참조 referrer 헤더를 숨겨준다.

 

후기

이렇게 helmet에 대해서 조금 자세하게 알아봤다. 모든 옵션들을 필히 알아야 하는 건 아니지만, 그래도 어떤 기능들이 있구나, 이래서 helmet 라이브러리를 적용하는구나 알고 써야한다고 생각되어서 한번 정리해봤다.

 

좋은 글을 제공해주신 분들에게 너무 감사합니다. 덕분에 잘 참고했습니다!


참고 자료

- https://overcome-the-limits.tistory.com/743

 

[Project] 프로젝트 삽질기30 (feat helmet 구성)

들어가며 NestJS로 개발하면서, 외부로부터 오는 해커들의 공격에 어떻게 대응할 수 있을지 고민하곤 했습니다. 그때 helmet이라는 라이브러리를 알 수 있었습니다. NestJS에서 helmet을 보다 잘 활용

overcome-the-limits.tistory.com

- https://docs.nestjs.com/security/helmet

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

- https://4rgos.tistory.com/1

 

XSS(Cross Site Scripting) 공격이란?

XSS 란? 웹 해킹 공격 중 XSS라는 공격 기법이 있다. Cross Site Scripting의 약자로 CSS라고 하는 것이 맞지만 이미 CSS가 Cascading Style Sheets의 약어로 사용되고 있어 XSS라 한다. XSS는 게시판이나 웹 메일 등

4rgos.tistory.com

- https://inpa.tistory.com/767

 

[NODE / 보안] 📚 helmet 모듈 사용법 - 웹 보안은 내가 👮

helmet 모듈 helmet 모듈은 서버에서 다양한 HTTP 헤더를 자동 설정을 통해 서버 어플리케이션의 보안을 강화해주는 대표적인 노드 보안 모듈이다. 헬멧을 써서 내 머리를 보호하듯이, 내 웹서버를

inpa.tistory.com