명령어 주입 (Command Injection)

Command Injection

설명

명령어 주입 취약점은 사용자의 입력값이 검증 없이 운영 체제 명령어로 실행될 때 발생합니다. Node.js의 child_process.exec와 execSync는 셸을 사용합니다. spawn과 spawnSync는 기본적으로 셸을 사용하지 않지만, shell: true를 설정하거나 아래처럼 sh -c에 입력을 넘기면 공격자가 셸 명령을 삽입할 수 있습니다. 실행 파일이나 인자를 사용자가 선택하는 경우에도 허용할 동작을 제한해야 합니다.

잠재적 영향

  • 애플리케이션 프로세스의 권한으로 의도하지 않은 명령이 실행될 수 있습니다.
  • 데이터 유출 및 변조 (중요 파일 접근이나 데이터 삭제)
  • 서비스 마비 (DoS, 시스템 장애 등)

해결 방법

  • 사용자 입력을 명령 문자열로 실행하지 말고, 고정된 실행 파일과 검증한 인자 배열을 사용하세요.
  • 입력으로 동작을 선택해야 한다면 허용 목록으로 제한하세요.
  • sh -c처럼 입력을 다시 코드로 해석하는 인터프리터 호출을 피하고, 실행 파일의 위치와 PATH를 신뢰할 수 있게 관리하세요.

예시

변경 전

javascript
const {spawnSync} = require('child_process');
function runCommand(userInput) {
  // 취약: 사용자가 입력한 명령어를 직접 실행
  spawnSync('sh', ['-c', userInput]);
}

변경 후

javascript
const {spawnSync} = require('child_process');
function runCommandSafe(userInput) {
  // 안전: 입력값을 미리 정의된 명령에만 사용
  const allowedCommands = ['ls', 'pwd'];
  if (!allowedCommands.includes(userInput)) {
    throw new Error('허용되지 않은 명령어입니다.');
  }
  spawnSync(userInput, []);
}

설명:

  • 변경 전: userInput을 sh -c에 전달해 셸 명령으로 실행합니다.
  • 변경 후: 입력을 ls와 pwd로 제한하고 셸 없이 실행합니다. 이 이름이 의도한 실행 파일로 해석되도록 신뢰할 수 있는 PATH를 사용해야 합니다.

참조