LLM에게 SQL을 생성시켰다가 털린 사례, 인젝션 막는 실전 가드

LLM에게 SQL을 생성시켰다가 회사 데이터베이스가 통째로 털렸다는 이야기, 정말 가능한 일일까요? 네, 가능합니다. 자연어 질문을 SQL로 바꿔주는 text-to-SQL 기능을 앱에 붙이는 순간, 사용자 입력이 LLM을 거쳐 실행 가능한 쿼리로 둔갑하는 새로운 인젝션 경로가 하나 더 생기기 때문입니다. 이 글에서는 LLM이 만든 SQL을 검증 없이 실행했을 때 실제로 어떤 경로로 뚫리는지, 그리고 파라미터 바인딩·권한 최소화·화이트리스트 검증으로 … Read more

파이썬 로깅에 traceback이 안 찍힐 때, exc_info부터 확인해 보세요

파이썬 로깅에 traceback이 안 찍혀서 당황했던 코드를 그대로 재현해 보면 원인은 거의 항상 한 가지로 좁혀집니다. except 블록 안에서 logging.error()를 호출하면서 exc_info 인자를 빠뜨린 경우입니다. 아래 코드를 그대로 실행해 보면, 예외 메시지 한 줄만 로그에 찍히고 정작 어디서 터졌는지 알려주는 traceback은 통째로 사라진다는 걸 확인할 수 있습니다. 이 글은 파이썬 3.8~3.12, 표준 라이브러리 logging 모듈 … Read more

requests에서 httpx로 옮길 때 진짜 달라지는 것들

“requests에서 httpx로 옮기면 코드가 얼마나 바뀔까요?” 검색창에 이렇게 쳐보신 적 있으실 텐데요, 정답은 “API는 거의 그대로지만 기본 동작 몇 가지가 조용히 달라진다”예요. 특히 타임아웃 기본값과 리다이렉트 처리 방식을 모르고 옮기면, 멀쩡하게 돌던 코드가 운영 환경에서 갑자기 예외를 던지는 경우가 생겨요. 이 글에서는 실제로 코드 동작이 달라지는 지점만 골라서, 조건과 예외 상황까지 함께 짚어볼게요. 먼저 전체 … Read more

Playwright로 로그인 세션을 재사용할 때, 쿠키 저장과 만료 감지부터 챙기세요

Playwright로 로그인 세션을 재사용할 때 가장 먼저 부딪히는 문제는 storageState()로 저장한 쿠키 파일을 그대로 믿어버리는 것입니다. 쿠키에는 만료 시각이 분명히 남아있지만, Playwright는 그 세션이 서버 쪽에서 이미 무효화됐는지까지는 알려주지 않습니다. 이 글에서는 로그인 세션을 저장하고 재사용할 때 실제로 쓰는 코드와, 파일 안의 만료 시각을 직접 검사하는 방법, 그리고 검사를 건너뛰면 어떤 일이 생기는지를 순서대로 정리합니다. … Read more

LLM 스트리밍 응답에서 토큰 수를 실시간으로 세는 법

LLM 스트리밍 응답에서 토큰 수를 실시간으로 확인하려면 전체 답변이 끝날 때까지 기다렸다가 한 번에 세야 한다고 생각하시는 분이 많은데요, 실제로는 응답이 오는 도중에도 토큰 수를 계속 누적해서 셀 수 있습니다. 방법은 크게 두 가지로 나뉘는데요, 클라이언트에서 토크나이저로 직접 세는 방식과 API가 스트림 중간이나 마지막에 내려주는 사용량 필드를 그대로 읽는 방식입니다. 어떤 모델과 SDK를 쓰느냐에 따라 … Read more

정적 파일 CDN 캐시가 배포 후에도 안 바뀌는 이유와 헤더 해결법

결론부터 말씀드리면, 정적 파일 CDN 캐시가 배포 후에도 그대로 남아있는 문제는 대부분 응답 헤더의 max-age 값과 CDN 엣지 캐시가 아직 만료되지 않았기 때문에 생깁니다. 파일 성격에 맞춰 Cache-Control을 다르게 설정하고, 배포 스크립트에 CDN 캐시 무효화 호출을 넣으면 대부분 해결됩니다. 이 글에서는 캐시가 안 바뀌는 구조적 원인부터, 실제로 쓸 수 있는 헤더·무효화 설정, 그리고 설정을 고쳐도 … Read more

Alembic 마이그레이션이 프로덕션에서 실패했을 때, 되돌리는 순서

이 글에서는 Alembic 마이그레이션이 프로덕션에서 실패했을 때 무엇부터 확인하고 어떤 순서로 되돌려야 하는지를 정리합니다. 결론부터 말씀드리면, 스키마를 먼저 되돌리기 전에 애플리케이션 코드 롤백 여부와 alembic_version 테이블의 실제 상태부터 확인하는 게 순서입니다. 순서를 반대로 하면 스키마는 되돌렸는데 코드는 새 스키마를 기대하는 상태가 되어 장애가 더 커지는 경우가 많습니다. 이 내용은 Alembic 1.13 계열, SQLAlchemy 2.x, PostgreSQL … Read more

FastAPI 의존성 주입에서 DB 세션이 새는 이유, yield 패턴부터 점검하기

SQLAlchemy 커넥션 풀을 pool_size=5로 두고 운영하다가 로그에 QueuePool limit of size 5 overflow 10 reached, connection timed out이 찍히기 시작했다면, 원인은 거의 하나로 좁혀집니다. FastAPI 의존성 주입에서 만든 DB 세션이 요청이 끝난 뒤에도 반납되지 않고 계속 쌓이는 경우입니다. 이 글은 yield 패턴을 어떻게 써야 세션이 새지 않는지, 어떤 조건에서 그 원칙이 깨지는지를 실제 코드로 짚어 … Read more

LLM 응답을 임베딩과 함께 저장할 때 자주 나오는 스키마 실수

결론부터 말씀드리면, LLM 응답을 임베딩과 함께 저장할 때 나는 대부분의 문제는 임베딩 차원을 고정하지 않은 테이블 설계, 원본 응답과 임베딩 대상 텍스트를 한 컬럼에 몰아넣는 구조, 그리고 모델 버전 기록 누락에서 시작됩니다. 이 세 가지만 스키마 단계에서 잡아도 나중에 벡터 차원 불일치 에러나 검색 품질 저하로 테이블을 갈아엎는 일을 피할 수 있습니다. 아래에서는 PostgreSQL과 pgvector … Read more

파이썬 멀티프로세싱에서 pickle 에러 잡는 법

이 글에서는 파이썬 멀티프로세싱에서 pickle 에러가 나는 정확한 원인, 직접 재현한 코드와 출력, 상황별 우회법 네 가지를 순서대로 다룹니다. 결론부터 짧게 말씀드리면, 이 에러는 대부분 대상 함수를 모듈 최상위가 아닌 곳(함수 안의 함수, 람다, 클래스 메서드)에 정의했을 때 나타나고, 함수를 최상위로 옮기거나 dill 기반 도구로 바꾸면 대부분 해결됩니다. 다만 이 방법들이 항상 만능은 아니라서, 어디서 … Read more