코더의 보안 정복: 공유와 학습 - SQL 인젝션

쉽게 말해 SQL(Structured Query Language)은 관계형 데이터베이스와 통신하기 위한 언어입니다. 개발자, 데이터베이스 관리자, 애플리케이션이 매일 생성되는 방대한 양의 데이터를 관리하기 위해 사용하는 쿼리 언어죠.
데이터는 빠르게 세계에서 가장 가치 있는 자산 중 하나가 되고 있습니다. 가치 있는 것에는 언제나 악의적인 의도를 가진 이들이 탐내기 마련입니다.
공격자들은 1998년부터 존재해 온 가장 오래되고 골치 아픈 데이터 취약점 중 하나인 SQL 인젝션을 사용하여 전 세계 수백만 데이터베이스의 민감한 정보를 탈취하고 변조하고 있습니다. 이는 매우 교묘한 공격이므로, 데이터를 안전하게 보호하려면 개발자가 SQL 인젝션의 원리와 방어 방법을 반드시 이해해야 합니다.
이를 위해 SQL 인젝션의 세 가지 핵심 측면을 살펴보겠습니다.
- 작동 원리
- 위험한 이유
- 방어 방법
SQL 인젝션 이해하기
SQL 인젝션은 '컨텍스트(context)'라는 단어 하나로 이해할 수 있습니다.
애플리케이션 내에는 데이터 컨텍스트와 코드 컨텍스트라는 두 가지 컨텍스트가 존재합니다. 코드 컨텍스트는 컴퓨터에 무엇을 실행할지 지시하며, 처리할 데이터와 코드를 구분합니다.
SQL 인젝션은 공격자가 입력한 데이터가 SQL 인터프리터에 의해 실수로 코드로 처리될 때 발생합니다.
예를 들어 웹사이트의 입력 필드에 공격자가 ‘’’ OR 1=1"을 입력하면, 이 값이 SQL 쿼리 끝에 추가됩니다. 쿼리가 실행되면 데이터베이스의 모든 행에 대해 "참(true)"을 반환하게 되어, 쿼리된 테이블의 모든 레코드가 노출됩니다.
SQL 인젝션의 영향은 치명적일 수 있습니다. 로그인 페이지에서 발생할 경우 사용자 이름과 비밀번호를 포함한 모든 사용자 레코드가 유출될 수 있습니다. 데이터를 추출하는 간단한 쿼리가 성공한다면, 데이터를 변경하는 쿼리 또한 성공할 수 있습니다.
SQL 인젝션 취약점이 실제로 어떤 모습인지 취약한 코드를 통해 살펴보겠습니다.
다음 코드를 확인해 보세요.
String query = "SELECT account balance FROM user_data WHERE user_name = "
+ request.getParameter("customerName");
try {
Statement statement = connection.createStatement( ... );
ResultSet results = statement.executeQuery( query );
}
이 코드는 클라이언트로부터 받은 매개변수 정보를 검증 없이 SQL 쿼리 끝에 단순히 추가합니다. 이 경우 공격자가 입력 필드나 URL 매개변수에 코드를 삽입하면 그대로 실행됩니다.
중요한 점은 공격자가 단순히 SELECT 쿼리에 ‘’’ OR 1=1"을 추가하는 것뿐만 아니라, 모든 유형의 SQL 쿼리(INSERT, UPDATE, DELETE, DROP 등)를 조작하고 데이터베이스가 지원하는 모든 명령으로 확장할 수 있다는 것입니다. 무엇이 가능한지 보여주는 훌륭한 리소스와 도구들이 공개되어 있습니다.

곧 이 문제를 해결하는 방법을 배우겠지만, 우선 이 공격으로 인해 얼마나 큰 피해가 발생할 수 있는지 먼저 알아보겠습니다.
SQL 인젝션이 위험한 이유
SQL 인젝션으로 인해 발생한 보안 사고 사례 3가지를 소개합니다.
- 일리노이주 선거관리위원회 웹사이트는 해킹을 당했습니다. SQL 인젝션 취약점으로 인해 미국 시민 20만 명의 개인정보가 유출되었습니다. 발견된 취약점의 특성상 공격자가 데이터를 변조할 수도 있었으나, 다행히 실제 변조는 일어나지 않았습니다.
- 남아프리카공화국의 웹 호스팅 업체인 헤츠너(Hetzner)는 해킹을 당해 고객 기록 4만 건이 유출되었습니다. SQL 인젝션 취약점으로 인해 데이터베이스 내의 모든 고객 기록이 탈취될 위험에 처했습니다.
- 미국 미네소타주의 한 가톨릭 금융 서비스 제공업체도 해킹을 당했습니다. 이 공격으로 계좌 번호를 포함한 고객 약 13만 명의 계좌 정보가 탈취되었습니다.
민감한 데이터는 계정 탈취, 비밀번호 재설정, 금전 절도 또는 사기 행각에 악용될 수 있습니다.
민감하거나 개인 식별 정보로 간주되지 않는 정보라도 다른 공격의 발판이 될 수 있습니다. 주소 정보나 정부 발급 신분증 번호의 마지막 네 자리는 기업을 상대로 본인을 사칭하거나 비밀번호를 재설정하는 데 사용될 수 있습니다.
공격이 성공하면 기업은 고객의 신뢰를 잃게 됩니다. 시스템 복구 비용이나 규제 당국의 벌금으로 인해 수백만 달러의 손실이 발생할 수 있습니다.
하지만 반드시 이런 결과로 이어져야 하는 것은 아닙니다.
SQL 인젝션 방어하기
SQL 인젝션은 애플리케이션의 각 부분을 명확하게 구분하여 컴퓨터가 특정 부분이 데이터인지 아니면 실행할 코드인지 인식하게 함으로써 방어할 수 있습니다. 이를 위해 매개변수화된 쿼리(parameterized queries)를 사용할 수 있습니다.
SQL 쿼리에 매개변수를 사용하면 SQL 인터프리터는 해당 매개변수를 오직 데이터로만 취급합니다. 코드로 실행하지 않는 것입니다.
예를 들어, ‘’’ OR 1=1"과 같은 공격은 통하지 않습니다. 데이터베이스는 "OR 1=1"이라는 문자열을 찾으려 할 것이고, 데이터베이스 내에 해당 문자열이 없으므로 아무것도 찾지 못할 것입니다. 그저 "죄송합니다. 해당 정보를 찾을 수 없습니다."라고 응답할 뿐입니다.
Java에서 매개변수화된 쿼리를 사용하는 예시는 다음과 같습니다:

대부분의 개발 프레임워크는 SQL 인젝션에 대한 기본 방어 기능을 제공합니다.
.NET 제품군의 Entity Framework와 같은 객체 관계 매퍼(ORM)는 기본적으로 쿼리를 매개변수화합니다. 이를 통해 별도의 추가 작업 없이도 SQL 인젝션을 방어할 수 있습니다.
하지만 사용 중인 ORM의 작동 방식을 정확히 이해해야 합니다. 예를 들어, Java 환경에서 널리 쓰이는 ORM인 Hibernate는 잘못 사용할 경우 여전히 SQL 인젝션에 취약할 수 있습니다.
쿼리 매개변수화는 가장 우선적이고 효과적인 방어 수단이지만, 다른 방법들도 있습니다. 저장 프로시저(Stored Procedures) 역시 SQL 매개변수를 지원하며 SQL 인젝션을 방지하는 데 사용할 수 있습니다. 단, 저장 프로시저가 올바르게 작성되어야만 효과가 있다는 점을 명심하세요.
// 이 부분도 반드시 검증해야 합니다
String custname = request.getParameter("customerName");
// 공격 탐지를 위한 입력값 검증 수행
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";
PreparedStatement pstmt = connection.preparedStatement( query );
pstmt.setString(1, custname);
ResultSet results = pstmt.executeQuery( );
항상 입력값을 검증하고 정화(sanitize)하십시오. "OR 1=1"과 같은 문자열은 일반적인 사용자가 입력할 이유가 없으므로 허용할 필요가 없습니다. 사용자에게 오류 메시지를 표시하거나 처리하기 전에 해당 문자열을 제거할 수 있습니다.
그렇다고 해서 검증과 정화만으로 보호가 충분하다고 생각해서는 안 됩니다. 영리한 공격자들은 이를 우회하는 방법을 찾아냅니다. 이는 훌륭한 심층 방어(Defense in Depth, DiD) 전략이지만, 모든 가능성을 차단하는 확실한 방법은 매개변수화입니다.
또 다른 좋은 심층 방어 전략은 데이터베이스 내에서 '최소 권한' 원칙을 적용하고 입력값 화이트리스트를 사용하는 것입니다. 최소 권한을 적용한다는 것은 애플리케이션이 데이터베이스 내에서 무제한적인 권한을 갖지 않도록 제한하는 것을 의미합니다. 공격자가 침입하더라도 그들이 입힐 수 있는 피해를 최소화할 수 있습니다.
OWASP에서 제공하는 SQL 인젝션 치트 시트를 통해 다양한 언어와 플랫폼에서 이 취약점을 처리하는 방법을 확인할 수 있습니다. 하지만 한 단계 더 나아가고 싶다면, 지금 바로 저희 플랫폼에서 선호하는 언어로 SQL 인젝션 챌린지에 도전해 보세요. 시작하기 좋은 인기 챌린지들을 소개합니다.
여정의 시작
SQL 인젝션에 대한 이해와 이를 해결하기 위한 단계별 과정에서 큰 발전을 이루셨습니다. 정말 대단합니다!
SQL 인젝션이 발생하는 원리에 대해 살펴보았습니다. 일반적으로 공격자가 사용자 입력을 조작하여 데이터베이스 쿼리를 제어하고 악의적인 목적을 달성하는 방식입니다.
또한 SQL 인젝션 취약점 공격으로 인한 피해도 확인했습니다. 계정이 탈취되고 막대한 금전적 손실이 발생할 수 있는, 그야말로 악몽과도 같은 상황입니다.
SQL 인젝션을 방지하는 방법은 다음과 같습니다.
- 쿼리 매개변수화
- 객체 관계 매핑(ORM) 및 저장 프로시저 사용
- 사용자 입력값 검증 및 화이트리스트 적용
이제 여러분의 차례입니다. 실습은 학습과 숙달을 위한 가장 좋은 방법입니다. SQL 인젝션에 관한 학습 리소스를 확인하고, 무료 데모를 체험해 보는 건 어떨까요? Secure Code Warrior가 되기 위한 여정이 시작될 것입니다.
배포 전 AI 기반 개발 거버넌스 확보
AI 기반 위험을 측정하고, 커밋 시점에 보안 코딩 정책을 적용하며, SDLC 전반에 걸쳐 안전한 소프트웨어 제공 속도를 높이세요.
더 많은 블로그 살펴보기
보안 코딩, AI 거버넌스, 소프트웨어 리스크 관리에 관한 전문가 콘텐츠를 확인해 보세요.
%252520%252520(3).avif)
Supercharged Security Awareness: How Tournaments are Inspiring Developers at Erste Group
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Security as culture: How Blue Prism cultivates world-class secure developers
Learn how Blue Prism, the global leader in intelligent automation for the enterprise, used Secure Code Warrior's agile learning platform to create a security-first culture with their developers, achieve their business goals, and ship secure code at speed
배포 전 AI 기반 개발 보안 확보
소프트웨어 개발 수명 주기 전반에서 개발자 리스크를 파악하고, 정책을 시행하며, 취약점을 예방하세요.



.avif)