메뉴 닫기

파이썬 문자열 처리 ast.literal_eval로 dict와 tuple 안전하게 파싱하는 방법

파이썬 문자열 처리 ast.literal_eval로 dict와 tuple 안전하게 파싱하는 방법

🐍 사용자 입력을 안전하게 처리하는 파이썬 문자열 파싱 핵심 가이드

코드를 작성하다 보면 사용자로부터 문자열 형태의 데이터를 입력받아 처리해야 하는 경우가 많습니다.
특히 딕셔너리(dict)나 튜플(tuple) 같은 구조화된 데이터를 직접 문자열로 입력받아야 하는 상황이라면, 이를 적절히 파싱하지 못하면 에러는 물론 보안 취약점까지 발생할 수 있습니다.
많은 초보자들이 eval 함수를 사용하려다 위험성을 경험하기도 하는데, 이는 악의적인 코드 실행을 유발할 수 있기 때문에 반드시 피해야 할 방법입니다.
이럴 때 안전하고 효율적으로 사용할 수 있는 것이 바로 ast.literal_eval입니다.

이 글에서는 파이썬에서 제공하는 ast.literal_eval을 활용해 문자열로 전달된 dict, tuple 등을 안전하게 파싱하는 방법을 다룹니다.
실제 사용 예제와 함께 eval과의 차이점, 주의해야 할 점까지 하나씩 살펴보면서, 문자열 파싱 작업을 보다 안전하게 수행할 수 있도록 안내할 예정입니다.
개발 현장에서 바로 적용할 수 있는 실용적인 정보이니 끝까지 읽어보시면 큰 도움이 될 것입니다.



🔗 파이썬 문자열 처리의 기본 이해

파이썬에서 문자열은 단순히 글자를 나열하는 자료형을 넘어, 다양한 데이터 표현에 활용되는 중요한 도구입니다.
특히 JSON과 같은 구조화된 데이터를 주고받거나, 사용자가 입력한 값을 프로그램에서 처리할 때 문자열 파싱이 핵심 역할을 합니다.
예를 들어 사용자가 “{‘name’: ‘Tom’, ‘age’: 25}”와 같은 문자열을 입력했다면, 이를 단순한 텍스트가 아니라 실제 딕셔너리 형태로 변환해야 유용하게 활용할 수 있습니다.

이 과정에서 흔히 쓰이는 방법이 eval 또는 ast.literal_eval과 같은 내장 기능입니다.
하지만 두 함수는 비슷해 보이더라도 동작 방식과 보안 측면에서 큰 차이가 있습니다.
단순히 문자열을 실행시키는 것이 아니라, 안전하게 파싱할 수 있는 방법을 이해하는 것이 파이썬 개발에서 매우 중요합니다.

📌 문자열과 자료형 변환의 필요성

사용자로부터 입력받는 데이터는 기본적으로 문자열 형태입니다.
따라서 숫자, 리스트, 딕셔너리처럼 실제 로직에 필요한 자료형으로 바꿔야 의미 있게 사용할 수 있습니다.
예를 들어 “123”이라는 문자열은 연산이 불가능하지만, 정수형 123으로 변환하면 수학적 계산에 활용할 수 있습니다.
마찬가지로 “{‘a’: 1, ‘b’: 2}”라는 문자열도 딕셔너리 객체로 변환해야 키-값 조회나 수정이 가능합니다.

🔎 JSON과의 차이

많은 사람들이 문자열 파싱을 이야기할 때 JSON을 먼저 떠올리지만, JSON은 엄밀히 말하면 JavaScript Object Notation 형식으로 제한된 문법을 따릅니다.
반면 파이썬에서는 JSON 형식뿐 아니라 튜플, 집합, 심지어 파이썬 스타일의 딕셔너리 표현까지 문자열로 다룰 수 있습니다.
따라서 JSON 파서를 쓰는 것보다 ast.literal_eval을 이용하면 더 다양한 상황을 처리할 수 있는 장점이 있습니다.

CODE BLOCK
# 문자열을 그대로 출력하면 단순 텍스트
data = "{'x': 10, 'y': 20}"
print(data)  
# 결과: {'x': 10, 'y': 20}

# 실제 딕셔너리로 변환해야 유용하게 사용 가능
import ast
parsed = ast.literal_eval(data)
print(parsed['x'] + parsed['y'])  
# 결과: 30

위 예제처럼 문자열을 자료형으로 변환하는 것은 파이썬 프로그래밍에서 흔히 필요한 작업이며, 특히 사용자 입력이나 파일에서 데이터를 불러올 때 자주 마주치게 됩니다.
따라서 본격적으로 안전한 방법을 배우기 전에 문자열 처리의 기본 개념을 확실히 이해하는 것이 중요합니다.

🛠️ eval 함수와 보안 문제

파이썬을 처음 배우는 사람들이 문자열을 코드처럼 실행하기 위해 가장 쉽게 접하는 방법은 eval 함수입니다.
이 함수는 문자열을 받아서 실제 파이썬 코드처럼 실행하는 기능을 제공하는데, 겉보기에는 편리해 보이지만 보안상 심각한 위험을 내포하고 있습니다.
만약 사용자가 입력한 값이 악의적인 코드라면, eval은 그것을 그대로 실행해 버리기 때문에 프로그램 전체가 공격에 노출될 수 있습니다.

예를 들어 누군가 “{‘a’: 1, ‘b’: 2}” 같은 정상적인 입력 대신, 시스템 명령어를 포함한 문자열을 넣을 수 있습니다.
이 경우 eval은 단순 파싱을 넘어 실제 명령을 실행하기 때문에 치명적인 결과로 이어질 수 있습니다.
따라서 공식 문서에서도 eval은 절대로 사용자 입력을 직접 처리하는 용도로 쓰지 말 것을 강력히 경고하고 있습니다.

⚠️ eval이 위험한 이유

eval은 단순히 수학 계산이나 자료형 변환을 넘어서, 문자열을 코드로 실행합니다.
즉, 사용자가 의도적으로 시스템 함수를 호출하거나, 외부 리소스에 접근하거나, 파일을 조작하는 명령어를 입력하면 그대로 실행됩니다.
이는 곧 보안 취약점으로 이어지며, 실무 환경에서는 특히 위험합니다.

CODE BLOCK
# 위험한 eval 사용 예시
user_input = user_input = "__import__('os').system('rm -rf /')"
eval(user_input)  # 실제로 시스템 명령어 실행 가능! 절대 금지

⚠️ 주의: eval은 사용자 입력을 그대로 실행하기 때문에 보안 취약점의 원인이 됩니다. 절대 신뢰할 수 없는 데이터에 사용해서는 안 됩니다.

이처럼 eval은 학습 과정에서 일시적으로 사용되는 경우를 제외하면 실제 서비스 코드에 포함되는 것은 매우 위험합니다.
따라서 안전하게 문자열을 파싱하고 싶다면, eval 대신 ast.literal_eval 같은 안전한 대안을 반드시 선택해야 합니다.



⚙️ ast.literal_eval의 특징과 장점

파이썬의 ast.literal_eval 함수는 문자열을 안전하게 파이썬 객체로 변환할 수 있는 기능을 제공합니다.
eval과 달리 코드 실행을 허용하지 않고, 파이썬의 리터럴(literal)만 평가합니다.
즉, 문자열, 숫자, 리스트, 딕셔너리, 튜플 등과 같은 기본 자료형은 문제없이 변환할 수 있지만, 함수 호출이나 시스템 명령어 같은 실행은 차단됩니다.

이러한 특성 덕분에 사용자 입력을 받아서 안전하게 딕셔너리나 튜플을 파싱할 때 가장 추천되는 방법이 바로 ast.literal_eval입니다.
실제로 파이썬 공식 문서에서도 eval의 위험성을 언급하며, 안전한 대안으로 literal_eval을 권장하고 있습니다.

🔒 literal_eval이 안전한 이유

literal_eval은 내부적으로 추상 구문 트리(AST, Abstract Syntax Tree)를 분석하여, 허용된 자료형만 변환합니다.
따라서 코드 실행 명령어나 위험한 함수 호출은 아예 지원하지 않으므로 보안적인 측면에서 훨씬 안전합니다.
이는 단순 문자열 평가가 아니라, ‘리터럴 데이터’만 허용하는 제한적 기능이기 때문에 가능한 것입니다.

  • 🛠️문자열, 숫자, 리스트, 튜플, 딕셔너리, 집합 등의 기본 자료형 지원
  • ⚙️함수 호출이나 모듈 임포트 같은 실행 불가
  • 🔌보안성을 유지하면서도 직관적인 사용 가능
CODE BLOCK
import ast

data = "{'name': 'Alice', 'age': 30}"
safe_parsed = ast.literal_eval(data)
print(safe_parsed)
# 결과: {'name': 'Alice', 'age': 30}

# 함수 호출을 포함한 문자열은 예외 발생
malicious = malicious = "__import__('os').system('echo hack')"
ast.literal_eval(malicious)  # ValueError 발생

이처럼 literal_eval은 eval과 달리 실행 가능한 코드를 거부하고, 안전한 데이터만 허용합니다.
따라서 사용자 입력을 처리할 때 가장 적합한 선택이며, 특히 웹 서비스나 API 개발 환경에서는 반드시 활용해야 할 함수입니다.

🔌 dict와 tuple 파싱 실전 예제

이제 실제로 ast.literal_eval을 활용해 문자열로 전달된 dict와 tuple을 안전하게 파싱하는 방법을 살펴보겠습니다.
실습 예제를 통해 eval을 대체하면서도 보안성을 유지하는 방법을 구체적으로 이해할 수 있습니다.

📌 dict 문자열 파싱

딕셔너리 형태의 문자열은 사용자 입력이나 설정 파일에서 자주 볼 수 있습니다.
이를 안전하게 변환하려면 literal_eval을 사용하면 됩니다.

CODE BLOCK
import ast

data_dict = "{'id': 101, 'title': 'Python Guide'}"
parsed_dict = ast.literal_eval(data_dict)
print(parsed_dict['title'])
# 결과: Python Guide

📌 tuple 문자열 파싱

튜플은 리스트와 비슷하지만 불변성을 가진다는 특징이 있습니다.
문자열로 입력된 튜플 역시 literal_eval을 사용해 안전하게 변환할 수 있습니다.

CODE BLOCK
import ast

data_tuple = "(10, 20, 30)"
parsed_tuple = ast.literal_eval(data_tuple)
print(sum(parsed_tuple))
# 결과: 60

💡 실무 활용 팁

실제 서비스에서는 사용자 입력이 단순하지 않고, 딕셔너리 안에 리스트가 중첩되거나 튜플 안에 여러 타입이 섞여 있는 경우도 많습니다.
이때도 literal_eval은 모든 기본 리터럴 구조를 안정적으로 파싱할 수 있기 때문에, 데이터를 다루는 로직을 단순화할 수 있습니다.

💡 TIP: JSON 형태와 달리 파이썬 스타일의 dict, tuple까지 파싱 가능하다는 점은 literal_eval의 가장 큰 장점 중 하나입니다.

즉, literal_eval은 eval의 보안 문제를 해결하면서도 다양한 파이썬 자료형을 유연하게 변환할 수 있는 강력한 도구입니다.
실전에서 dict와 tuple을 다루는 경우라면 반드시 이 함수를 활용하는 것이 좋습니다.



💡 사용 시 주의할 점과 한계

ast.literal_eval은 eval보다 훨씬 안전하지만, 무조건 만능 도구는 아닙니다.
기본적인 리터럴만 허용하기 때문에 복잡한 객체나 사용자 정의 클래스는 변환할 수 없습니다.
또한 입력 데이터의 형식이 올바르지 않다면 ValueErrorSyntaxError가 발생하기 때문에 예외 처리를 반드시 고려해야 합니다.

실제로 서비스 환경에서 사용자 입력은 언제나 불완전할 수 있다는 점을 전제로 해야 합니다.
따라서 literal_eval을 사용할 때도 try-except 구문을 활용해 안전망을 두는 것이 중요합니다.

⚠️ 예외 처리의 필요성

사용자가 입력한 문자열이 올바른 파이썬 리터럴 형식이 아닐 경우, literal_eval은 예외를 발생시킵니다.
따라서 이를 적절히 처리하지 않으면 프로그램이 중단될 수 있습니다.
아래 예시처럼 반드시 예외 처리를 포함하는 습관을 들이는 것이 바람직합니다.

CODE BLOCK
import ast

user_input = "{'a':1, 'b':2"  # 닫는 괄호가 없음
try:
    result = ast.literal_eval(user_input)
    print(result)
except (ValueError, SyntaxError):
    print("올바르지 않은 입력입니다.")

🔎 literal_eval의 한계

literal_eval은 단순 자료형 변환에는 탁월하지만, JSON처럼 다른 언어와 호환되는 데이터 구조를 다루기에는 제한이 있습니다.
예를 들어 true, false, null 같은 JSON 키워드는 파이썬과 문법이 달라 literal_eval에서 바로 사용할 수 없습니다.
이 경우에는 json.loads() 같은 별도의 파서를 함께 사용하는 것이 좋습니다.

💬 실무에서는 데이터 입력 형태가 다양하기 때문에, 상황에 따라 literal_eval과 json 모듈을 적절히 병행하는 것이 가장 안전하고 효율적입니다.

즉, literal_eval은 eval의 보안 문제를 해결하면서도 기본 자료형 변환을 안전하게 처리할 수 있는 훌륭한 도구입니다.
하지만 그 한계를 정확히 알고, 필요할 때는 다른 파서와 함께 사용해야 안정적인 프로그램을 구축할 수 있습니다.

자주 묻는 질문 (FAQ)

ast.literal_eval은 어떤 경우에 가장 유용한가요?
문자열로 표현된 dict, list, tuple 같은 기본 자료형을 안전하게 파싱해야 할 때 가장 유용합니다. 특히 사용자 입력을 처리할 때 보안성을 유지하면서 변환할 수 있습니다.
eval과 literal_eval의 가장 큰 차이는 무엇인가요?
eval은 문자열을 코드처럼 실행해 보안에 취약하지만, literal_eval은 리터럴 데이터만 허용해 안전합니다. 즉, 함수 호출이나 시스템 명령은 literal_eval에서 실행되지 않습니다.
literal_eval로 JSON 데이터를 바로 처리할 수 있나요?
일부 파이썬 스타일 JSON은 처리 가능하지만, true, false, null 같은 JSON 전용 문법은 에러가 발생합니다. 이 경우 json.loads()를 사용하는 것이 더 적절합니다.
literal_eval은 모든 데이터 타입을 지원하나요?
아닙니다. 문자열, 숫자, 리스트, 튜플, 딕셔너리, 집합 등 기본 리터럴만 지원합니다. 사용자 정의 클래스나 함수 객체는 변환할 수 없습니다.
잘못된 입력을 넣으면 어떻게 되나요?
구문 오류가 있거나 지원하지 않는 타입일 경우 ValueError 또는 SyntaxError가 발생합니다. 따라서 try-except 구문으로 예외 처리를 해주는 것이 안전합니다.
literal_eval은 속도가 빠른 편인가요?
보안 검증 과정을 거치기 때문에 eval보다는 느리지만, 대부분의 상황에서는 충분히 빠릅니다. 대규모 JSON 파싱보다는 안정성이 중요한 경우에 적합합니다.
웹 개발에서 literal_eval을 자주 쓰나요?
네, 특히 API나 폼 입력에서 문자열을 객체로 변환할 때 종종 활용됩니다. 다만 JSON 형식의 데이터 교환이 일반적이므로, literal_eval은 특정 상황에서만 사용됩니다.
eval 대신 literal_eval을 항상 사용하면 되나요?
네, 사용자 입력을 파싱하는 상황에서는 반드시 literal_eval을 사용해야 합니다. 단, 모든 경우에 적합한 것은 아니므로 JSON 파싱이 필요한 경우 json 모듈을 함께 고려하는 것이 좋습니다.

📌 파이썬에서 안전한 문자열 파싱 정리

파이썬에서 문자열을 처리할 때 eval은 간단하지만 보안적으로 매우 위험합니다.
따라서 사용자 입력을 안전하게 처리하려면 반드시 ast.literal_eval을 사용하는 것이 좋습니다.
이 함수는 기본 리터럴 데이터만 허용하여 딕셔너리, 튜플, 리스트, 집합 같은 자료형을 안전하게 변환할 수 있습니다.
또한 예외 처리를 통해 잘못된 입력에도 안정적으로 대응할 수 있다는 장점이 있습니다.

실무에서는 JSON 데이터와 혼용되는 경우가 많기 때문에, 상황에 맞춰 literal_eval과 json.loads()를 병행하는 전략이 필요합니다.
즉, 파이썬 내부 표현을 그대로 입력받을 때는 literal_eval을, 외부 시스템과 교환할 때는 JSON 파서를 쓰는 것이 가장 안전하고 효율적인 방법입니다.

이 글을 통해 문자열 파싱의 기본 원리와 보안 문제, literal_eval의 장점과 한계, 그리고 실전 예제까지 살펴보았습니다.
앞으로 사용자 입력 데이터를 다룰 때 eval 대신 literal_eval을 습관적으로 사용한다면, 프로그램의 안전성을 크게 높일 수 있을 것입니다.


🏷️ 관련 태그 : 파이썬문자열, 파이썬eval, astliteral_eval, 파이썬보안, 문자열파싱, dict파싱, tuple파싱, json대비, 파이썬예외처리, 파이썬입력안전