보안 지침

API 속도 제한 및 보안 필터링

디스코드 API 속도 제한(429)을 방지하고 사용자 입력 검증 및 메모리 누수를 예방하는 방법을 다룹니다.

봇을 안정적으로 운영하기 위해서는 외부 사용자의 도배 요청을 제어하는 API 레이트 리밋(Rate Limit) 관리와 안전한 입력값 검증이 필수적입니다.


1. 디스코드 API 속도 제한 (Rate Limit) 관리

디스코드 API 게이트웨이는 단일 IP 및 봇 토큰 단위로 초당 요청 처리 수량을 제한합니다. 이를 초과하여 빠르게 메시지를 연속 발송하면 429 Too Many Requests 에러가 발생하며 일시적으로 통신이 차단될 수 있습니다.

  • 메시지 일괄 전송(Batching): 여러 개의 정보를 한 번에 보내야 한다면 각각 별도 메시지로 보내기보다, 하나의 임베드 필드 목록에 합쳐서 전송하는 것이 요청 수를 크게 줄입니다.
  • 적절한 딜레이(Delay) 추가: 대량의 반복 작업을 처리할 때는 최소 0.5초 이상의 지연(Sleep / setTimeout)을 주어 요청이 집중되지 않도록 조절하세요.

2. 사용자 입력값 검증 및 인젝션 예방

사용자가 명령어 인자나 대화창을 통해 전달하는 입력값은 항상 검증 과정을 거쳐야 합니다.

  • SQL Parameterized Query 사용: SQLite 등 데이터베이스에 사용자 입력값을 저장할 때 문자열을 직접 연결(+)하지 마세요. 반드시 파라미터 바인딩(? 또는 플레이스홀더)을 사용해야 SQL 인젝션을 방지할 수 있습니다.
  • 명령어 실행 함수 주의: 사용자 입력 문자열을 셸 명령어로 직접 넘겨 child_process.exec() 등으로 실행하는 것은 매우 위험하므로 피해야 합니다.

3. 중첩 이벤트 리스너 방지 (메모리 누수 예방)

이벤트 리스너 내부에서 또 다른 리스너를 중첩 등록하면 메시지가 올 때마다 리스너가 누적되어 심각한 메모리 누수가 발생합니다.

잘못된 예시 (중첩 등록)

client.on('messageCreate', (message) => {
  if (message.content === '!인증') {
    // !인증 명령이 올 때마다 새로운 리스너가 누적되어 메모리 누수가 발생합니다.
    client.on('messageCreate', (reply) => {
      if (reply.content === '동의') {
        message.reply('인증이 끝났습니다.');
      }
    });
  }
});

올바른 예시 (MessageCollector 활용)

특정 사용자의 후속 입력을 대기할 때는 createMessageCollector를 활용해 필요한 조건과 제한 시간을 지정하는 것이 안전합니다.

client.on('messageCreate', async (message) => {
  if (message.content === '!인증') {
    message.reply('동의 여부를 입력해 주세요. (제한시간 10초)');
    
    // 해당 사용자의 메시지만 수집하는 콜렉터 생성
    const filter = m => m.author.id === message.author.id;
    const collector = message.channel.createMessageCollector({ filter, time: 10000, max: 1 });
    
    collector.on('collect', m => {
      if (m.content === '동의') {
        m.reply('인증이 정상 완료되었습니다.');
      }
    });
  }
});