Rails 애플리케이션 인프라의 숨겨진 취약점
일반적인 Rails 애플리케이션은 데이터베이스, 캐시, 마이크로서비스와 같은 외부 서비스, Docker 및 Kubernetes를 활용한 배포, 그리고 Rails 개발팀 등 다양한 계층으로 구성됩니다. 이 모든 계층은 Ruby 위에서 실행되지만, Ruby 자체의 안정성에 대한 책임이나 가시성이 부족할 수 있습니다. 새로운 Rails 앱조차 21개의 네이티브 Gem을 기본으로 설치하며, 이는 잠재적인 불안정성 요인을 21개 더 추가하는 것과 같습니다.
Ruby 및 네이티브 Gem 충돌의 주요 원인
Ruby와 많은 네이티브 Gem은 C로 작성되어 있어 C 코드에서 발생하는 일반적인 버그에 취약합니다.
- C 코드 버그:
- Use-after-free: 이미 해제된 메모리를 다시 접근하여 예측 불가능한 동작이나 충돌을 유발합니다.
- Buffer overflow: 할당된 메모리 영역을 벗어나 데이터를 쓰거나 읽어 충돌, 데이터 손상, 심지어 보안 공격으로 이어질 수 있습니다.
- Memory leaks: 메모리 해제 누락으로 인해 프로세스가 결국 시스템에 의해 강제 종료될 수 있습니다.
- Ruby C API 오용:
- Missing GC guards: C 컴파일러의 스택 최적화로 인해 Ruby GC가 활성 객체를 놓쳐 객체가 이동되거나 재활용되어 예상치 못한 동작이나 충돌을 일으킬 수 있습니다.
- Raising errors: C의
long jump기능을 사용하여 오류를 발생시킬 때 수동으로 관리되는 메모리가 누락되어 메모리 누수로 이어질 수 있습니다. - Missing write barriers: 올바르게 구현하기 어려운 복잡한 메모리 관리 버그입니다.
- Rust Gem에 대한 오해: Rust의 메모리 안전성 약속에도 불구하고, Ruby C API와의 직접적인 인터페이스 과정에서 구현상의 어려움이 존재하며, 개발자들이 코드의 실제 동작을 충분히 이해하지 못하는 경우가 많아 불안정성을 초래할 수 있습니다.
프로덕션 충돌 사전 예방 기법
- Assertions 활성화: Ruby 컴파일 시
-DRUBY_DEBUG플래그를 추가하여 Ruby 내부 상태 검사를 강화하고 CI 환경에서 버그를 조기에 발견합니다. - YJIT
call_threshold=1설정: YJIT가 모든 메서드를 첫 실행 시 컴파일하도록 설정하여 테스트 환경에서 YJIT 관련 버그를 더 많이 노출시킵니다. - 메모리 검사 도구 사용: Valgrind 또는 Address Sanitizer(ASan)와 같은 도구를 사용하여
use-after-free또는out-of-bounds메모리 접근과 같은 C 메모리 오류를 감지합니다. (성능 저하 및 메모리 사용량 증가를 고려해야 합니다.) - Ruby Head 대상 야간 CI 실행: Ruby 마스터 브랜치에 대해 야간 CI를 실행하여 다음 Ruby 버전과의 호환성 문제 및 Ruby 자체의 버그를 조기에 발견하고 업스트림에 기여합니다.
프로덕션 충돌 정보 수집 및 디버깅
- Ruby 충돌 보고서: Ruby 충돌 시 충돌 유형, Ruby 스택 트레이스, C 스택 트레이스를 포함하는 보고서가 생성됩니다. Ruby 3.3부터
RUBY_CRASH_REPORT환경 변수를 통해 파일로 리다이렉션할 수 있습니다. - 코어 덤프: 충돌 시점의 프로그램 상태(스택, 힙, 모든 변수)를 담은 파일입니다. GDB나 LLDB와 같은 디버거로 분석할 수 있지만, 민감한 정보(비밀번호, PII)를 포함할 수 있으므로 보안에 각별히 유의해야 합니다. Shopify는 코어 덤프를 암호화하여 클라우드에 업로드하고 접근을 제한합니다.
- Shopify의 Crash Reporter: 코어 덤프를 클라우드에 업로드하고, 관련 Ruby 충돌 보고서를 찾아 업로드하며, 에러 모니터링 시스템에 이벤트를 생성하여 충돌을 추적합니다.
- 코어 덤프 디버깅: 디버깅을 위해서는 코어 덤프 파일, 원본 Ruby 바이너리, 시스템 라이브러리 및 네이티브 Gem 바이너리(심볼 포함), 그리고 프로덕션 시스템과 동일한 운영체제 및 CPU 아키텍처가 필요합니다. Docker와 같은 컨테이너 시스템을 활용하면 이러한 요구사항을 쉽게 충족할 수 있습니다.