This guide details the method that actually works: structural restriction to SELECT, closed whitelist of functions, mandatory row cap, and locking of the queried schema. Each step relies on the validator actually implemented in Aurabase's NL2SQL engine, a capability of its native AI built into thebackend, not a third-party service thrown together after the fact. If the subject is new to you, our overview of NL2SQL lays the foundations, and the step-by-step tutorial shows how to build the complete endpoint.
필수사항
- 프롬프트 엔지니어링("SELECT만 생성")은 보안 검사가 아닌 입니다.: 모델은 환각을 느끼거나, 모호한 질문에 이끌리거나, 단순히 지침을 무시할 수 있습니다.
- 유지되는 유효성 검사는 구조적입니다. 파서는 요청의 구문 트리(AST)를 구성하고 기본적으로 명시적으로 승인되지 않은 모든 것을 거부합니다.
- 4개의 구체적인 레이어는 위험을 제한합니다. 엄격한 SELECT(하위 쿼리도 CTE도 UNION도 아님), 10개 기능의 폐쇄형 화이트리스트,
LIMIT필수 및 제한, 시스템 카탈로그 및 비테넌트 스키마에 대한 액세스 차단. - 쿼리된 스키마는 서버에서 와야 하며 클라이언트 요청의 필드에서 와서는 안 됩니다. 그렇지 않으면 호출자가 유효성 검사를 우회하기 위해 자체 스키마를 제공하는 것을 막을 수 있는 방법이 없습니다.
- Aurabase에서 이 검증기(Rust 크레이트
sqlparser)는 코드에 문서화된 적대적 사례, 즉FILTER, 집계 내ORDER BY또는OFFSET에 숨겨진 금지된 기능으로 테스트됩니다.
시스템 프롬프트의 지침이 아무것도 차단하지 않는 이유는 무엇입니까?
"SELECT 쿼리만 생성합니다"라는 시스템 프롬프트는 선호 사항이지 장벽이 아닙니다. 모델은 기술적 제약으로 인해 다른 내용을 작성할 수 없기 때문에가 아니라 지침을 따르도록 훈련되었기 때문에 대부분의 경우 이를 존중합니다. 두 가지 유형의 실패로 인해 생산 시 이러한 확신이 불충분해집니다.
첫 번째는 질문 자체에서 비롯됩니다. 의도가 없거나 단순히 창의적인 공식을 가진 사용자는 작성해서는 안 되는 SQL에 모델을 푸시하는 방식으로 질문을 지시할 수 있습니다. 즉, 민감한 테이블에 대한 조인, 예상되는 논리를 우회하는 필터, 시스템 함수 호출 등이 있습니다. 이 모델은 타당한 질문과 이를 조작하도록 설계된 질문을 구분하지 않습니다.
두 번째는 악의가 필요하지 않습니다. 모델은 테이블 이름을 환각하거나 프롬프트에서 요청한 LIMIT을 잊어버리거나 큰 테이블에 대한 제한 없이 SELECT *을 생성할 수 있습니다. 결과는 두 경우 모두 동일합니다. 프롬프트 필터를 통과하고 실제 데이터베이스에 대해 실행될 예정인 잠재적으로 비용이 많이 들거나 침입적인 SQL입니다.
시스템 프롬프트는 여전히 유용하며 대부분의 경우 모델을 올바른 결과로 안내합니다. 그러나 "접근 금지" 표시는 읽는 방법을 모르거나 이를 무시하기로 결정한 사람을 막지 못합니다. 앞에 패널만 있는 것이 아니라 뒤에 닫힌 문이 필요합니다.
생성된 SQL을 원시 문자열이 아닌 구문 트리로 구문 분석합니다.
첫 번째 방어선은 대상 방언에 대한 실제 파서를 사용하여 모델에서 생성된 SQL을 구문 분석한 다음 원시 텍스트가 아닌 결과 구조의 유효성을 검사하는 것입니다. 문자열에서 금지된 단어(“DROP”, “DELETE”, “;”)에 대한 검색은 대소문자 구별, 키워드 중간에 주석 삽입, 따옴표 입력 등으로 간단하게 우회됩니다. 구문 트리는 쿼리가 실제로 수행하는 작업을 명확하게 설명합니다.
Aurabase는 Rust 크레이트 sqlparser 및 해당 방언 PostgreSqlDialect을 사용하여 이 단계를 구현합니다. 구문 분석 전에도 첫 번째 어휘 필터는 트리에서 한 번 정확하게 추론하기 어려운 두 가지 구성, 즉 문자열의 임의 내용을 숨길 수 있는 달러 인용($$...$$)과 명령의 실제 끝을 숨길 수 있는 여러 줄 주석(/* */)을 거부합니다.
다중 문만 거부하면 가장 잘 알려진 형태의 SQL 주입(스태킹: SELECT * FROM users; DROP TABLE users;--)이 차단됩니다. 파서는 실행 가능한 명령 하나만 반환하며, 원래 질문에서 어떻게 표현되었든 두 번째 명령에는 도달하지 않습니다.
구조적으로 간단한 SELECT로 제한
트리를 얻은 후 가장 광범위한 검증은 루트 노드의 한 가지 유형인 쿼리(Statement::Query)만 허용하고 다른 모든 항목(INSERT, UPDATE, DELETE, DROP, CREATE, ALTER)을 거부하는 것입니다. 이는 더 이상 즉각적인 지시가 아니며, 질문에 대한 능숙한 공식화로 피할 수 없는 구문 분석된 개체의 유형에 대한 조건입니다.
SELECT 내에서도 여러 구성은 여전히 위험하며 명시적으로 거부할 가치가 있습니다.
| 건설 거부됨 | 왜 위험합니까? |
|---|---|
| CTE / 함께 | 최종 SELECT 전에 의도하지 않은 논리를 추가로 연결할 수 있습니다. |
| 하위 쿼리, UNION / INTERSECT / EXCEPT | 단일 쿼리에서 단일 질문으로 수행할 수 있는 작업의 표면적을 확장합니다. |
| 선택...으로 | 테이블을 생성합니다: 읽기를 가장한 글쓰기. |
| 업데이트용/공유용 | 잠금 장치 설치, 프로덕션 트래픽과의 경합 위험. |
| 테이블 함수(generate_series, pg_read_file...) | 요청 시 생성된 회선을 통한 시스템 액세스 또는 서비스 거부. |
저장소에서 가져온 테스트 사례는 마지막 요점을 구체적으로 보여줍니다. SELECT * INTO backup FROM users는 눈에 보이는 쓰기 키워드나 의심스러운 기능이 포함되어 있지 않더라도 거부됩니다. 요청 양식은 실격 처리하기에 충분합니다.
블랙리스트가 아닌 기능 화이트리스트
금지된 기능(pg_sleep, pg_read_file, dblink...)의 블랙리스트는 각각의 위험한 기능을 하나씩 예상해야 하는 반면 Postgres는 수백 가지 기능을 노출합니다. 화이트리스트는 증명 부담을 뒤집습니다. count, sum, avg, min, max, lower, upper, coalesce, date_trunc, now10개의 기능만 승인됩니다. . 아직 아무도 추가할 생각이 없는 합법적인 기능을 포함하여 다른 모든 것은 기본적으로 허용되지 않습니다.
단일 검증 패스가 항상 충분하지는 않습니다. 트리의 구조적 순회는 진입점을 하나씩 나열하며(프로젝션, WHERE, JOIN, GROUP BY...) 하나를 잊어버리기 쉽습니다. 금지된 함수는 FILTER (WHERE pg_sleep(10) IS NOT NULL)절, 집계 내 ORDER BY(sum(id ORDER BY pg_sleep(10))), WITHIN GROUP, DISTINCT ON또는 OFFSET.
따라서 Aurabase 유효성 검사기는 구조적 경로와 관계없이 트리의 모든 표현이 어디에 있든 통과하는 두 번째 철저한 패스를 추가합니다. 이는 심층 방어를 가정한 것입니다. 첫 번째 패스에서 케이스가 누락되면 두 번째 패스에서 따라잡습니다.
반환된 줄 바인딩: LIMIT 필수 및 제한
SELECT *은 승인된 상태로 유지되므로 데이터 마이닝에 유용합니다. 위험은 별이 아니라 모델이 작성한 쿼리에 상한선이 없다는 것입니다. 잘못 구성된 질문은 메모리 비용과 응답 시간을 포함하여 전체 테이블을 가져올 수 있습니다.
Aurabase는 간단하고 투명한 규칙을 적용합니다. 생성된 SQL에 LIMIT이 없으면 서버는 하나를 추가합니다(기본적으로 100줄, 시스템 프롬프트에서 모델에 알리는 값). SQL이 하드 캡(기본적으로 1000행)을 초과하여 LIMIT을 요청하는 경우 쿼리는 자동으로 줄어들지 않고 명시적으로 거부됩니다. 두 값 모두 서버 측에서 구성 가능하며(AI_NL2SQL_DEFAULT_LIMIT, AI_NL2SQL_MAX_LIMIT), 오류가 한도를 초과하면 서버는 시작을 거부하기도 합니다.
조용히 취소하는 것보다 거절하는 것은 직접적인 이익이 있습니다. 말하지 않고 천장을 적용하면 발신자에게 자신의 요청이 받아들여졌다는 착각을 주게 되고 결과는 자신도 모르는 사이에 잘리게 됩니다. limit_injected는 값이 모델에서 오는지 아니면 서버에서 나오는지 항상 알려줍니다.
스키마에 대한 액세스 잠금: 시스템 카탈로그 및 교차 스키마
두 가지 뚜렷한 누출이 실제 데이터베이스에 연결된 NL2SQL 엔진을 위협합니다. Postgres 시스템 카탈로그에 대한 액세스와 호출자에게 속하지 않은 스키마에 대한 액세스입니다. 다운스트림에 배치된 RLS 정책에 관계없이 검증 시 둘 다 차단됩니다.
pg_catalog은 항상 search_path의 일부입니다. 즉, pg_authid 또는 pg_stat_activity와 같은 정규화되지 않은 이름은 접두사 없이 직접 액세스합니다. Aurabase 유효성 검사기는 자격 여부에 관계없이 pg_로 시작하는 모든 이름은 물론 information_schema 및 내부 스키마 aura_console를 차단합니다.
두 구성 요소 이름(schema.table)에서는 호출 프로젝트의 스키마만 허용되고 다른 값은 거부됩니다. 세 개 이상의 구성 요소가 포함된 이름은 자동으로 거부됩니다. 생성된 쿼리 수준의 이 경계는다중 테넌트 격리에 대한 기사에 자세히 설명된 데이터베이스 수준 격리에 추가됩니다. 하나는 생성된 SQL이 다른 스키마를 대상으로 하는 것을 방지하고, 다른 하나는 연결 자체가 다른 데이터베이스에 도달하는 것을 방지합니다. 어느 쪽도 다른 쪽을 대체하지 않습니다.
클라이언트가 쿼리된 스키마를 재정의하지 않도록 하세요.
개별 트랩은 클라이언트 쿼리에서 허용되는 스키마 또는 테이블을 설명하는 매개변수를 허용하는 NL2SQL API를 기다리는 데 있습니다. 프롬프트를 구성하고 출력 SQL의 유효성을 검사하는 데 동일한 매개 변수가 사용되는 경우 호출자는 허용되는 내용에 대해 거짓말을 할 수 있으며 그런 다음 유효성 검사에서는 데이터베이스의 현실이 아닌 이 거짓말에 대해 유효성을 검사합니다.
Aurabase는 성능을 위해 짧은 30초 캐시를 사용하여 각 호출에서 실제 프로젝트 기본 스키마를 검사하고 요청 본문에 전송된 모든 schema, allowed_schema또는 schema_context 필드를 수락한 다음 자동으로 덮어쓰는 대신 명시적으로 거부(400 오류)합니다. 차이점은 중요합니다. 승인된 후 무시된 필드는 존재하지 않는 제어라는 환상을 제공합니다. 거부된 필드는 즉시 이를 말합니다.
프로덕션 전에 자체 NL2SQL 파이프라인을 감사하세요.
Aurabase를 사용하든 일반 LLM을 기반으로 자체 파이프라인을 구축하든 다음 사항은 가장 흔히 놓치는 사항을 다룹니다.
유효성 검사기를 직접 작성하는 경우
- 문자열의 패턴 일치를 사용하지 않고 정확한 방언을 위해 실제 파서로 SQL을 구문 분석합니다.
- 기본 거부를 채택합니다. 이미 식별된 위험한 사례뿐만 아니라 모든 유형의 노드, 명시적으로 승인되지 않은 모든 기능을 거부해야 합니다.
- 쿼리당 하나의 문만 허용합니다. 이는 쿼리 누적에 대한 가장 간단한 거부입니다.
- 명백한 경우뿐만 아니라 실제 적대적인 경우(FILTER, 집계 내 ORDER BY, OFFSET에서 금지된 기능)로 유효성 검사기를 테스트합니다.
- 모든 것에도 불구하고 예상 스키마에 대한 제한된 권한으로 Postgres 역할을 사용하여 검증된 SQL을 실행하십시오. 검증기는 쿼리 형식을 제한하고 역할은 사례가 탈출한 경우 물리적으로 달성할 수 있는 것을 제한합니다.
타사 NL2SQL 프레임워크를 평가하는 경우
- 유효성 검사가 구조적(AST)인지 아니면 프롬프트 지침인지 명시적으로 물어보세요. 대답이 모든 것을 바꿉니다.
- 귀하의 비용을 들여 모범 사례로 문서화되었을 뿐만 아니라 기본적으로 라인 한도가 적용되었는지 확인하십시오.
- 유효성 검사에 사용되는 스키마가 API 클라이언트에서 제공될 수 있는지 확인하세요. 그러면 위에서 설명한 결함이 정확히 다시 열릴 수 있습니다.
- 선택하기 전에 이 특정 기준에 대한 여러 도구를 비교하십시오. NL2SQL 도구 비교에서는 2026년에 사용할 수 있는 접근 방식의 차이점을 자세히 설명합니다.
검증인은 위험을 줄이지만 RLS를 대체하지는 않습니다.
견고한 AST 유효성 검사기는 소스의 위험을 줄여줍니다. 데이터베이스에 도달하는 SQL에는 이미 알려지고 제한된 형식이 있습니다. 그러나 특정 사용자가 볼 권한이 있는 행을 결정하는 중요한 테이블의 RLS 정책을 대체하지는 않습니다. 두 계층은 서로 다른 질문에 대답합니다. 유효성 검사기는 생성된 쿼리의 형식을 제한하고 RLS는 특정 사용자에 대해 반환할 수 있는 데이터를 제한합니다. 하나가 다른 하나와 중복되는 것처럼 보이더라도 둘 다 활성 상태로 유지하십시오.
NL2SQL covers structured questions about your tables. For questions about unstructured content, documents, notes, tickets, Aurabase's native RAG follows a comparable security logic, detailed in our RAG pipeline tutorial on pgvector.