C.W.K.
Stream
Lesson 10 of 10 · published

보안: Role, 권한, Injection 예방

~14 min · apps, security

Level 0스키마 새싹
0 XP0/86 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

Superuser 로 연결 금지

Default postgres 유저가 superuser — 모든 권한 체크 우회, DB drop 가능. 프로덕션 앱이 필요한 권한만 가진 least-privilege role 로 연결해야: 보통 앱 테이블에 SELECT, INSERT, UPDATE, DELETE, 그 이상 없음.

Role 과 grant

앱 role (app) 생성 + 특정 권한 grant. GRANT USAGE ON SCHEMA + GRANT SELECT, INSERT ON TABLE 사용. ALTER DEFAULT PRIVILEGES 가 나중에 만드는 테이블에 자동으로 같은 권한 grant.

Row-Level Security

RLS 가 multi-tenant 룰을 DB 자체로 push: "의사가 자기 환자만 봄", "유저가 자기 post 만 봄". 정책이 테이블에 attach; 그 테이블에 대한 모든 쿼리가 정책 투명하게 적용. Supabase 의 auth story 가 거의 전부 RLS 위에 세워짐.

SQL injection — 해결된 문제

파라미터화 쿼리 (드라이버 레벨) 가 injection 구조적으로 불가능하게. 어디서나 사용. 유저 입력 SQL 에 절대 연결 금지. Client 제공 식별자 이름 절대 신뢰 금지; 동적으로 컬럼 골라야 하면 allowlist 검증 + quote_ident.

Code

Least privilege 앱 role·sql
-- 앱이 쓰는 role 생성
CREATE ROLE app LOGIN PASSWORD '****';

-- Schema 사용
GRANT USAGE ON SCHEMA public TO app;

-- 테이블 권한
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app;

-- 미래 테이블이 같은 grant 자동
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app;
Row-Level Security 정책·sql
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

CREATE POLICY posts_owner_only
ON posts
FOR ALL
USING (author_id = current_setting('app.current_user_id')::int);

-- 앱이 각 요청 시작에 user id 설정
SET LOCAL app.current_user_id = '7';
SELECT * FROM posts;  -- author_id = 7 인 행만 반환
파라미터화 쿼리 — SQL injection 치료·python
# 드라이버가 escape 실수 없음 보장
cur.execute("SELECT * FROM posts WHERE author_id = %s AND status = %s", (user_id, status))

# 동적 식별자 (드뭄): allowlist + quote_ident
ALLOWED_COLUMNS = {'created_at', 'updated_at', 'title'}
if sort_col not in ALLOWED_COLUMNS:
    raise ValueError("invalid sort column")
cur.execute(
    sql.SQL("SELECT * FROM posts ORDER BY {} DESC").format(sql.Identifier(sort_col))
)

External links

Exercise

샌드박스에서 단일 테이블에 INSERT/SELECT 만 있는 app role 생성. 그 role 로 연결. DROP TABLE 시도 — 실패 확인. 그 다음 세션 변수로 행 필터하는 RLS 정책 추가; 동작 확인.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.