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 인젝션이라고 하며, 웹 어플리케이션의 보안 취약점을 이용한 공격 기법이다. 이 공격은 데이터베이스와 상호작용하는 애플리케이션에서 주로 발생한다.
작동 방식
- 공격자가 웹 폼이나 URL 파라미터 등의 입력란에 SQL 구문을 포함한 데이터를 입력한다.
- 애플리케이션이 이 입력을 적절히 필터링 하지 않고 SQL 쿼리에 그대로 포함시킨다.
- 결과적으로 공격자가 의도한 SQL 명령이 데이터베이스에서 실행된다.
위험성
- 민감한 정보를 무단으로 조회할 수 있다.
- 데이터베이스의 정보를 변경하거나 삭제할 수 있다.
- 로그인 과정을 무력화하여 무단 접근할 수 있다.
- DBMS 파일 시스템에 있는 주어진 파일의 내용을 복구하고 경우에 따라 운영체제에 명령을 내린다.
많은 데이터 침해가 주로 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), 또는 디시리얼라이제이션은 직렬화된 데이터를 다시 원래의 개체나 데이터 구조로 변환하는 것을 말한다.
용도
- 데이터 저장 및 전송
- 상태 유지
- 데이터 포맷
- 언어 간 호환성
언어별 직렬화
- 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 - 이진 형식의 직렬화 포맷
직렬화란 무언가(예: 강아지 렉스)를 일련의 0과 1로 변환하는 것이에요. 이를 통해 운반 / 저장 등을 할 수 있습니다. 그러면 해외에 있는 제 친구들은 그 0과 1을 다시 완전한 강아지로 변환할 수 있는 것이죠(비직렬화). 여러분, 이건 비유입니다. 저는 여러분이 실제로 강아지를 (아직은)직렬화 할 수 있다고 생각하지 않아요. 실제로는 데이터 구조나 다른 복잡한 객체를 직렬화 할 것입니다.
필요성
직렬화가 필요하게 된 배경과 현재 사용되는 이유에 대해 조금 더 찾아보았다.
- 데이터 저장과 전송
컴퓨터 메모리 상의 데이터는 복잡한 구조를 가질 수 있다. 이것을 파일이나 데이터베이스에 저장하거나 네트워크로 전송하거나 하려면 일련의 바이트 스트림으로 변환해야 하는데, 직렬화는 이런 변환을 표준화 된 방식으로 수행해준다.
- OOP(객체 지향 프로그래밍)의 발전
OOP가 널리 사용되면서, 객체의 상태를 저장하고 복원하는 기능이 필요해졌다. 직렬화는 객체의 전체 상태(필드 값들)를 저장하고 나중에 정확히 복원할 수 있게 해준다.
- 분산 시스템과 네트워크 통신
여러 컴퓨터나 프로세스끼리 데이터를 주고 받을 때는 데이터를 표준화된 형식으로 변환해야 한다. 직렬화는 이기종 시스템 간의 데이터 교환을 가능하게 한다.
- 캐싱과 생능 최적화
복잡한 객체를 생성할 때 시간이 많이 걸리는 경우, 이를 직렬화하여 저장해두면 다음에 빠르게 로드할 수 있다. 데이터베이스 쿼리 결과 등을 캐싱할 때도 직렬화가 사용된다.
- 상태 유지와 복구
게임을 할 때(예를 들어 스타듀밸리) 프로그램의 현재 상태를 저장하고 나중에 복원할 수 있어야 함은 당연하다. 이런저런 사건(시스템 장애라거나) 발생 시 복구를 위해 중요한 데이터의 상태를 주기적으로 저장할 때 직렬화가 사용된다.
- 버전 관리와 역호환성
소프트웨어가 업데이트 되더라도 이전에 저장된 데이터를 읽을 수 있어야 한다. 직렬화 메커니즘은 데이터 버전 관리와 역호환성을 지원한다.
- 보안과 암호화
민감한 데이터를 저장하거나 전송할 때 직렬화 된 데이터를 쉽게 암호화 할 수 있다.
- 웹 서비스와 API
REST API나 SOAP 웹 서비스에서 데이터를 주고받을 때 JSON이나 XML 형식으로 직렬화 한다.
- 마이크로서비스 아키텍처
여러 독립적인 서비스 간의 통신에서 데이터를 교환할 때 표준화된 형식이 필요하다.
- 빅데이터와 데이터 분석
대량의 데이터를 효율적으로 저장하고 처리하기 위한 직렬화 형식(예: 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
등 안전한 대안을 사용하는 것이 좋다. - 최신 보안 패치 적용 최신 보안 업데이트와 패치를 적용하는 것이 필수적이다.