[파이썬] Psycopg2에서 SQL Injection 방지

SQL Injection은 웹 애플리케이션에서 가장 흔한 보안 취약점 중 하나입니다. 이러한 공격은 사용자로부터 입력받은 데이터를 제대로 검증하지 않고 SQL 쿼리에 직접 삽입하여 악의적인 동작을 수행하는 것을 의미합니다.

파이썬에서 PostgreSQL 데이터베이스를 다룰 때 가장 많이 사용되는 라이브러리인 Psycopg2도 SQL Injection 공격에 취약할 수 있습니다. 하지만, Psycopg2에서는 많은 기능들을 제공하여 SQL Injection을 방지할 수 있습니다.

1. Placeholder 사용하기

가장 효과적인 SQL Injection 방지 방법은 placeholder를 사용하는 것입니다. Psycopg2에서는 %s를 placeholder로 사용합니다.

예를 들어, 다음은 사용자로부터 입력받은 값을 사용하여 SQL 쿼리를 수행하는 코드입니다.

import psycopg2

def get_user(username):
    conn = psycopg2.connect(database="mydb", user="myuser", password="mypassword", host="myhost", port="myport")
    cur = conn.cursor()
    cur.execute(f"SELECT * FROM users WHERE username = '{username}'")
    user = cur.fetchone()
    conn.close()
    return user

위의 코드는 SQL Injection에 취약합니다. 입력된 사용자 이름을 그대로 쿼리에 삽입하므로, 사용자가 악의적인 문자열을 입력하면 예기치 않은 결과가 발생할 수 있습니다.

이를 방지하기 위해 Psycopg2의 placeholder를 사용하여 수정된 코드는 다음과 같습니다.

import psycopg2

def get_user(username):
    conn = psycopg2.connect(database="mydb", user="myuser", password="mypassword", host="myhost", port="myport")
    cur = conn.cursor()
    cur.execute("SELECT * FROM users WHERE username = %s", (username,))
    user = cur.fetchone()
    conn.close()
    return user

위의 코드에서 %s는 placeholder로 사용되며, 이후 튜플 형태로 값을 전달하여 SQL Injection을 방지합니다.

2. SQL 쿼리 파싱하기

때로는 동적으로 생성된 SQL 쿼리가 필요한 상황이 있을 수 있습니다. 이를 처리하기 위해 Psycopg2는 SQL 쿼리를 파싱하는 기능을 제공합니다.

예를 들어 다음과 같이 사용자가 선택한 필드와 값에 따라 동적으로 SQL 쿼리를 생성하는 함수가 있다고 가정해 봅시다.

import psycopg2

def get_user_by_field(field, value):
    conn = psycopg2.connect(database="mydb", user="myuser", password="mypassword", host="myhost", port="myport")
    cur = conn.cursor()
    query = f"SELECT * FROM users WHERE {field} = '{value}'"
    cur.execute(query)
    user = cur.fetchone()
    conn.close()
    return user

위의 코드는 사용자로부터 입력받은 필드와 값으로 직접 SQL 쿼리를 생성합니다. 이는 SQL Injection 공격에 취약합니다.

이를 방지하기 위해 Psycopg2의 SQL 쿼리 파싱 기능을 사용하여 수정된 코드는 다음과 같습니다.

import psycopg2
from psycopg2 import sql

def get_user_by_field(field, value):
    conn = psycopg2.connect(database="mydb", user="myuser", password="mypassword", host="myhost", port="myport")
    cur = conn.cursor()
    query = sql.SQL("SELECT * FROM users WHERE {field} = {value}").format(field=sql.Identifier(field), value=sql.Literal(value))
    cur.execute(query)
    user = cur.fetchone()
    conn.close()
    return user

위의 코드에서 sql.SQL을 사용하여 SQL 쿼리를 생성하고, sql.Identifiersql.Literal을 사용하여 필드와 값이 유효하게 파싱되도록 합니다.

SQL Injection은 심각한 보안 문제이며, Psycopg2를 사용하면서 이러한 취약점에 대비하여 적절한 방어 메커니즘을 구축해야 합니다. Placeholder 사용과 SQL 쿼리 파싱은 Psycopg2에서 쉽게 구현할 수 있는 방법이며, 웹 애플리케이션 등에서 안전한 데이터베이스 처리를 위해 적극적으로 활용해야 합니다.