티스토리 뷰

 

 

📌 3줄 요약
1. NoSQL은 표(테이블)에 얽매이지 않고 데이터를 자유롭게 저장하는 데이터베이스입니다.
2. 대용량·고속·유연한 구조가 필요할 때 쓰며, RDBMS를 대체하기보다 함께 씁니다.
3. SQL을 안 쓴다고 인젝션이 없는 게 아닙니다. NoSQL 인젝션과 무인증 노출이 핵심 위험입니다.

신규 서비스 취약점 점검을 하다 보면 이런 답변을 자주 듣습니다. "저희는 MongoDB라서 SQL 인젝션 항목은 해당 없습니다."

틀린 말은 아닙니다. SQL을 쓰지 않으니 SQL 인젝션은 성립하지 않습니다.

 

그런데 로그인 요청의 password 값을 {"$ne": null}로 바꿔 보내면, 비밀번호 없이 admin으로 로그인되는 경우가 있습니다. 이름만 다를 뿐 인젝션은 그대로 살아 있는 상태입니다. 이 글에서는 NoSQL이 무엇이고 왜 쓰는지, 어떤 종류가 있고 어디에 쓰는지, 그리고 보안 점검 시 무엇을 봐야 하는지를 정리했습니다.


🎯 NoSQL이란?

NoSQL은 "Not Only SQL"의 줄임말입니다. "SQL을 쓰지 않는다"가 아니라 "SQL 방식만 고집하지 않는다"는 뜻입니다.

구분 RDBMS (관계형 DB) NoSQL (비관계형 DB)
비유 칸이 정해진 엑셀 표 자유롭게 쓰는 서류철
데이터 구조 테이블 · 행 · 열 (고정 스키마) 키-값 · 문서 · 컬럼 · 그래프 (유연한 스키마)
쿼리 언어 SQL (표준) 제품마다 다름 (MongoDB Query, Redis 명령어 등)
확장 방식 주로 Scale-up 주로 Scale-out
일관성 강한 일관성 (ACID) 제품에 따라 최종 일관성 허용
대표 제품 MySQL, Oracle, PostgreSQL MongoDB, Redis, Cassandra, Neo4j

 

RDBMS에서 회원의 관심사를 저장하려면 별도 테이블을 만들고 JOIN을 해야 합니다. 문서형 NoSQL은 한 문서 안에 배열째 넣으면 끝납니다. 이 차이가 NoSQL의 장점이자, 뒤에서 볼 보안 문제의 출발점이기도 합니다.


🧩 왜 NoSQL을 쓸까?

문제 상황 RDBMS의 한계 NoSQL의 해결 방식
데이터 폭증 서버 한 대 성능을 키우는 데 한계 서버를 옆으로 늘리는 수평 확장
데이터 형태가 제각각 컬럼 추가·변경(ALTER)이 부담 스키마 없이 바로 저장
초고속 응답 필요 JOIN·트랜잭션 비용 단순 구조로 빠른 읽기·쓰기
무중단 서비스 단일 서버 장애 시 전체 중단 복제·분산으로 장애 흡수

💡 NoSQL이 "무조건 빠르다"는 뜻은 아닙니다. 단순한 조회를 대량으로 처리할 때 빠른 것이고, 복잡한 집계나 여러 데이터를 엮는 조회는 RDBMS가 더 유리한 경우가 많습니다.

🔍 NoSQL 4가지 유형

유형 저장 방식 대표 제품 주요 용도 기본 포트
키-값 Key 하나에 Value 하나 Redis, DynamoDB 로그인 세션, 캐시, 실시간 순위 6379 (Redis)
문서형 JSON(BSON) 문서 MongoDB, Couchbase 회원·상품·게시판 27017 (MongoDB)
컬럼 패밀리 행마다 다른 컬럼 묶음 Cassandra, HBase 대량 로그, IoT 시계열 9042 (Cassandra)
그래프형 노드와 관계(엣지) Neo4j, Amazon Neptune 친구 추천, 이상거래 탐지 7687 (Neo4j)

기본 포트는 점검 시 외부 노출 여부를 확인할 때 그대로 쓰이니 같이 기억해 두면 좋습니다.


🛠 실제로는 이렇게 섞어 씁니다

현업 서비스는 DB 하나로 끝나지 않습니다. 데이터 성격에 맞춰 여러 DB를 조합하는데, 이를 폴리글랏 퍼시스턴스(Polyglot Persistence)라고 부릅니다.

데이터 추천 DB 이유
결제·주문·계좌 RDBMS 정합성(트랜잭션)이 최우선
로그인 세션·인기 상품 캐시 Redis 메모리 기반, 밀리초 단위 응답
형식이 자주 바뀌는 상품 상세 MongoDB 스키마 변경 없이 필드 추가
대량 접속 로그 Cassandra / Elasticsearch 쓰기 성능과 확장성
연관 관계 분석 (추천·FDS) Neo4j 관계 탐색이 빠름

⚖️ 장단점 정리

구분 ✅ 장점 ❌ 단점
확장성 노드 추가만으로 수평 확장 분산 환경 운영 복잡도 증가
유연성 스키마 없이 빠른 개발 규칙이 없으면 데이터가 엉망이 됨
성능 단순 조회·대량 쓰기에 강함 복잡한 JOIN·집계는 비효율
일관성 가용성을 우선할 수 있음 강한 트랜잭션 보장이 약한 제품이 있음
표준화 용도별 최적 제품 선택 가능 제품마다 쿼리·보안 설정이 전부 다름

마지막 줄이 보안 담당자에게 가장 중요합니다. SQL은 하나를 알면 대부분 통하지만, NoSQL은 제품마다 인증·권한·인젝션 방식이 다릅니다. 점검 기준도 제품별로 따로 봐야 합니다.


⚠️ 보안 ① — NoSQL 인젝션

MongoDB는 쿼리를 문자열이 아니라 객체(JSON)로 받습니다. 그래서 입력값이 문자열이 아니라 객체로 들어오면, 값이 아니라 조건 자체가 바뀝니다.

// 공격자가 보낸 요청 (Content-Type: application/json)
{ "username": "admin", "password": { "$ne": null } }

// 취약한 서버 코드 — 요청 body를 그대로 조건에 넣음
db.users.findOne({ username: req.body.username, password: req.body.password })

// 실제 실행 조건 = "admin 이고 비밀번호가 null이 아니면" → 항상 참
공격 유형 삽입 예시 결과
연산자 인젝션 {"$ne": null}, {"$gt": ""} 조건이 항상 참 → 로그인 우회
정규식 인젝션 {"$regex": "^a"} 한 글자씩 비밀번호·토큰 추측
JavaScript 인젝션 $where 절에 코드 삽입 서버 측 JS 실행, DoS
폼 파라미터 변조 password[$ne]=x JSON이 아니어도 파서가 객체로 변환
⚠️ 마지막 항목을 특히 조심해야 합니다. Express(qs 파서) 등은 password[$ne]=x 같은 일반 폼 요청도 객체로 바꿔주기 때문에, "JSON 요청이 아니니까 괜찮다"는 판단도 틀릴 수 있습니다.

대응 방법

대책 내용
타입 검증 문자열이어야 할 값이 객체·배열이면 거부
연산자 필터링 $로 시작하거나 .이 포함된 키 제거 (express-mongo-sanitize, Mongoose sanitizeFilter 등)
$where 금지 서버 측 JavaScript 실행 비활성화 (security.javascriptEnabled: false)
스키마 검증 앱 단(Joi, Zod 등) 또는 DB 단(JSON Schema Validator)에서 형식 강제

⚠️ 보안 ② — 인증 없이 열려 있는 DB

NoSQL 사고의 상당수는 해킹 기술이 아니라 설정 문제입니다. 인증 없이 인터넷에 열린 MongoDB·Elasticsearch·Redis가 통째로 삭제되고 복구 대가를 요구받는 사례가 반복돼 왔습니다.

제품 흔한 문제 확인 포인트
MongoDB 인증 미설정, bindIp: 0.0.0.0 security.authorization: enabled 여부
Redis requirepass 미설정, protected-mode 해제 무인증 접속 시 명령 실행 가능 여부
Elasticsearch 보안 기능 비활성화로 REST API 공개 9200 포트 무인증 응답 여부
공통 평문 통신, 관리자 계정 공용 사용 TLS 적용, 계정별 최소 권한
⚠️ Redis는 무인증 상태로 노출되면 단순 데이터 유출에서 끝나지 않습니다. 설정 변경 명령으로 서버에 파일을 쓸 수 있어 서버 장악으로 이어질 수 있습니다. 내부망이라도 인증과 위험 명령 비활성화(rename-command, ACL)를 권장합니다.

📋 점검 체크리스트

확인 항목 확인 방법 (예시) 체크
외부에서 DB 포트가 열려 있지 않은가 nmap -p 6379,9042,9200,27017 <대상IP> ☐
MongoDB 인증이 활성화되어 있는가 mongod.conf의 security.authorization ☐
MongoDB 바인딩 IP가 제한되어 있는가 net.bindIp 값 확인 ☐
Redis 비밀번호/ACL이 설정되어 있는가 CONFIG GET requirepass / ACL LIST ☐
Redis protected-mode가 켜져 있는가 CONFIG GET protected-mode ☐
앱 계정이 최소 권한인가 (root/admin 미사용) db.getUsers() 권한 목록 ☐
입력값 타입 검증·연산자 필터링이 있는가 로그인·검색 API에 {"$ne":null} 테스트 ☐
서버 JS 실행이 비활성화되어 있는가 security.javascriptEnabled ☐
DB 통신에 TLS가 적용되어 있는가 net.tls.mode ☐
백업·접근 로그가 남고 있는가 백업 주기, 감사 로그 설정 ☐

🚫 이런 판단은 하지 마세요

① "SQL을 안 쓰니 인젝션 항목은 해당 없음"

SQL 인젝션은 해당 없어도 NoSQL 인젝션은 해당됩니다. "SQL 인젝션"이 아니라 "쿼리 인젝션" 관점으로 보고, 실제 요청을 변조해서 확인해야 합니다.

② "내부망이라 인증 안 걸어도 된다"

내부망 PC 한 대만 감염돼도 무인증 DB는 바로 털립니다. 내부 네트워크 스캔에서 무인증 Redis·MongoDB가 나오면 고위험으로 분류하는 게 맞습니다.

③ "클라우드 관리형이라 알아서 안전하다"

관리형 서비스는 패치와 인프라를 대신해 줄 뿐, 네트워크 공개 범위·계정 권한·입력값 검증은 여전히 사용자 몫입니다.

④ "스키마리스니까 검증도 필요 없다"

스키마가 없다는 건 DB가 대신 검증해 주지 않는다는 뜻입니다. 그만큼 애플리케이션에서 더 엄격하게 검증해야 합니다.


💬 자주 나오는 질문

Q. NoSQL이 RDBMS보다 좋은 건가요?

우열이 아니라 용도 차이입니다. 돈이 오가는 데이터는 RDBMS, 대량·고속·유연한 데이터는 NoSQL이 맞고, 대부분의 서비스는 둘을 함께 씁니다.

Q. 정적 분석(SAST) 도구가 NoSQL 인젝션도 잡나요?

도구와 룰셋에 따라 다릅니다. SQL 인젝션 룰만 켜져 있으면 MongoDB 쿼리 패턴은 누락될 수 있으니, NoSQL 관련 룰이 활성화되어 있는지 확인하고 동적 점검으로 교차 검증하는 편이 안전합니다.

Q. Redis는 캐시일 뿐인데 보안이 그렇게 중요한가요?

캐시에 세션 토큰이 들어 있는 경우가 많습니다. 세션이 털리면 로그인 없이 사용자 계정을 탈취할 수 있고, 앞서 본 것처럼 서버 장악까지 이어질 수 있습니다.

Q. 입력값 필터링 라이브러리만 쓰면 끝인가요?

1차 방어로는 효과적이지만, 타입 검증 + 최소 권한 계정 + 네트워크 차단을 함께 적용해야 합니다. 하나가 뚫려도 다음 단계에서 막히는 구조가 목표입니다.


🎉 정리

  1. NoSQL은 "Not Only SQL" — 표에 얽매이지 않는 데이터베이스의 총칭이다.
  2. 목적은 확장성·속도·유연성이다. 대신 복잡한 조회와 강한 일관성은 약하다.
  3. 키-값·문서·컬럼·그래프 4가지 유형이 있고 용도가 다르다.
  4. RDBMS를 대체하는 게 아니라 함께 쓴다.
  5. SQL을 안 써도 인젝션은 있다. 입력값이 객체로 들어오는 순간 쿼리 구조가 바뀐다.
  6. 사고의 상당수는 설정 문제다. 인증·바인딩 IP·포트 노출부터 확인하자.
  7. 제품마다 보안 설정이 다르다. "NoSQL 점검"이 아니라 "MongoDB 점검", "Redis 점검"으로 봐야 한다.

"MongoDB라 인젝션 해당 없음"이라는 답변을 들으면, 로그인 API에 {"$ne": null} 한 번만 보내보세요. 그 한 번의 요청이 점검 결과를 바꿉니다.


🔗 참고 자료