설명
Node.js에서 child_process 모듈의 spawn, spawnSync 함수에 {shell: true} 또는 {shell: '/bin/sh'} 옵션을 사용하면 외부 명령어가 쉘 환경에서 실행됩니다. 이로 인해 사용자 입력 값이 특수 문자를 포함할 경우 의도치 않은 명령어가 실행될 수 있고, 공격자가 임의의 명령어를 삽입(주입)할 수 있습니다.
잠재적 영향
- 명령어 실행 권한 탈취 (명령어 권한 남용): 공격자가 악성 코드를 실행하거나 서버의 중요한 파일을 삭제, 유출할 수 있습니다.
- 데이터 유출 및 손상 (데이터 누출 및 변조): 민감한 시스템 데이터를 외부로 유출하거나, 데이터를 조작 및 파괴할 수 있습니다.
- 서비스 중단 (서비스 거부): 시스템 자원을 고갈시키거나 프로세스를 종료시켜 서비스가 중단될 수 있습니다.
해결 방법
- 고정된 실행 파일을 사용하고
{shell: false}로 인자를 배열로 전달하세요. - 셸 실행이 필요한 경우 명령어와 인자를 신뢰할 수 있는 허용 목록으로 제한하세요.
- 외부 입력을 명령어나 인자로 사용하기 전에 검증하고, 따옴표 처리에만 의존하지 마세요.
예시
변경 전
javascript
const { spawn } = require("child_process");
const app = require("express")();
app.get("/list", (req, res) => {
// 요청 입력이 셸에서 해석되는 인자로 전달됩니다.
const userInput = req.query.path;
const p = spawn("ls", ["-lh", userInput], { shell: true });
});
변경 후
javascript
const { spawn } = require("child_process");
const app = require("express")();
app.get("/list", (req, res) => {
const userInput = req.query.path;
if (typeof userInput !== "string" || !/^[a-zA-Z0-9_-]+$/.test(userInput)) {
return res.sendStatus(400);
}
// 고정된 실행 파일에 검증된 인자를 전달하고 셸을 사용하지 않습니다.
const p = spawn("ls", ["-lh", "--", userInput], { shell: false });
});
설명:
- 변경 전: shell: true 옵션을 사용하면, 사용자가 입력한 값에 특수 문자가 포함될 경우 쉘에서 그 값을 명령어처럼 해석할 수 있어 명령어 주입 공격이 발생할 수 있습니다.
- 변경 후:
shell: false(기본값)로 셸 해석을 피하고 입력 형식을 제한합니다.--는ls가 입력을 옵션으로 해석하지 않게 합니다. 실행 파일의 위치와 조회할 디렉터리의 접근 권한은 별도로 관리해야 합니다.