설명
압축 해제 Reader의 출력을 크기 제한 없이 복사하면 작은 입력이 매우 큰 출력으로 확장되어 CPU, 메모리, 디스크를 고갈시킬 수 있습니다.
잠재적 영향
- 서버 리소스 고갈과 프로세스 장애가 발생할 수 있습니다.
- 업로드 또는 아카이브 처리 기능이 서비스 거부 공격 경로가 될 수 있습니다.
해결 방법
- 실제 압축 해제 출력에 크기 제한을 적용하고, 초과한 데이터는 거부하세요.
io.LimitReader는 제한에 도달해도 EOF를 반환하므로 크기 초과를 별도로 구분해야 합니다. - 파일에 선언된 비압축 크기만 신뢰하지 말고 실제 읽은 바이트 수를 검사하세요. 아카이브 전체의 출력 크기와 엔트리 수, 처리 시간도 제한하세요.
- Reader 생성·복사 오류를 처리하고 실패한 작업의 부분 출력은 폐기하세요.
예시
오류를 반환하는 함수 내부의 발췌입니다. src는 io.Reader, dst는 임시 출력이며, compress/gzip, io, fmt를 사용합니다. 호출자는 오류가 발생하면 부분 출력을 폐기해야 합니다. 10 MiB는 예시 상한이며 초과 확인을 위해 최대 한 바이트를 더 읽습니다.
변경 전
go
r, _ := gzip.NewReader(src)
_, _ = io.Copy(dst, r)
변경 후
go
const maxExpanded int64 = 10 << 20
r, err := gzip.NewReader(src)
if err != nil {
return err
}
defer r.Close()
n, err := io.Copy(dst, io.LimitReader(r, maxExpanded+1))
if err != nil {
return err
}
if n > maxExpanded {
return fmt.Errorf("expanded data exceeds limit")
}
return nil
설명:
- 변경 전: 압축 해제 Reader에서 나온 데이터를 크기 제한 없이
io.Copy또는io.CopyBuffer로 끝까지 복사하면, 작은 입력이 매우 큰 출력으로 확장되어 CPU, 메모리, 디스크를 고갈시킬 수 있습니다. - 변경 후: 오류를 처리하고 실제 출력 크기를 검사합니다. 상한을 초과하면 오류를 반환하며, 호출자는 임시 출력을 폐기해야 합니다.