04·개념·10분
데이터베이스와 행 수준 보안
관계형 데이터베이스는 테이블의 집합입니다. 각 테이블은 격자입니다. 열은 한 종류의 대상을 설명하고(주문에는 합계, 상태, 날짜가 있음), 각 행은 그 대상 하나입니다.
키가 테이블을 잇는다
모든 행에는 다른 어떤 행과도 겹치지 않는 기본 키, 보통 id가 있습니다. 외래 키는 다른 테이블의 id를 담는 열입니다. 주문은 주문한 고객의 id를 갖습니다. "이 고객의 주문을 보여줘"는 이 숫자 하나로 작동하고, 주문이 있는 고객을 지우려 하면 주문을 어떻게 할지 말하기 전까지 거부되는 이유이기도 합니다.
쿼리
앱은 쿼리로 읽고 씁니다. 상태가 paid인 행 찾기, 행 추가, 필드 하나 수정, 개수 세기. 쿼리는 부품으로 조립되며, 값(누군가 입력한 이메일, URL의 id)은 쿼리 본문과 따로 전송됩니다. 이 분리가 악의적인 값이 명령으로 바뀌는 것을 막습니다. 파라미터화라고 하며 SQL 인젝션에 대한 표준 방어입니다.
행 수준 보안
접근 제어는 보통 앱 코드에 있습니다. "소유자가 아니면 보여주지 마라." **행 수준 보안(RLS)**은 이 규칙을 데이터베이스 자체로 옮깁니다. orders 테이블의 정책이 "행의 고객 id가 세션의 사용자 id와 일치할 때만 읽을 수 있다"고 말할 수 있습니다. 그러면 어떤 페이지나 스크립트에서 온 쿼리든 이 정책으로 걸러집니다. 한 페이지의 버그가 다른 고객의 행을 유출할 수 없습니다. 데이터베이스가 애초에 돌려주지 않기 때문입니다.
RLS는 행에 관한 것입니다. 열 수준 규칙(고객에게 원가 숨기기)과 테이블 수준 규칙(직원만 정산 테이블 읽기)이 그 옆에 함께 있습니다.
DontCode에서는
각 프로젝트는 격리된 자체 데이터베이스 스키마를 가지며, users 테이블은 플랫폼이 관리하고 보호합니다. 공개 API 쿼리는 원시 SQL이 아니라 구조화된 객체이고, 모든 값은 서버에서 파라미터화됩니다. 스키마 변경은 실행 전에 검증되고 실패하면 되돌려지는 마이그레이션을 거칩니다.
이해도 확인
1.외래 키란 무엇일까요?
2.페이지에 버그가 있어 현재 사용자의 주문이 아니라 모든 주문을 요청합니다. RLS 정책이 있다면 사용자는 무엇을 볼까요?
3.쿼리 값을 쿼리 본문과 따로 보내는 이유는?
4.RLS 정책을 무시하는 쿼리는?