본문 바로가기

Node.js

Node.js helmet 적용하기

728x90

npm의 helmet 패키지를 사용해 각종 공격에 대비할 수 있다.

helmet 설치

npm install helmet --save

 

아래 페이지에 helmet 패키지에 대한 설명이 있다

https://www.npmjs.com/package/helmet

 

var helmet = require('helmet');

app.use(helmet());

app.use(helmet())을 사용하면 helmet의 아래 기능을 모두 디폴트 값으로 사용하겠다는 의미다.

패키지 설명 페이지를 참고해 보면 app.use(helmet())과 아래 코드가 같은 의미인걸 알수있다.

 

app.use(helmet.contentSecurityPolicy());
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.permittedCrossDomainPolicies());
app.use(helmet.referrerPolicy());
app.use(helmet.xssFilter());

기능별로 따로 적용이 가능하다.

 

기능에 대해서 세세하게는 대충 적어보면

1. CSP : Content-Security-Policy 헤더를 설정해서 XSS나 교차사이트 인젝션등을 방지한다. 다른사이트의 script를 불러오는것도 막기때문에 헬멧 적용전 별도로 설정이 필요하다.

2. dnsPrefetchControl : 도메인이 미리로딩되는 Prefetch에 대해 컨트롤 하기위해 X-DNS-Prefetch-Control 헤더를 설정한다.

3. expectCt : 잘못 발급된 SSL인증서를 완화한다.

4. frameguard : X-Frame-Options를 설정하여 클릭재킹의 공격을 방지한다.

5. HidePowerdBy : 응답 헤더에 있는 X-Powerd-By에 서버 소프트웨어가 표기되는데 이를 숨겨준다. 나는 Express 표기

6. hsts : http보다 https를 선호하도록 지시하는 Strict-Transport-Security 헤더를 설정한다. => 기본 false

7. ieNoOpen : IE8 이상에 대해 X-Download-Options 설정한다.

8. noSniff : X-Content-Type-Options를 설정하여 MIME유형 스니핑을 방지한다.

9. permittedCrossDomainPolicies : 일부 클라이언트간에 도메인 간 콘텐츠 로드에 대해 도메인 정책을 알려주는 헤더 X-Permitted-Cross-Domain-Policies를 설정한다

10. xssFilter : X-XSS-Protection헤더를 설정하여 xss공격이 있는 스크립트를 비활성화 시킨다.

referrerPolicy는 헤더에 있는 referrer과 관련이 있는 설정같다.

 

자세한 설명은 위에 helmet 패키지 설명 사이트에 나와있고, 참조 문서와 기본값들에 대한 정보가 나와있다.

 

나는 javascript를 이용한 카카오 로그인, 카카오 맵에 대해 csp 설정만 따로 했다.

 

const cspOptions = {
	directives: {
		...helmet.contentSecurityPolicy.getDefaultDirectives(),
		"default-src" : ["'self'", "*.kakao.com", "*.daumcdn.net", "*.kakaocdn.net"],
		"script-src" : ["'self'", "*.kakao.com", "*.daumcdn.net", "*.kakaocdn.net" , "'unsafe-inline'", "'unsafe-eval'"],
		"img-src" : ["'self'", "data:", "*.daumcdn.net", "*.kakaocdn.net"],
	}
}

app.use(helmet({
	contentSecurityPolicy: cspOptions,
}));

 

참고로 안했을때 개발자 도구 콘솔 에러를 확인해보면

이런식으로 나온다

 

 

**** 2021-09-03 추가 ****

helmet 추가한 후 로컬에서는 이슈가 없었지만

서버에 배포했을때 budle.js에 https로 자동으로 붙어서 렌더링이 되지않는 이슈가 발생했다.

helmet 패키지 npm 사이트를 참고해보면 base-uri가 보였는데 기본값 self로 되어있고,

mdn 문서를 참고해보니, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/base-uri

 

CSP: base-uri - HTTP | MDN

The HTTP Content-Security-Policy base-uri directive restricts the URLs which can be used in a document's element. If this value is absent, then any URI is allowed. If this directive is absent, the user agent will use the value in the element.

developer.mozilla.org

 

schema-source부분을 보면 http: 나 https: 로 지정을 할 수 있고,

위반사례, violation case 부분을 확인해보면

base-uri가 self로 되어있을때 base href가 도메인의 형태가 아니라면 자동으로 https://도메인 값이 set된다고 나와있다.

로컬과 개발에 같이 적용되기 위해 base태그의 href에 "/"만적어서 발생한 이슈같았다. 때문에 csp 세팅을 추가로 했다.

 

const cspOptions = {
	directives: {
		...helmet.contentSecurityPolicy.getDefaultDirectives(),
		"default-src" : ["'self'", "*.kakao.com", "*.daumcdn.net", "*.kakaocdn.net"],
		"script-src" : ["'self'", "*.kakao.com", "*.daumcdn.net", "*.kakaocdn.net" , "'unsafe-inline'", "'unsafe-eval'"],
		"img-src" : ["'self'", "data:", "*.daumcdn.net", "*.kakaocdn.net"],
		"base-uri" : ["/", "http:"],
	}
}

base-uri를 추가했다.

잘 된다.

728x90