mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-27 02:44:28 +08:00
Merge pull request #1114 from backend-joonyoung/korean-translation-kojoonyoung
(5.7 ~ 5.13, 6.14~6.19) Korean-translation-kojoonyoung
This commit is contained in:
@ -629,7 +629,11 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 단지 서버 진단을 목적으로 일부 정보를 추출하기 위하여 상용서버에 코드를 배포하는 "진단용 배포"를 자주 수행하고 있게 될 것이다
|
**그렇게 하지 않을 경우:** 단지 서버 진단을 목적으로 일부 정보를 추출하기 위하여 상용서버에 코드를 배포하는 "진단용 배포"를 자주 수행하고 있게 될 것이다
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
🔗 [**자세히 보기: ‘유지 엔드포인트’를 생성하라**](/sections/production/createmaintenanceendpoint.korean.md)
|
🔗 [**자세히 보기: ‘유지 엔드포인트’를 생성하라**](/sections/production/createmaintenanceendpoint.korean.md)
|
||||||
|
=======
|
||||||
|
🔗 [**자세히 보기: Create a ‘maintenance endpoint’**](/sections/production/createmaintenanceendpoint.korean.md)
|
||||||
|
>>>>>>> eac1089d (Update README.korean.md link address)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -639,7 +643,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** API 성능 및 가동 중지 시간을 측정하는 데 많은 노력을 기울임에도 실전에서 가장 느린 코드 부분이 어느것인지, 그리고 이것이 UX에 미치는 영향을 알지 못할 것이다
|
**그렇게 하지 않을 경우:** API 성능 및 가동 중지 시간을 측정하는 데 많은 노력을 기울임에도 실전에서 가장 느린 코드 부분이 어느것인지, 그리고 이것이 UX에 미치는 영향을 알지 못할 것이다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Discover errors and downtime using APM products**](/sections/production/apmproducts.md)
|
🔗 [**자세히 보기: Discover errors and downtime using APM products**](/sections/production/apmproducts.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -649,7 +653,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 세계 최고의 IT/DevOps 전문가도 형편없이 쓰여진 코드로 이루어진 시스템은 구하지 못한다
|
**그렇게 하지 않을 경우:** 세계 최고의 IT/DevOps 전문가도 형편없이 쓰여진 코드로 이루어진 시스템은 구하지 못한다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Make your code production-ready**](/sections/production/productioncode.md)
|
🔗 [**자세히 보기: Make your code production-ready**](/sections/production/productioncode.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -659,7 +663,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** [월마트](https://www.joyent.com/blog/walmart-node-js-memory-leak)에서 일어났던 것처럼 메모리가 하루에 수백 메가바이트씩 누수 될 수 있다
|
**그렇게 하지 않을 경우:** [월마트](https://www.joyent.com/blog/walmart-node-js-memory-leak)에서 일어났던 것처럼 메모리가 하루에 수백 메가바이트씩 누수 될 수 있다
|
||||||
|
|
||||||
🔗 [**자세히 보기: 메모리 사용량 측정 및 보호**](/sections/production/measurememory.md)
|
🔗 [**자세히 보기: 메모리 사용량 측정 및 보호**](/sections/production/measurememory.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -669,7 +673,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 단일 노드 스레드는 수백 개의 html/이미지/angular/react 파일을 스트리밍 하느라 바빠서 정작 천직인 동적 컨텐츠를 전달하는 작업에는 신경쓸 겨를이 없을것이다.
|
**그렇게 하지 않을 경우:** 단일 노드 스레드는 수백 개의 html/이미지/angular/react 파일을 스트리밍 하느라 바빠서 정작 천직인 동적 컨텐츠를 전달하는 작업에는 신경쓸 겨를이 없을것이다.
|
||||||
|
|
||||||
🔗 [**자세히 보기: Get your frontend assets out of Node**](/sections/production/frontendout.md)
|
🔗 [**자세히 보기: Get your frontend assets out of Node**](/sections/production/frontendout.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -679,7 +683,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 해당서버에 오류가 발생하면 해당 서버만 제거하면 되는 것이 아니라 어플리케이션의 다운타임이 발생하게된다. 게다가 특정 서버에 의존하기 때문에 수평적 확장이 힘들어질 것이다
|
**그렇게 하지 않을 경우:** 해당서버에 오류가 발생하면 해당 서버만 제거하면 되는 것이 아니라 어플리케이션의 다운타임이 발생하게된다. 게다가 특정 서버에 의존하기 때문에 수평적 확장이 힘들어질 것이다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Be stateless, kill your Servers almost every day**](/sections/production/bestateless.md)
|
🔗 [**자세히 보기: Be stateless, kill your Servers almost every day**](/sections/production/bestateless.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -689,7 +693,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 전용 도구없이 취약점으로부터 코드를 깨끗하게 유지하려면 새로운 취약점에 대한 데이터를 지속적으로 확인해야 할것이다
|
**그렇게 하지 않을 경우:** 전용 도구없이 취약점으로부터 코드를 깨끗하게 유지하려면 새로운 취약점에 대한 데이터를 지속적으로 확인해야 할것이다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Use tools that automatically detect vulnerabilities**](/sections/production/detectvulnerabilities.md)
|
🔗 [**자세히 보기: Use tools that automatically detect vulnerabilities**](/sections/production/detectvulnerabilities.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -922,7 +926,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 애플리케이션이 커다란 요청을 처리해야하면 다른 중요한 일을 완수할 수 없게 되어 성능이 영향을 받고 DOS 공격에 취약하게 된다
|
**그렇게 하지 않을 경우:** 애플리케이션이 커다란 요청을 처리해야하면 다른 중요한 일을 완수할 수 없게 되어 성능이 영향을 받고 DOS 공격에 취약하게 된다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Limit payload size**](/sections/security/requestpayloadsizelimit.md)
|
🔗 [**자세히 보기: Limit payload size**](/sections/security/requestpayloadsizelimit.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -934,7 +938,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 악의적인 자바스크립트 코드가 `eval`같이 실시간으로 평가하는 자바스크립트 언어 함수에 넘어가면 페이지 안의 자바스크립트 승인을 완전히 장악하게 된다. 이 취약점은 XSS 공격 형태로 자주 나타난다.
|
**그렇게 하지 않을 경우:** 악의적인 자바스크립트 코드가 `eval`같이 실시간으로 평가하는 자바스크립트 언어 함수에 넘어가면 페이지 안의 자바스크립트 승인을 완전히 장악하게 된다. 이 취약점은 XSS 공격 형태로 자주 나타난다.
|
||||||
|
|
||||||
🔗 [**자세히 보기: Avoid JavaScript eval statements**](/sections/security/avoideval.md)
|
🔗 [**자세히 보기: Avoid JavaScript eval statements**](/sections/security/avoideval.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -946,7 +950,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 저조하게 쓰여진 정규표현들은 이벤트 루프를 완전히 정체시킬 수 있는 정규표현 DOS 공격에 취약해진다. 예를들면, 자주 쓰이는 `moment` 패키지 또한 2017년 11월에 악성 정규표현 사용에 취약하다는 것이 발견되었다
|
**그렇게 하지 않을 경우:** 저조하게 쓰여진 정규표현들은 이벤트 루프를 완전히 정체시킬 수 있는 정규표현 DOS 공격에 취약해진다. 예를들면, 자주 쓰이는 `moment` 패키지 또한 2017년 11월에 악성 정규표현 사용에 취약하다는 것이 발견되었다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Prevent malicious RegEx**](/sections/security/regex.md)
|
🔗 [**자세히 보기: Prevent malicious RegEx**](/sections/security/regex.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -958,7 +962,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 악의적인 사용자 입력이 이전에 파일시스템에 업로드되었거나 이미 시스템에 존재하는 흑화된 파일을 require 하는데 쓰이는 매개변수로 들어가게 될 수 있다.
|
**그렇게 하지 않을 경우:** 악의적인 사용자 입력이 이전에 파일시스템에 업로드되었거나 이미 시스템에 존재하는 흑화된 파일을 require 하는데 쓰이는 매개변수로 들어가게 될 수 있다.
|
||||||
|
|
||||||
🔗 [**자세히 보기: Safe module loading**](/sections/security/safemoduleloading.md)
|
🔗 [**자세히 보기: Safe module loading**](/sections/security/safemoduleloading.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -970,7 +974,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 플러그인이 무한 루프나, 메모리 과부화나, 민감한 프로세스 환경 변수로의 접근과 같이 무한히 가지각색으로 공격할 수 있다
|
**그렇게 하지 않을 경우:** 플러그인이 무한 루프나, 메모리 과부화나, 민감한 프로세스 환경 변수로의 접근과 같이 무한히 가지각색으로 공격할 수 있다
|
||||||
|
|
||||||
🔗 [**자세히 보기: Run unsafe code in a sandbox**](/sections/security/sandbox.md)
|
🔗 [**자세히 보기: Run unsafe code in a sandbox**](/sections/security/sandbox.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -982,7 +986,7 @@ null == undefined; // true
|
|||||||
|
|
||||||
**그렇게 하지 않을 경우:** 순진무구하게 자식 프로세스를 썼다가는 악의적인 사용자 입력이 무결처리 되지 않은 시스템 명령어로 인한 원격 커맨드 실행이나 쉘 주입 공격을 초래할 수 있다.
|
**그렇게 하지 않을 경우:** 순진무구하게 자식 프로세스를 썼다가는 악의적인 사용자 입력이 무결처리 되지 않은 시스템 명령어로 인한 원격 커맨드 실행이나 쉘 주입 공격을 초래할 수 있다.
|
||||||
|
|
||||||
🔗 [**자세히 보기: Be cautious when working with child processes**](/sections/security/childprocesses.md)
|
🔗 [**자세히 보기: Be cautious when working with child processes**](/sections/security/childprocesses.korean.md)
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
@ -1195,6 +1199,33 @@ CMD [ "node", "dist/app.js" ]
|
|||||||
|
|
||||||
<br/><br/><br/>
|
<br/><br/><br/>
|
||||||
|
|
||||||
|
## ![✔] 8.5. 배포하기 전 종속성을 정리해라
|
||||||
|
|
||||||
|
**핵심요약:** 빌드 및 생산주기동안 개발의존성이 필요할 때도 있지만, 결국 배포할 때에는 개발의존성은 없어져야 하고 이미지는 최소화 되어야 한다. 그렇게 되면 필요한 코드만 배포가 되고, 잠재적인 공격을 줄일 수 있다. 여러 단계의 빌드를 사용할 때 모든 종속성을 먼저 설치하고 마지막에 `npm ci --production`를 실행하여 원하는 바를 달성할 수 있다.
|
||||||
|
**그렇게 하지 않을 경우:** 악명 높은 npm보안 침해중 다수가 발견된 패키지를 배포할 수 있다. ([eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes)와 같은)
|
||||||
|
|
||||||
|
🔗 [**자세히 보기: Remove development dependencies**](./sections/docker/install-for-production.korean.md)
|
||||||
|
|
||||||
|
<br /><br /><br />
|
||||||
|
|
||||||
|
## ![✔] 8.6. 현명하고 우아하게 종료해라
|
||||||
|
|
||||||
|
**핵심요약:** 프로세스 SIGTERM 이벤트를 처리하고 모든 기존의 연결 및 리소스를 정리해라. 이 작업은 진행중이 요청에 대해 응답하는 동안 수행해야 한다. 도커의 런파임에서는 컨테이너를 종료하는 것은 드문일이 아니라 자주 발생하는 작업이다. 이를 달성하기 위해 로드벨런서, 연결 유지 및 연결, HTTP서버 및 기타 리소스와 같은 몇가지 움직이는 부분을 원활하게 작업하기 위해서는 이를 고려한 코드가 필요하다.
|
||||||
|
**그렇게 하지 않을 경우:** 여러가지 고려하지 않고 바로 컨테이너를 종료하는것은 수천 사용자의 실망을 의미한다.
|
||||||
|
|
||||||
|
🔗 [**자세히 보기: Graceful shutdown**](./sections/docker/graceful-shutdown.korean.md)
|
||||||
|
|
||||||
|
<br /><br /><br />
|
||||||
|
|
||||||
|
## ![✔] 8.7. 도커와 V8엔진을 모두 사용하여 메모리를 제한해라
|
||||||
|
|
||||||
|
**핵심요약:** 항상 도커 및 JS 런타임 플래그를 사용하여 메모리를 제한해라. 컨테이너 배치를 신중하게 하기위해 Docker 제한이 필요하며, V8엔진의 max-old-space 플래그는 정시에 GC를 시작하고 메모리 사용량 부족을 방지하는 데 필요하다. V8엔진의 메모리를 실제 컨테이너의 제한보다 약간 작게 설정해라.
|
||||||
|
**그렇게 하지 않을 경우:** 도커의 메모리 제한은 확장을 결정하고, 다른 컨테이너를 굶주리게 하는것을 방지하기 위해 필요하다. V8엔진의 메모리를 제한하지 않으면 컨테이너 리소스를 충분히 활용하지 않는다. 명시적으로 정하지 않으면 리소스의 50~60%를 사용할 때 충돌이 발생한다.
|
||||||
|
|
||||||
|
🔗 [**자세히 보기: Set memory limits using Docker only**](./sections/docker/memory-limit.korean.md)
|
||||||
|
|
||||||
|
<br /><br /><br />
|
||||||
|
|
||||||
# 마일스톤
|
# 마일스톤
|
||||||
|
|
||||||
이 가이드를 관리하고 최신 버전을 유지하기 위해, 우리는 지속해서 가이드라인과 모범 사례들을 커뮤니티의 도움으로 업데이트하고 개선해 나가고 있습니다. [마일스톤](https://github.com/i0natan/nodebestpractices/milestones)을 확인하시고 이 프로젝트에 기여하고 싶다면 작업중인 그룹에 참여하세요!
|
이 가이드를 관리하고 최신 버전을 유지하기 위해, 우리는 지속해서 가이드라인과 모범 사례들을 커뮤니티의 도움으로 업데이트하고 개선해 나가고 있습니다. [마일스톤](https://github.com/i0natan/nodebestpractices/milestones)을 확인하시고 이 프로젝트에 기여하고 싶다면 작업중인 그룹에 참여하세요!
|
||||||
|
|||||||
BIN
assets/images/Kubernetes-graceful-shutdown-flowchart.png
Normal file
BIN
assets/images/Kubernetes-graceful-shutdown-flowchart.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
83
sections/docker/graceful-shutdown.korean.md
Normal file
83
sections/docker/graceful-shutdown.korean.md
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# 우아하게 종료해라
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
쿠버네티스와 같은 도커화된 런타임에서 컨테이너는 자주 생성되고 삭제된다. 삭제와 재생성은 오류가 발생했을 때뿐만 아니라 컨테이너 재배치, 새 버전으로 업그레이드와 같은 합당한 이유로 발생한다. 30초의 유예 기간이 있는 프로세스에 알림(SIGTERM 신호)을 보내면 된다. 이로 인해 개발자는 앱이 진행 중인 요청을 적시에 처리하고 리소스를 정리해야 한다. 그렇게 하지 않으면 수천 명의 사용자가 응답을 받지 못할 것이다. 구현하는 측면에서, 종료 코드는 진행 중인 모든 요청이 응답하고 리소스를 정리할때까지 기다려야 한다.
|
||||||
|
말은 쉽지만 실제로 여러가지를 조율해야 한다: 헬스 체크를 통해서 앱이 더 많은 요청을 처리할 준비가 되지 않았다고 LoadBalancer에게 알린다, 기존 요청이 완료될 때까지 기다린다, 새로운 요청의 처리를 피한다, 리소스를 정리하고 최종적으로 종료하기 전에 중요정보를 기록한다.
|
||||||
|
계속 유지되는 연결을 사용 중인 경우, 클라이언트는 새로운 연결이 설정되어야 함을 알려야 한다. [Stoppable](https://github.com/hunterloftis/stoppable)과 같은 라이브러리는 이를 수행하는데 크게 도움이 될 수 있다.
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
|
||||||
|
### 예시 코드 – Node.js를 루트 프로세스로 배치하면 코드에 신호를 전달할 수 있다. ([node를 사용한 bootstrap](./bootstrap-using-node.md)를 참고해라)
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><strong>Dockerfile</strong></summary>
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:12-slim
|
||||||
|
|
||||||
|
# 여기에 빌드 로직을 작성해라
|
||||||
|
|
||||||
|
CMD ["node", "index.js"]
|
||||||
|
#이것은 Node.js를 루트 프로세스(PID1)로 만든다.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시 코드 – Tiny 프로세스 관리자를 사용하여 노드에 신호 전달
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><strong>Dockerfile</strong></summary>
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:12-slim
|
||||||
|
|
||||||
|
# 여기에 빌드 로직을 작성해라
|
||||||
|
|
||||||
|
ENV TINI_VERSION v0.19.0
|
||||||
|
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
|
||||||
|
RUN chmod +x /tini
|
||||||
|
ENTRYPOINT ["/tini", "--"]
|
||||||
|
|
||||||
|
CMD ["node", "index.js"]
|
||||||
|
#노드는 PID1 역할을 하는 TINI의 하위 프로세스를 실행한다.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 안티 패턴 예시 코드 – npm 스크립트를 사용한 프로세스 초기화
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><strong>Dockerfile</strong></summary>
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:12-slim
|
||||||
|
|
||||||
|
# 여기에 빌드 로직을 작성해라
|
||||||
|
|
||||||
|
CMD ["npm", "start"]
|
||||||
|
#노드는 npm의 하위 프로세스를 실행하고 신호를 수신하지 않는다.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시 - 종료 단계
|
||||||
|
|
||||||
|
[Rising Stack](https://blog.risingstack.com/graceful-shutdown-node-js-kubernetes/)의 블로그 인용
|
||||||
|
|
||||||
|

|
||||||
91
sections/docker/install-for-production.korean.md
Normal file
91
sections/docker/install-for-production.korean.md
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
# 배포시 의존성을 제거해라
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
개발 종속성은 잠재적인 보안 취약점과 컨테이너의 크기를 크게 증가시킨다.
|
||||||
|
예를들어, 가장 영향도 있는 npm 보안 침해 중 일부는 [eslint-scope](https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes) 또는 [event-stream that was used by nodemon](https://snyk.io/blog/a-post-mortem-of-the-malicious-event-stream-backdoor/)과 같은 영향을 받는 패키지 개발의존성에서 시작했다. 이러한 이유로 인해 최종적으로 배포되는 이미지는 안전하고 최소화 되어야 한다. `--production`플래그와 함께 `npm install`을 하는것이 가장 좋다. 그러나, 새로운 설치와 잠금 파일의 존재를 보장하는 `npm ci`를 실행하는 것이 훨씬 더 안전하다. 로컬 캐시를 제거하면 수십MB를 추가로 절약할 수 있다. 종종 개발의존성을 사용하여 컨테이너 내에서 테스트를 하거나 디버깅을 해야 할 필요가 있는데 [multi stage builds](./multi_stage_builds.md)가 서로 다른 종속성 세트와 배포용 종속성 세트를 갖는데 도움이 될 수 있다.
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시 코드 – 배포를 위한 설치
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><strong>Dockerfile</strong></summary>
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:12-slim AS build
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --production && npm cache clean --force
|
||||||
|
|
||||||
|
# 나머지 코드는 여기서 부터 작성하면 된다
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시 코드 – 여러 단계로 이루어진 빌드의 배포를 위한 설치
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><strong>Dockerfile</strong></summary>
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:14.8.0-alpine AS build
|
||||||
|
|
||||||
|
COPY --chown=node:node package.json package-lock.json ./
|
||||||
|
# ✅ 안전한 설치
|
||||||
|
RUN npm ci
|
||||||
|
COPY --chown=node:node src ./src
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
|
||||||
|
# 런타임 단계
|
||||||
|
FROM node:14.8.0-alpine
|
||||||
|
|
||||||
|
COPY --chown=node:node --from=build package.json package-lock.json ./
|
||||||
|
COPY --chown=node:node --from=build node_modules ./node_modules
|
||||||
|
COPY --chown=node:node --from=build dist ./dist
|
||||||
|
|
||||||
|
# ✅ 깔끔한 개발 패키지
|
||||||
|
RUN npm prune --production
|
||||||
|
|
||||||
|
CMD [ "node", "dist/app.js" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 안티 패턴 예시 코드 – 모든 의존성을 하나의 dockerfile로 설치
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary><strong>Dockerfile</strong></summary>
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:12-slim AS build
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
# 두 가지 실수: 개발 의존성 설치, npm 설치 후 캐시 미삭제
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# 나머지 코드는 여기서 부터 작성하면 된다
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 블로그 인용: "npm ci 는 일반적인 설치보다 엄격하다"
|
||||||
|
|
||||||
|
[npm 공식 문서](https://docs.npmjs.com/cli/ci.html)로 부터
|
||||||
|
|
||||||
|
> This command is similar to npm-install,
|
||||||
|
테스트 플랫폼 또는 CI/CD와 같은 자동화된 환경에서 사용하는 것 또는 종속성을 새로 설치하고 있는지 확인하려는 상황을 제외하고. 이 명령어는 npm-install과 유사하다. 특정 사용자가 지향하는 기능을 건너뛰면 일반 npm 설치보다 훨씬 빠를 수 있다. 또한 일반적인 설치보다 더욱 엄격하므로 대부분의 npm 사용자가 로컬 환경에서 하는 설치로 인한 오류나 불일치를 포착하는데 도움이 된다.
|
||||||
71
sections/docker/memory-limit.korean.md
Normal file
71
sections/docker/memory-limit.korean.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# 도커와 V8엔진을 사용하여 메모리를 제한해라
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
메모리 제한은 프로세스/컨테이너에 허용된 최대 메모리 사용량을 알려준다. 이를 초과하는 요청이나 사용이 발생하면 프로세스를 종료한다. 이는 하나의 프로세스/컨테이너만 독식하지 않고 다른 구성요소가 자원을 할당받지 못해 죽지 않도록 하는 방법이다. 또한 메모리 제한을 통해 런타임은 컨테이너를 올바른 인스턴스에 배치할 수 있다. 사용가능한 메모리가 300MB인 인스턴스에 500MB를 소비하는 컨테이너를 배치하면 오류가 발생한다. 두가지 옵션을 통해 이러한 제한을 구현할 수 있다: V8엔진의 --max-old-space-size 플래그와 도커 런타임은 둘다 절대적으로 필요하다. 올바른 헬스 결정을 내리는데 훨씬 넓은 관점을 갖기 위해 도커 런타임 제한을 항상 고려하는 것은 보장한다. 이러한 제한이 주어지면 런타임은 더 많은 리소스를 확장하고 생성할 수 있다.
|
||||||
|
또한 충돌 시기에 신중한 결정을 내릴 수 있다. 컨테이너에 짧은 메모리 요청이 있고 호스팅 인스턴스가 이를 지원할 수 있는 경우 도커 컨테이너를 활성 상태로 유지한다.
|
||||||
|
마지막으로 Ops 전문가는 도커를 사용하여 메모르 스왑과 같이 고려할 수 있는 다양한 프로덕션 메모리 구성을 설정할 수 있다. 호스트 환경에서 이것만으로는 충분하지 않다. V8엔진의 --max-old-space-size플래그를 설정해주지 않으면 JS 런타임은 한계에 가까워질 때 GC를 동작하지 않으며 50~60%의 자원만을 사용해도 충돌이 발생한다. 따라서 V8엔진의 메모리 제한을 도커 메모리 제한의 75~100%로 설정해라.
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시 코드 – 도커를 사용한 메모리 제한
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Bash</strong></summary>
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --memory 512m my-node-app
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시 코드 – 쿠버네티스와 V8엔진을 사용한 메모리 제한
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Kubernetes deployment yaml</strong></summary>
|
||||||
|
|
||||||
|
```yml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: my-node-app
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: my-node-app
|
||||||
|
image: my-node-app
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "400Mi"
|
||||||
|
limits:
|
||||||
|
memory: "500Mi"
|
||||||
|
command: ["node index.js --max-old-space-size=350"]
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 쿠버네티스 공식문서: "당신이 구체적인 메모리 제한을 정하지 않는다면"
|
||||||
|
|
||||||
|
[쿠버네티스 공식문서](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/)로 부터
|
||||||
|
|
||||||
|
> 컨테이너에는 사용하는 메모리의 상한이 없다. 컨테이너는 실행 중인 노드에서 사용 가능한 모든 메모리를 사용할 수 있으며, 이는 차례로 OOM 킬러를 호출할 수 있다. 또한 리소스 제한이 없는 컨테이너가 OOM 킬러에 의해 죽을 확률이 높다.
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 도커 공식문서: "OOME를 발생시키고 종료하기 시작한다."
|
||||||
|
|
||||||
|
[도커 공식문서](https://docs.docker.com/config/containers/resource_constraints/)로 부터
|
||||||
|
|
||||||
|
> 실행중인 컨테이너가 호스트 시스템의 메모리를 너무 많이 사용하지 않도록 하는 것이 중요하다. 리눅스 호스트에서 커널이 중요한 시스템 기능을 수행하기에 메모리의 부족을 감지하면 OOME 또는 메모리 부족 예외가 발생하고 메모리를 확보하기 위해 프로세스를 종료한다.
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### Node.js 공식문서: "V8엔진은 GC에 더 많은 시간을 사용할 것이다."
|
||||||
|
|
||||||
|
[Node.js 공식문서](https://nodejs.org/api/cli.html#cli_max_old_space_size_size_in_megabytes)로 부터
|
||||||
|
|
||||||
|
> V8엔진의 오래된 메모리 섹션의 최대 크기를 설정해라. 메모리 사용량이 한계에 가까워지면 V8엔진은 사용하지 않는 메모리를 해제하기 위해 GC에 더 많은 시간을 사용한다. 2GB의 메모리가 있는 시스템에서 다른 용도를 위해 일부 메모리를 남겨두고 1.5GB로 메모리 사용량을 제한하는 것이 좋다.
|
||||||
@ -1,25 +1,25 @@
|
|||||||
# Sure user experience with APM products
|
# 확실한 사용자 관점의 APM 제품
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### One Paragraph Explainer
|
### 한문단 설명
|
||||||
|
|
||||||
APM (application performance monitoring) refers to a family of products that aims to monitor application performance from end to end, also from the customer perspective. While traditional monitoring solutions focus on Exceptions and standalone technical metrics (e.g. error tracking, slow server endpoints, etc), in the real world our app might create disappointed users without any code exceptions, for example, if some middleware service performed real slow. APM products measure the user experience from end to end, for example, given a system that encompasses frontend UI and multiple distributed services – some APM products can tell how fast a transaction that spans multiple tiers last. It can tell whether the user experience is solid and point to the problem. This attractive offering comes with a relatively high price tag hence it’s recommended for large-scale and complex products that require going beyond straightforward monitoring.
|
APM (어플리케이션 성능 모니터링)은 고객의 관점에서도 애플리케이션 성능을 처음부터 끝까지 모니터링 하는 제품군을 나타낸다. 기존의 모니터링 솔루션은 예외 및 독립형 기술 지표에 중점을 두었다 (예를들어 에러 트래킹, 서버 엔트포인트의 속도 저하 등) 현실에서 코드의 문제는 없으나, 사용자의 실망을 초래할 수 있는데, 예를 들면 미들웨어 서비스가 느리게 수행되는 경우이다. APM은 사용자의 관점에서 처음부터 끝까지 측정한다. 예를들어, 프론트엔드 UI와 여러 분산 서비스를 포괄하는 시스템을 제공하는 경우 일부 APM 제품은 여러 계층에 걸친 트랜잭션이 각각 얼마나 빠르게 이루어 지는지 알 수 있다. 그것은 사용자의 관점에서 견고한지, 문제가 있는지 알 수 있다. 이 매력적인 제품은 상대적으로 고가에 제공된다. 따라서 단순한 모니터링을 넘어 대규모 및 복잡한 어플레케이션에 권장된다.
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### APM example – a commercial product that visualizes cross-service app performance
|
### APM 예시 – 서비스간 앱 성능을 시각화 하는 제품
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### APM example – a commercial product that emphasizes the user experience score
|
### APM 예시 – 사용자의 관점에서 지표를 강조하는 제품
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### APM example – a commercial product that highlights slow code paths
|
### APM 예시 – 느린 코드의 경로를 강조하는 제품
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@ -1,42 +1,47 @@
|
|||||||
# Be stateless, kill your Servers almost every day
|
# 무상태(stateless)로 운영하고, 거의 매일 서버를 재부팅하라
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### One Paragraph Explainer
|
### 한문단 요약
|
||||||
|
|
||||||
Have you ever encountered a severe production issue where one server was missing some piece of configuration or data? That is probably due to some unnecessary dependency on some local asset that is not part of the deployment. Many successful products treat servers like a phoenix bird – it dies and is reborn periodically without any damage. In other words, a server is just a piece of hardware that executes your code for some time and is replaced after that.
|
서버에서 일부 데이터가 누락되어 서버의 심각한 문제가 발생한 적이 있는가? 이것은 배포가 아니라 일부 로컬 자산에 대해 불필요한 종속성 때문에 발생했을 수 있다.
|
||||||
This approach
|
많은 성공적인 제품은 서버를 불사조처럼 취급한다. 이것은 손상없이 주기적으로 죽고 다시 태어난다.
|
||||||
|
즉, 서버는 일정 시간 동안 코드를 실행하고, 교체되는 하드웨어의 일부분과 같다. 이러한 접근은
|
||||||
- allows scaling by adding and removing servers dynamically without any side-effects.
|
- 부작용 없이 동적으로 서버를 추가 및 제거하여 확장할 수 있다.
|
||||||
- simplifies the maintenance as it frees our mind from evaluating each server state.
|
- 각 서버의 상태를 확인하지 않아도 되므로 유지 관리가 간단해진다.
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### Code example: anti-patterns
|
### 예시 코드: anti-patterns
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// Typical mistake 1: saving uploaded files locally on a server
|
// 실수 1 : 업로드 된 파일 서버에 로컬로 저장
|
||||||
var multer = require('multer'); // express middleware for handling multipart uploads
|
var multer = require('multer'); // 멀티파트 업로드 처리를 위한 express 미들웨어
|
||||||
var upload = multer({ dest: 'uploads/' });
|
var upload = multer({ dest: 'uploads/' });
|
||||||
|
|
||||||
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {});
|
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {});
|
||||||
|
|
||||||
// Typical mistake 2: storing authentication sessions (passport) in a local file or memory
|
// 실수 2: 로컬 파일 또는 메모리에 인증 정보 저장
|
||||||
var FileStore = require('session-file-store')(session);
|
var FileStore = require('session-file-store')(session);
|
||||||
app.use(session({
|
app.use(session({
|
||||||
store: new FileStore(options),
|
store: new FileStore(options),
|
||||||
secret: 'keyboard cat'
|
secret: 'keyboard cat'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Typical mistake 3: storing information on the global object
|
// 실수 3: 전역 객체에 정보 저장
|
||||||
Global.someCacheLike.result = { somedata };
|
Global.someCacheLike.result = { somedata };
|
||||||
```
|
```
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### What Other Bloggers Say
|
### 블로그 인용
|
||||||
|
|
||||||
From the blog [Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html):
|
|
||||||
> ...One day I had this fantasy of starting a certification service for operations. The certification assessment would consist of a colleague and I turning up at the corporate data center and setting about critical production servers with a baseball bat, a chainsaw, and a water pistol. The assessment would be based on how long it would take for the operations team to get all the applications up and running again. This may be a daft fantasy, but there’s a nugget of wisdom here. While you should forego the baseball bats, it is a good idea to virtually burn down your servers at regular intervals. A server should be like a phoenix, regularly rising from the ashes...
|
|
||||||
|
|
||||||
|
[Martin Fowler](https://martinfowler.com/bliki/PhoenixServer.html)의 블로그:
|
||||||
|
> ...나는 운영을 위한 인증 서비스를 시작하는 상상을 했다.
|
||||||
|
인증 평가는 동료로 구성되며 나는 기업의 데이터 센터에 나타나 야구방망이, 전기톱, 물총을 들고 중요한 서버에 대한 설정을 한다.
|
||||||
|
평가는 운영팀이 모든 애플리케이션을 다시 가동하고 살행하는데 걸리는 시간을 기반으로 한다
|
||||||
|
This may be a daft fantasy, but there’s a nugget of wisdom here.
|
||||||
|
이것은 어리석은 상상일 수 있지만 여기에서 작은 지혜를 옅볼 수 있다.
|
||||||
|
야구방망이는 포기해야 하지만 정기적으로 서버를 사실상 소진시키는 것이 좋다.
|
||||||
|
서버는 불사조와 같아야 하며, 정기적으로 잿더미에서 일어나야 한다...
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
```javascript
|
```javascript
|
||||||
const heapdump = require('heapdump');
|
const heapdump = require('heapdump');
|
||||||
|
|
||||||
// 요청이 인가된 것인지 확인하기
|
// 인가된 사용자 확인/
|
||||||
function isAuthorized(req) {
|
function isAuthorized(req) {
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
@ -37,10 +37,10 @@ router.get('/ops/heapdump', (req, res, next) => {
|
|||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### 추천 자료들
|
### 권장 리소스
|
||||||
|
|
||||||
[Getting your Node.js app production ready (Slides)](http://naugtur.pl/pres3/node2prod)
|
[Node.js 앱 프로덕션 준비하기 (슬라이드)](http://naugtur.pl/pres3/node2prod)
|
||||||
|
|
||||||
▶ [Getting your Node.js app production ready (Video)](https://www.youtube.com/watch?v=lUsNne-_VIk)
|
▶ [Node.js 앱 프로덕션 준비하기 (비디오)](https://www.youtube.com/watch?v=lUsNne-_VIk)
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
@ -1,20 +1,24 @@
|
|||||||
# Use tools that automatically detect vulnerable dependencies
|
# 취약점을 자동으로 탐지하는 도구를 사용해라
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### One Paragraph Explainer
|
### 한문단 요약
|
||||||
|
|
||||||
Modern Node applications have tens and sometimes hundreds of dependencies. If any of the dependencies
|
최신의 노드 애플리케이션에는 수십 때로는 수백 개의 종속성이 있다.
|
||||||
you use has a known security vulnerability your app is vulnerable as well.
|
종속성이 있는 경우 당신의 애플리케이션에는 알려진 보안 취약점이 존재한다.
|
||||||
The following tools automatically check for known security vulnerabilities in your dependencies:
|
|
||||||
|
|
||||||
- [npm audit](https://docs.npmjs.com/cli/audit) - npm audit
|
다음은 종속성을 사용함에 있어 알려진 보안 취약성을 자동으로 확인하는 도구이다:
|
||||||
- [snyk](https://snyk.io/) - Continuously find & fix vulnerabilities in your dependencies
|
- [npm audit](https://docs.npmjs.com/cli/audit) - npm 검사
|
||||||
|
- [snyk](https://snyk.io/) - 종속 항목의 취약점을 지속적으로 파악하고 수정
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### What Other Bloggers Say
|
### 블로그 인용
|
||||||
|
|
||||||
From the [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/) blog:
|
[StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-one-security/)의 블로그:
|
||||||
|
|
||||||
> ...Using to manage your application’s dependencies is powerful and convenient. But the packages that you use may contain critical security vulnerabilities that could also affect your application. The security of your app is only as strong as the “weakest link” in your dependencies. Fortunately, there are two helpful tools you can use to ensure the third-party packages you use: nsp and requireSafe. These two tools do largely the same thing, so using both might be overkill, but “better safe than sorry” are words to live by when it comes to security...
|
> ...애플리케이션의 종속성을 관리하는데 취약성 검사 도구를 사용하는 것은 강력하고 편리하다.
|
||||||
|
그러나 사용하는 패키지에 당신의 어플리케이션에 영향을 줄 수 있는 심각한 보안 취약점이 포함되어 있을 수 있다.
|
||||||
|
앱의 의존성 중 "가장 약한 연결고리"가 당신 앱의 보안 수준이다.
|
||||||
|
다행스럽게도 당신이 사용할 수 있는 보장하는 써드파티 패키지가 두개 존재한다. 당신은 nsp 또는 requireSafe를 사용할 수 있다.
|
||||||
|
이 두 가지 도구는 거의 같은 일을 수행한다. 따라서 두 개 모두 사용하는 것은 과할 수 있다. 그러나 보안에 있어서 "안전한 것이 퍼포먼스가 좋지 않은 것보다 낫다" 라는 문장은 생활해야 할 문장이다.
|
||||||
@ -1,32 +1,37 @@
|
|||||||
# Get your frontend assets out of Node
|
# Node에서 프론트 엔드 자산을 빼라
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### One Paragraph Explainer
|
### 한문단 요약
|
||||||
|
|
||||||
In a classic web app the backend serves the frontend/graphics to the browser, a very common approach in the Node’s world is to use Express static middleware for streamlining static files to the client. BUT – Node is not a typical webapp as it utilizes a single thread that is not optimized to serve many files at once. Instead, consider using a reverse proxy (e.g. nginx, HAProxy), cloud storage or CDN (e.g. AWS S3, Azure Blob Storage, etc) that utilizes many optimizations for this task and gain much better throughput. For example, specialized middleware like nginx embodies direct hooks between the file system and the network card and uses a multi-threaded approach to minimize intervention among multiple requests.
|
클래식 웹에서는 백엔드가 브라우저에 프론트엔드/그래픽을 제공했다. Node에서 일반적인 방식은 정적 파일을 클라이언트에게 전달하기 위해 Express 정적 미들웨어를 사용하는 것이다.
|
||||||
|
그러나 단일 스레드를 사용하는 Node는 일반적인 웹 앱이 아니기에 한번에 많은 파일을 제공하기에 최적화되지 않았다.
|
||||||
|
대신 작업에 대해 많은 최적화와, 훨씬 많은 처리량을 제공하는 리버스 프록시(예를 들어 nginx, HAProxy), 클라우드 저장소, CDN(예를 들어, AWS S3, Azure Blob Storage 등)의 사용을 고려해야 한다.
|
||||||
|
예를 들어 nginx와 같은 특수 미들웨어는 파일 시스템과 네트웨크 카드 간의 직접 연결을 구현하고 다중 스레드 접근 방식을 사용하여, 다수의 요청 간의 개입을 최소화 한다.
|
||||||
|
|
||||||
Your optimal solution might wear one of the following forms:
|
최적의 솔루션:
|
||||||
|
|
||||||
1. Using a reverse proxy – your static files will be located right next to your Node application, only requests to the static files folder will be served by a proxy that sits in front of your Node app such as nginx. Using this approach, your Node app is responsible deploying the static files but not to serve them. Your frontend’s colleague will love this approach as it prevents cross-origin-requests from the frontend.
|
1. 리버스 프록시 사용 - 정적 파일은 Node 애플리케이션의 바로 옆에 위치하며, 정적 파일 폴더에 대한 요청만 nginx와 같은 Node 애플리케이션 앞에 있는 프록시에서 제공한다.
|
||||||
|
이 방식을 사용하면, Node는 정적 파일을 배포하는 책임은 있으나 직접 제공하지는 않는다. 이 방법은 CORS를 예방하기에 이러한 방식을 선호 할 것이기 때문에 프론트엔드 동료는 이 접근 방식을 선호할 것이다.
|
||||||
|
|
||||||
2. Cloud storage – your static files will NOT be part of your Node app content, they will be uploaded to services like AWS S3, Azure BlobStorage, or other similar services that were born for this mission. Using this approach, your Node app is not responsible deploying the static files neither to serve them, hence a complete decoupling is drawn between Node and the Frontend which is anyway handled by different teams.
|
2. 클라우드 저장소 - 정적 파일은 Node 애플리케이션의 컨텐츠가 아니고, AWS S3, Azure BlobStorage와 비슷한 저장소에 저장이 될 것이다.
|
||||||
|
이 방식을 사용하면, Node는 정적 파일을 배포 하거나 제공할 책임이 없다. 따라서 노드와 프론트엔드 간에 완전한 분리가 이루어지며, 이는 다른 팀에서 처리한다.
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### Configuration example: typical nginx configuration for serving static files
|
### 예제 논의: 정적 파일을 제공하지 위한 일반적인 nginx 구성
|
||||||
|
|
||||||
```nginx
|
```nginx
|
||||||
# configure gzip compression
|
# gzip 압축 구성
|
||||||
gzip on;
|
gzip on;
|
||||||
keepalive 64;
|
keepalive 64;
|
||||||
|
|
||||||
# defining web server
|
# 웹서버 정의
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
|
|
||||||
# handle static content
|
# 정적 컨텐츠 관리
|
||||||
location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
|
location ~ ^/(images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
|
||||||
root /usr/local/silly_face_society/node/public;
|
root /usr/local/silly_face_society/node/public;
|
||||||
access_log off;
|
access_log off;
|
||||||
@ -36,10 +41,13 @@ expires max;
|
|||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### What Other Bloggers Say
|
### 블로그 인용
|
||||||
|
|
||||||
From the blog [StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/):
|
[StrongLoop](https://strongloop.com/strongblog/best-practices-for-express-in-production-part-two-performance-and-reliability/)의 블로그:
|
||||||
|
|
||||||
>…In development, you can use [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile) to serve static files. But don’t do this in production, because this function has to read from the file system for every file request, so it will encounter significant latency and affect the overall performance of the app. Note that res.sendFile() is not implemented with the sendfile system call, which would make it far more efficient. Instead, use serve-static middleware (or something equivalent), that is optimized for serving files for Express apps. An even better option is to use a reverse proxy to serve static files; see Use a reverse proxy for more information…
|
|
||||||
|
|
||||||
|
>…개발중 당신은 정적 파일을 제공하기 위해 [res.sendFile()](http://expressjs.com/4x/api.html#res.sendFile)를 사용할 수 있다.
|
||||||
|
그러나 이 함수는 모든 파일 요청에 대해 파일 시스템에서 읽어야 하기 때문에 상당한 대기 시간이 발생하고 애플리케이션 전체 성능에 영향을 미치기 때문에 상용되는 서버에는 사용하면 안된다.
|
||||||
|
res.sendFile()은 파일 전송 시스템으로 구현되어 있지 않기 때문에 효율과는 거리가 멀어진다.
|
||||||
|
대신, Express 애플리케이션에서 파일 제공에 최적화 되어있는 serve-static 미들웨어(또는, 비슷한 환경)를 사용해라.
|
||||||
|
더 나은 방법은 정적 파일 제공을 위해 리버스 프록시를 사용하는 것이다. 자세한 내용은 리버스 프록시 사용에 대한 정보를 참조해라…
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|||||||
@ -1,25 +1,28 @@
|
|||||||
# Measure and guard the memory usage
|
# 메모리 사용량을 측정하고 보호해라
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### One Paragraph Explainer
|
### 한문단 요약
|
||||||
|
|
||||||
In a perfect world, a web developer shouldn’t deal with memory leaks. In reality, memory issues are a known Node’s gotcha one must be aware of. Above all, memory usage must be monitored constantly. In the development and small production sites, you may gauge manually using Linux commands or npm tools and libraries like node-inspector and memwatch. The main drawback of this manual activities is that they require a human being actively monitoring – for serious production sites, it’s absolutely vital to use robust monitoring tools e.g. (AWS CloudWatch, DataDog or any similar proactive system) that alerts when a leak happens. There are also few development guidelines to prevent leaks: avoid storing data on the global level, use streams for data with dynamic size, limit variables scope using let and const.
|
완벽한 세상에서는 개발자가 메모리 릭과 씨름할 일이 없다.
|
||||||
|
실제 세상에서 메모리 이슈는 노드의 알려진 문제로 개발자가 잘 인지하고 있어야한다.
|
||||||
|
무엇보다 메모리의 사용량을 지속적으로 모니터해야 한다.
|
||||||
|
|
||||||
|
개발 및 작은 제품에서 당신은 리눅스 명령어 또는 node-inspector 및 memwatch와 같은 npm 라이브러리를 통해 수동으로 측정할 수 있다.
|
||||||
|
수동 작업의 주요한 단점은 사람이 적극적으로 모니터링 해야 한다는 것이다. 중요한 제품에서 메모리의 누수를 알려주는 강력한 모니터링 도구(AWS CloudWatch, DataDog 또는 이와 유사한 선제적 시스템)를 사용하는 것은 절대적으로 중요하다.
|
||||||
|
메모리의 누수를 방지하기 위한 몇가지 지침은 다음과 같다. 전역에서 데이터를 저장하지 말 것, 동적 데이터의 스트림을 사용할 것, let, const를 사용하여 변수 범위를 제한할 것.
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### What Other Bloggers Say
|
### 블로그 인용
|
||||||
|
|
||||||
* From the blog [Dyntrace](http://apmblog.dynatrace.com/):
|
* [Dyntrace](https://www.dynatrace.com/news/blog/understanding-garbage-collection-and-hunting-memory-leaks-in-node-js/)의 블로그:
|
||||||
> ... ”As we already learned, in Node.js JavaScript is compiled to native code by V8. The resulting native data structures don’t have much to do with their original representation and are solely managed by V8. This means that we cannot actively allocate or deallocate memory in JavaScript. V8 uses a well-known mechanism called garbage collection to address this problem.”
|
> ... ”이미 우리가 배웠듯이 Node.js에서 JavaScript코드는 V8엔진에 의해 네이티브 코드로 실행된다. 그 결과 네이티브 데이터 구조는 원래의 구조와 크게 관련이 없으며 V8에서 단독으로 관리한다. 이것은 우리가 JavsScript에서 메모리를 능동적으로 할당하거나 해제 할 수 없음을 의미한다. V8엔진은 이 문제를 해결하기 위해 가비지 컬렉터라는 유명한 메커니즘을 사용한다.”
|
||||||
|
|
||||||
* From the blog [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):
|
|
||||||
> ... “Although this example leads to obvious results the process is always the same:
|
|
||||||
Create heap dumps with some time and a fair amount of memory allocation in between
|
|
||||||
Compare a few dumps to find out what’s growing”
|
|
||||||
|
|
||||||
* From the blog [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load):
|
* [Dyntrace](http://blog.argteam.com/coding/hardening-node-js-for-production-part-2-using-nginx-to-avoid-node-js-load)의 블로그:
|
||||||
> ... “fault, Node.js will try to use about 1.5GBs of memory, which has to be capped when running on systems with less memory. This is the expected behavior as garbage collection is a very costly operation.
|
> ... “약간의 시간과 상당한 양의 메모리 할당으로 힙덤프를 생성하여, 이러한 덤프들을 비교해보면 프로세스는 항상 동일하다는 명백한 결과로 이어진다.”
|
||||||
The solution for it was adding an extra parameter to the Node.js process:
|
|
||||||
node –max_old_space_size=400 server.js –production ”
|
|
||||||
“Why is garbage collection expensive? The V8 JavaScript engine employs a stop-the-world garbage collector mechanism. In practice, it means that the program stops execution while garbage collection is in progress.”
|
* [Rising Stack](https://blog.risingstack.com/finding-a-memory-leak-in-node-js/)의 블로그:
|
||||||
|
> ... “메모리가 적은 시스템에서 Node.js가 1,5GBs의 메모리를 사용햐려고 하는 것은 제한되어야 하지만, 제한되지 않는다. 이것은 가바지 컬렉터의 고비용 작업에 의한 것으로 추측된다. 이에 대한 해결책은 "node –max_old_space_size=400 server.js –production" 명령을 이용해 Node.js 프로세스에 추가 변수를 할당하는 것이다. 가비지 컬렉터는 왜 고비용 작업인가? V8 JavaScript 엔진은 stop-the-world 가바지 컬렉터를 사용한다. 이것은 실제로 가비지 컬렉션이 진행되는 동안 프로그램이 실행을 중단한다는 의미이다.”
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
# Make your code production-ready
|
# 상용에 사용될 수 있게 코드를 작성하라
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
### One Paragraph Explainer
|
### 한문단 설명
|
||||||
|
|
||||||
Following is a list of development tips that greatly affect the production maintenance and stability:
|
생산 유지 및 안정성에 큰 영향을 미치는 개발 팀 목록을 따라하라:
|
||||||
|
|
||||||
* The twelve-factor guide – Get familiar with the [Twelve factors](https://12factor.net/) guide
|
* 12가지 가이드 요소 - [12가지 요소](https://12factor.net/) 가이드와 친해지기
|
||||||
* Be stateless – Save no data locally on a specific web server (see separate bullet – ‘Be Stateless’)
|
* 상태 갖고있지 않기 – 특정 웹 서버에 로컬로 데이터를 저장하지 말라 (‘Be Stateless’ 참조)
|
||||||
* Cache – Utilize cache heavily, yet never fail because of cache mismatch
|
* 캐시 - 캐시를 많이 활용하지만, 캐시의 불일치로 절대 실패를 만들지 말라
|
||||||
* Test memory – gauge memory usage and leaks as part your development flow, tools such as ‘memwatch’ can greatly facilitate this task
|
* 메모리 측정 - 메모리 사용량과 누수를 개발의 일부분으로 측정하면 ‘memwatch’과 같은 도구가 큰 도움이 될 수 있다.
|
||||||
* Name functions – Minimize the usage of anonymous functions (i.e. inline callback) as a typical memory profiler will provide memory usage per method name
|
* 이름이 있는 함수 - 일반적으로 메모리 프로파일러가 함수 이름당 메모리 사용량을 제공하므로 익명 함수(즉, 인라인 콜백함수)의 사용을 최소화 해라
|
||||||
* Use CI tools – Use CI tool to detect failures before sending to production. For example, use ESLint to detect reference errors and undefined variables. Use –trace-sync-io to identify code that uses synchronous APIs (instead of the async version)
|
CI 도구를 사용해라 - 상용으로 사용하기 전에 오류를 감지하기 위하여 CI 도구를 사용해라. 예를들어, ESLint를 사용하여 에러와 정의되지 않은 변수를 찾는다. 비동기 버전을 사용하는 대신 동기 API를 사용하는 코드를 찾을 수 있는 --trace-sync-io를 사용해라.
|
||||||
* Log wisely – Include in each log statement contextual information, hopefully in JSON format so log aggregators tools such as Elastic can search upon those properties (see separate bullet – ‘Increase visibility using smart logs’). Also, include transaction-id that identifies each request and allows to correlate lines that describe the same transaction (see separate bullet – ‘Include Transaction-ID’)
|
* 현명하게 기록해라 – 상태정보를 각 로그에 포함하는 대신에 Elastic과 같은 로그 수집 도구를 사용하여 해당 속성을 찾을 수 있도록 JSON 형식으로 제공되기를 원한다. ('Increase visibility using smart logs' 참조) 또한 각 요청을 식별하고 동일한 트랜잭션을 설명하는 행의 상관관계를 허용하는 transaction-id를 포함해라. (‘Include Transaction-ID’ 참조)
|
||||||
* Error management – Error handling is the Achilles’ heel of Node.js production sites – many Node processes are crashing because of minor errors while others hang on alive in a faulty state instead of crashing. Setting your error handling strategy is absolutely critical, read here my [error handling best practices](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)
|
* 오류 관리 – 오류 처리는 Node.js로 제공되는 사이트의 아킬레스건이다. 많은 노드 프로세스가 작은 오류로 인해 출돌하는 반면 다른 프로세스들은 충돌하는 대신 오류가 있는 상태로 살아있다. 오류 처리 전략을 설정하는것은 절대적으로 즁요하다. [오류 처리의 좋은 예](http://goldbergyoni.com/checklist-best-practices-of-node-js-error-handling/)를 참고해라.
|
||||||
23
sections/security/avoideval.korean.md
Normal file
23
sections/security/avoideval.korean.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# 자바스크립트 eval statement를 피하라
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
`eval()`, `setTimeout()`, `setInterval()`, 그리고 `new Function()` 는 Node.js 에서 자주 사용되는 전역 함수이며 JS표현식, 명령문, 명령문 시퀀스를 나타내는 문자열을 변수로 허용한다.
|
||||||
|
이러한 함수를 사용하는데 있어 보안상의 문제점은 사용자의 코드가 기본적으로 공격자가 할 수 있는 모든 작업을 실행할 수 있기 떄문에 신뢰할 수 없는 사용자의 입력이 코드에 침투하여 서버의 손상으로 이어질 가능성이 있다는 것이다.
|
||||||
|
사용자의 입력이 함수에 전달되고 실행될 수 있는 함수를 사용하지 않도록 리팩토링 하는것이 좋다.
|
||||||
|
|
||||||
|
### 코드 예시
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 공격자가 입력할 수 있는 악성코드 예시
|
||||||
|
const userInput = "require('child_process').spawn('rm', ['-rf', '/'])";
|
||||||
|
|
||||||
|
// 악성코드 실행
|
||||||
|
eval(userInput);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 블로그 인용
|
||||||
|
|
||||||
|
[Liran Tal](https://leanpub.com/nodejssecurity)의 필수 Node.js 보안 책으로 부터:
|
||||||
|
> eval함수는 JS에서 보안의 관점에서 가장 거슬리는 부분이다. eval 함수는 JS문자열을 텍스트로 분석하고 JS코드인 것처럼 실행한다.
|
||||||
|
신뢰할 수 없는 사용자와 eval함수의 사용의 혼합은 결국 서버 손상으로 끝날 수 있다.
|
||||||
30
sections/security/childprocesses.korean.md
Normal file
30
sections/security/childprocesses.korean.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# 자식 프로세스를 다룰 땐 특히 조심해라
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
아무리 자식 프로세스가 성능이 좋더라도 주의해서 사용해야 한다. 사용자의 입력은 필터링이 되어있지 않다면 자식 프로세스의 사용을 금해야 한다.
|
||||||
|
시스템 수준의 로직을 실행하는 필터링 되지 않은 입력의 위험성은 무한하다. 이러한 위험성에는 원격 코드 실행, 민감한 시스템 데이터 노출 및 데이터 손실까지 있다. 이를 예방하기 위한 체크리스트는 다음과 같다.
|
||||||
|
|
||||||
|
- 모든 경우에 사용자의 입력을 피하고, 그렇지 않다면 유효성을 검사하고 삭제해라
|
||||||
|
- 사용자/그룹 ID를 사용하여 상위 및 하위 프로세스의 사용을 제한해라
|
||||||
|
- 다른 준비가 실패할 경우 원치 않는 부작용을 방지하기 위해 격리된 환경 내에서 프로세스를 실행해라
|
||||||
|
|
||||||
|
### 예시 코드: 필터링 되지 않은 자식 프로세스 실행의 위험성
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
// 두개의 인자를 갖는 스크립트를 사용하고 그중 하나는 필터링 되지 않은 사용자의 입력이다.
|
||||||
|
exec('"/path/to/test file/someScript.sh" --someOption ' + input);
|
||||||
|
|
||||||
|
// -> 사용자가 단순히 '&& rm -rf --no-preserve-root /' 이렇게 입력하면 어떤 일이 일어날 수 있는지 생각해봐라
|
||||||
|
// 당신은 원치않는것을 경험할 것이다.
|
||||||
|
```
|
||||||
|
|
||||||
|
### 추가 내용
|
||||||
|
|
||||||
|
Node.js 자식 프로세스 [문서](https://nodejs.org/dist/latest-v8.x/docs/api/child_process.html#child_process_child_process_exec_command_options_callback)로 부터:
|
||||||
|
|
||||||
|
> 이 함수에 필터링 되지 않은 사용자의 입력을 전달하지 마라. 쉘 메타 문자를 포함하는 모든 입력은 임의의 명령 실행을 시작하는데 사용할 수 있다.
|
||||||
37
sections/security/regex.korean.md
Normal file
37
sections/security/regex.korean.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# 악성 정규표현(RegEx)이 단일 스레드 실행을 과부하시키는것을 막아라
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
정규식을 사용하는데 있어 내제된 위험은 텍스트를 분석하고 주어진 정규식 패턴과 일치하는지 확인하는데 필요한 계산 리소스이다.
|
||||||
|
단일 스레드 이벤트 루프가 지배적인 Node.js 플랫폼의 경우 정규식 패턴을 확인하는 것과 같은 CPU를 사용하는 작업은 애플리케이션이 응답하지 않을 수 있게 한다.
|
||||||
|
|
||||||
|
|
||||||
|
가능하면 정규식 사용을 피하거나 정규식 패턴이 안전한지 확인하는 작업을 [validator.js](https://github.com/chriso/validator.js), 또는 [safe-regex](https://github.com/substack/safe-regex)와 같은 전용 라이브러리로 미뤄라.
|
||||||
|
|
||||||
|
|
||||||
|
[OWASP 예시](https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS)에 있는 취약한 정규식 패턴 몇가지:
|
||||||
|
* (a|aa)+
|
||||||
|
* ([a-zA-Z]+)*
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 예시코드 – Express 프레임워크를 사용하여 SSL/TLS 활성화하기
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const saferegex = require('safe-regex');
|
||||||
|
const emailRegex = /^([a-zA-Z0-9])(([\-.]|[_]+)?([a-zA-Z0-9]+))*(@){1}[a-z0-9]+[.]{1}(([a-z]{2,3})|([a-z]{2,3}[.]{1}[a-z]{2,3}))$/;
|
||||||
|
|
||||||
|
// email정규식은 redos 공격에 취약하기 때문에 false를 출력해야 한다.
|
||||||
|
console.log(saferegex(emailRegex));
|
||||||
|
|
||||||
|
// 정규식 패턴 대신 유효성 검사기를 사용해라
|
||||||
|
const validator = require('validator');
|
||||||
|
console.log(validator.isEmail('liran.tal@gmail.com'));
|
||||||
|
```
|
||||||
|
|
||||||
|
<br/><br/>
|
||||||
|
|
||||||
|
### 책 인용: "취약한 정규식은 반복을 적용하는 것으로 알려져 있다."
|
||||||
|
|
||||||
|
Liran Tal의 [필수 Node.js 보안](https://leanpub.com/nodejssecurity)에서 발췌
|
||||||
|
> 프로그래머는 종종 정규식을 사용하여 사용자의 입력이 조건에 부합하는지 확인하는 작업을 한다. 취약한 정규식은 반복의 연속과 일치하는 접미사 패턴과 +의 조합으로 알려져 있다.
|
||||||
59
sections/security/requestpayloadsizelimit.korean.md
Normal file
59
sections/security/requestpayloadsizelimit.korean.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# 리버스 프록시나 미들웨어를 사용해서 페이로드 크기를 제한해라
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
JSON 인코딩 페이로드와 같은 요청구문은 요청의 크기가 클수록 높은 성능이 요구된다.
|
||||||
|
웹 애플리케이션에서 요청을 처리할 때 페이로드의 크기를 제한해야 한다.
|
||||||
|
요청의 크기를 제한하지 않으면 서비스 거부 또는 기타 원치 않는 부작용으로 인해 애플리케이션의 성능이 저하되거나 충돌이 생긴다.
|
||||||
|
Express를 위한`body-parser`와 같은 요청문 분석을 위한 인기 있는 미들웨어의 요청 페이로드 크기 제한 옵션을 사용하여 개발자는 쉽게 요청의 크기를 제한할 수 있다.
|
||||||
|
당신은 리버스 프록시 또는 웹서버 소프트웨어가 지원한다면 해당 기능을 통해 요청문의 크기제한을 통합할 수 있다.
|
||||||
|
다음은 `express` 또는 `nginx`를 사용하여 요청문의 크기를 제한하는 예이다.
|
||||||
|
|
||||||
|
### `express`를 사용하는 예시
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const express = require('express');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
app.use(express.json({ limit: '300kb' })); // body-parser의 기본 사이즈 제한은 100kb이다
|
||||||
|
|
||||||
|
// json body을 포함한 요청
|
||||||
|
app.post('/json', (req, res) => {
|
||||||
|
|
||||||
|
//body-parser가 content-type을 체크할 수 없기 때문에 content-type이 json인지 확인한다
|
||||||
|
if (!req.is('json')) {
|
||||||
|
return res.sendStatus(415); // JSON으로 이루어진 요청문이 아닌것은 지원하지 않는다.
|
||||||
|
}
|
||||||
|
|
||||||
|
res.send('Hooray, it worked!');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(3000, () => console.log('Example app listening on port 3000!'));
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [**express.json()을 위한 Express 문서**](http://expressjs.com/en/4x/api.html#express.json)
|
||||||
|
|
||||||
|
### `nginx`를 사용하는 예시
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
http {
|
||||||
|
...
|
||||||
|
# 모든 요청에 대해 1MB의 크기 제한
|
||||||
|
client_max_body_size 1m;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
...
|
||||||
|
# 특정 서버로 들어오는 요청에 대해 1MB의 크기 제한
|
||||||
|
client_max_body_size 1m;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /upload {
|
||||||
|
...
|
||||||
|
# 특정 경로로 들어오는 요청에 대해 1MB의 크기 제한
|
||||||
|
client_max_body_size 1m;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
🔗 [**client_max_body_size 사용을 위한 Nginx 문서**](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size)
|
||||||
16
sections/security/safemoduleloading.korean.md
Normal file
16
sections/security/safemoduleloading.korean.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# 변수를 사용해 모듈을 로딩하는것을 피해라
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
사용자의 입력으로 값이 변할 수 있기에 매개변수로 제공된 경로를 사용한 파일의 사용을 피해라.
|
||||||
|
일반적으로 `fs.readFile()` 또는 사용자가 입력한 변수가 민감한 리소스에 접근 할 수 있도록 확장될 수 있다.
|
||||||
|
|
||||||
|
### 코드 예시
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 사용자의 입력에 의해 helperPath 변수가 수정되었을 수 있기 때문에 안전하지 않음
|
||||||
|
const badWayToRequireUploadHelpers = require(helperPath);
|
||||||
|
|
||||||
|
// 안전함
|
||||||
|
const uploadHelpers = require('./helpers/upload');
|
||||||
|
```
|
||||||
38
sections/security/sandbox.korean.md
Normal file
38
sections/security/sandbox.korean.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# 위험한 코드는 샌드박스 안에서 실행해라
|
||||||
|
|
||||||
|
### 한문단 요약
|
||||||
|
|
||||||
|
경험상 자신의 JavaScript 파일만 실행해야 한다.
|
||||||
|
이론은 미뤄두고, 실제로는 런타임에 동적으로 전달되는 JavaScript 파일을 실행해야 한다.
|
||||||
|
예를 들어, 사용자 정의 로더를 허용하고 빌드 시간동안 동적으로 실행되는 webpack과 같은 프레임워크의 사용을 떠올려 보아라.
|
||||||
|
일부 악성 플러그인이 있는 경우 우리는 손상을 최소화하고 흐름이 성공적으로 종료되도록 하기를 원한다. 이를 위해서는 리소스, 충돌 및 공유된 정보의 측면에서 완전히 격리된 샌드박스 환경에서 플러그인을 실행해야 한다.
|
||||||
|
|
||||||
|
이런 격리를 실행하는데 도움이 될 수 있는 세 가지 주요 옵션은 다음과 같다:
|
||||||
|
|
||||||
|
- 전용 자식 프로세스 - 이것은 빠른 정보 격리를 제공하지만 자식 프로세스를 길들이고 실행시간을 제한하며 오류로부터 복구해야 한다.
|
||||||
|
- 클라우드 서버리스 프레임워크는 모든 샌드박스 요구 사항을 확인하지만 Faas 기능을 동적으로 배포하고 호출하는 것은 공원에서 산책하는것 만큼 쉬운일이 아니다.
|
||||||
|
- [sandbox](https://www.npmjs.com/package/sandbox) 그리고 [vm2](https://www.npmjs.com/package/vm2)같은 몇몇 npm 라이브러리는 한줄의 코드에서 격리된 코드를 실행할 수 있다. 이는 간편하지만 제한된 보호를 제공한다.
|
||||||
|
|
||||||
|
### 예시 코드 - Sandbox 라이브러리를 사용여 격리된 코드 실행
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const Sandbox = require('sandbox');
|
||||||
|
const s = new Sandbox();
|
||||||
|
|
||||||
|
s.run('lol)hai', (output) => {
|
||||||
|
console.log(output);
|
||||||
|
//output='Syntax error'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 제한된 코드
|
||||||
|
s.run('process.platform', (output) => {
|
||||||
|
console.log(output);
|
||||||
|
//output=Null
|
||||||
|
});
|
||||||
|
|
||||||
|
// 무한 루프
|
||||||
|
s.run('while (true) {}', (output) => {
|
||||||
|
console.log(output);
|
||||||
|
//output='Timeout'
|
||||||
|
});
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user