..

TIL 0903

[TOC]

SQL 인젝션 (SQL Injection)

정의

SQL 인젝션악의적인 SQL 코드를 애플리케이션의 입력 필드에 삽입하여 데이터베이스를 비정상적으로 조작하는 기법이다.

예를 들어 로그인 폼에서 다음과 같은 SQL 쿼리가 사용된다고 생각해보자.

SELECT * FROM users WHERE username = '[입력값1]' AND password = '[입력값2]'

입력된 사용자 이름과 비밀번호가 모두 일치하는 사용자 정보를 데이터베이스에서 찾아오는 쿼리이다.

이때, 공격자가 username 필드에 'admin' -- 를 입력하면 쿼리가 다음과 같이 변경된다.

SELECT * FROM users WHERE username = 'admin' -- ' AND password = '[입력값2]'

SQL에서 -- 이후의 내용은 모두 주석처리되므로, AND password = '[입력값2]' 부분이 주석처리 되어 무시된다. 따라서 이 쿼리는 비밀번호 확인 없이 admin 사용자의 모든 정보를 반환하게 된다. 즉, 비밀번호 입력 없이 관리자 계정에 접근할 수 있게 되는 것이다.

이러한 경우를 SQL 인젝션이라고 하며, 웹 어플리케이션의 보안 취약점을 이용한 공격 기법이다. 이 공격은 데이터베이스와 상호작용하는 애플리케이션에서 주로 발생한다.

작동 방식

  1. 공격자가 웹 폼이나 URL 파라미터 등의 입력란에 SQL 구문을 포함한 데이터를 입력한다.
  2. 애플리케이션이 이 입력을 적절히 필터링 하지 않고 SQL 쿼리에 그대로 포함시킨다.
  3. 결과적으로 공격자가 의도한 SQL 명령이 데이터베이스에서 실행된다.

위험성

  • 민감한 정보를 무단으로 조회할 수 있다.
  • 데이터베이스의 정보를 변경하거나 삭제할 수 있다.
  • 로그인 과정을 무력화하여 무단 접근할 수 있다.
  • DBMS 파일 시스템에 있는 주어진 파일의 내용을 복구하고 경우에 따라 운영체제에 명령을 내린다.

가장 일반적인 취약점의 원형 차트: SQL 주입은 취약점의 50%를 담당하고, 크로스 사이트 스크립팅은 취약점의 42%를 담당하고, 소스 코드 공개는 취약점의 7%를 담당합니다

많은 데이터 침해가 주로 SQL 인젝션에 의해 발생한다. (출처: MDN Web Docs 용어 사전: 웹 용어 정의)

  • SQL 인젝션은 PHP 및 ASP 클래식 응용 프로그램에서 매우 일반적이다. 반면 J2EE나 ASP.NET 응용 프로그램은 SQL 삽입이 보다 어렵다.
    • PHP와 ASP 언어는 초기에 보안 기능이 상대적으로 부족했고, 개발자들이 직접 SQL 쿼리를 작성하는 경우가 많았다. 따라서 초기에는 SQL 인젝션 취약점이 더욱 흔했다.
    • J2EE와 ASP.NET은 처음부터 보안을 고려하여 설계되었고, SQL 인젝션을 방지하는 기능들을 내장하고 있다.
    • 다만 현재 PHP와 ASP도 많은 보안 기능을 추가하여 SQL 인젝션 방지가 쉬워진 편이다. 모든 언어와 프레임워크는 시간이 지남에 따라 보안 측면에서 개선되기 마련이다.
    • 대부분의 현대적인 웹 개발 프레임워크는 SQL 인젝션을 방지하는 기능을 제공하고 있다!

방어 방법

  • 모든 사용자 입력을 철저히 검증한다.
  • 준비된 구문(Prepared Statements)를 사용하여 SQL 쿼리와 데이터를 분리하여 처리한다.
  • 미리 정의된 데이터베이스 프로시저를 사용한다.
  • 데이터베이스 사용자에게 필요한 최소한의 권한만 부여한다.

더 읽어보기


직렬화 (Serialization)

정의

직렬화(Serialization), 또는 시리얼라이제이션이란 객체나 데이터 구조를 저장하거나 전송할 수 있고, 나중에 재구성할 수 있는 형태로 변환하는 과정이다. 반대 과정인 역직렬화(Deserialization), 또는 디시리얼라이제이션은 직렬화된 데이터를 다시 원래의 개체나 데이터 구조로 변환하는 것을 말한다.

용도

  1. 데이터 저장 및 전송
  2. 상태 유지
  3. 데이터 포맷
  4. 언어 간 호환성

언어별 직렬화

  • Python
    • pickle 모듈을 사용한 바이너리 직렬화
    • json 모듈을 사용한 JSON 직렬화
  • JavaScript
    • JSON.stringify()JSON.parse() 메서드를 사용한 JSON 직렬화와 역직렬화
  • C#
    • System.Runtime.Serialization 네임 스페이스를 사용한 직렬화
  • 기타 등등…

각 언어마다 직렬화를 구현하는 방식이나 사용하는 라이브러리는 다를 수 있지만, 기본 개념은 동일하다. 언어에 상관없이 사용할 수 있는 범용적인 직렬화 형식들도 있다.

  • JSON (JavaScript Object Notation) - 거의 모든 프로그래밍 언어에서 지원
  • XML (eXtenstible Markup Language) - 구조화 된 데이터를 표현하는데 사용
  • Protocol Buffers - Google에서 개발한 직렬화 포맷
  • MessagePack - 이진 형식의 직렬화 포맷

내 강아지 렉스는 데이터로 직렬화되고, 그 데이터는 1과 0으로 더 전송됩니다.

직렬화란 무언가(예: 강아지 렉스)를 일련의 0과 1로 변환하는 것이에요. 이를 통해 운반 / 저장 등을 할 수 있습니다. 그러면 해외에 있는 제 친구들은 그 0과 1을 다시 완전한 강아지로 변환할 수 있는 것이죠(비직렬화). 여러분, 이건 비유입니다. 저는 여러분이 실제로 강아지를 (아직은)직렬화 할 수 있다고 생각하지 않아요. 실제로는 데이터 구조나 다른 복잡한 객체를 직렬화 할 것입니다.

필요성

직렬화가 필요하게 된 배경과 현재 사용되는 이유에 대해 조금 더 찾아보았다.

  1. 데이터 저장과 전송

컴퓨터 메모리 상의 데이터는 복잡한 구조를 가질 수 있다. 이것을 파일이나 데이터베이스에 저장하거나 네트워크로 전송하거나 하려면 일련의 바이트 스트림으로 변환해야 하는데, 직렬화는 이런 변환을 표준화 된 방식으로 수행해준다.

  1. OOP(객체 지향 프로그래밍)의 발전

OOP가 널리 사용되면서, 객체의 상태를 저장하고 복원하는 기능이 필요해졌다. 직렬화는 객체의 전체 상태(필드 값들)를 저장하고 나중에 정확히 복원할 수 있게 해준다.

  1. 분산 시스템과 네트워크 통신

여러 컴퓨터나 프로세스끼리 데이터를 주고 받을 때는 데이터를 표준화된 형식으로 변환해야 한다. 직렬화는 이기종 시스템 간의 데이터 교환을 가능하게 한다.

  1. 캐싱과 생능 최적화

복잡한 객체를 생성할 때 시간이 많이 걸리는 경우, 이를 직렬화하여 저장해두면 다음에 빠르게 로드할 수 있다. 데이터베이스 쿼리 결과 등을 캐싱할 때도 직렬화가 사용된다.

  1. 상태 유지와 복구

게임을 할 때(예를 들어 스타듀밸리) 프로그램의 현재 상태를 저장하고 나중에 복원할 수 있어야 함은 당연하다. 이런저런 사건(시스템 장애라거나) 발생 시 복구를 위해 중요한 데이터의 상태를 주기적으로 저장할 때 직렬화가 사용된다.

  1. 버전 관리와 역호환성

소프트웨어가 업데이트 되더라도 이전에 저장된 데이터를 읽을 수 있어야 한다. 직렬화 메커니즘은 데이터 버전 관리와 역호환성을 지원한다.

  1. 보안과 암호화

민감한 데이터를 저장하거나 전송할 때 직렬화 된 데이터를 쉽게 암호화 할 수 있다.

  1. 웹 서비스와 API

REST API나 SOAP 웹 서비스에서 데이터를 주고받을 때 JSON이나 XML 형식으로 직렬화 한다.

  1. 마이크로서비스 아키텍처

여러 독립적인 서비스 간의 통신에서 데이터를 교환할 때 표준화된 형식이 필요하다.

  1. 빅데이터와 데이터 분석

대량의 데이터를 효율적으로 저장하고 처리하기 위한 직렬화 형식(예: Avro, Parquet)도 있다!

예시

import json

# 직렬화
data = {
    "name": "John",
    "age": 30,
    "city": "New York"
}
serialized = json.dumps(data)
print(serialized)
# 출력: {"name": "John", "age": 30, "city": "New York"}

# 역직렬화
deserialized = json.loads(serialized)
print(deserialized['name'])  # 출력: John

더 읽어보기


직렬화의 보안 취약점

직렬화는 데이터 전송과 저장에서 편리한 기능이지만 역직렬화 과정에서 보안 위협에 취약하다. 주로 신뢰할 수 없는 데이터가 역직렬화 될 때 발생하며, 공격자는 원격 코드 실행, 서비스 거부(DOS)공격, 정보 유출 등을 일으킬 수 있다.

주요 원인

  • 불신 데이터 역직렬화 역직렬화된 데이터는 객체를 복원하는 과정에서 임의의 코드를 실행할 수 있다. 공격자는 이를 이용하여 악성 데이터를 주입해 코드 실행을 유도하기도 한다.1 2

  • Java와 .NET의 취약점 Java의 Serializable 인터페이스나 .NET의 BinaryFormatter가 잘못된 역직렬화를 통해 코드 실행을 유발할 수 있다.3

방어 방법

  • 역직렬화 필터링 Java의 경우 역직렬화 할 클래스와 객체의 타입을 제어할 수 있는 직렬화 필터를 사용하는 것이 권장된다. 이를 통해 허용된 클래스만 역직렬화하도록 제한할 수 있다.
  • 안전한 대안 .NET에서는 BinaryFormatter 대신 XmlSerializer, DataContractSerializer 등 안전한 대안을 사용하는 것이 좋다.
  • 최신 보안 패치 적용 최신 보안 업데이트와 패치를 적용하는 것이 필수적이다.