파이썬은 간결하고 생산성이 높아 백엔드, 데이터 분석, 자동화 등 다양한 분야에서 널리 사용됩니다. 하지만 그만큼 보안에 취약할 가능성도 많습니다.
이번 포스팅에서는 Python 개발자들이 실무에서 자주 놓치는 보안 취약점 5가지를 집중 분석하고, 각 취약점의 안전한 대응 방법을 함께 살펴보겠습니다. 또한 Python 기반 웹 프레임워크인 Flask와 Django에서 안전하게 요청을 처리하기 위한 실무 시큐어코딩 패턴도 함께 소개합니다.
취약점만 알면 막을 수 있습니다. Python 코드를 안전하게 작성하고 싶은 분들이라면 끝까지 읽어보세요.
📌 바로가기 목차

1. 파이썬 보안 취약점 TOP 5
파이썬은 동적 언어인 만큼, 입력 검증이 느슨하거나 잘못된 함수 사용 시 심각한 보안 문제가 발생할 수 있습니다. 여기서는 실무에서 가장 자주 발생하는 보안 취약점 5가지를 소개합니다.
- eval() 함수의 오용
외부 입력을 eval()로 처리하면 코드 실행 위험이 발생합니다. 사용자 입력을 절대 eval에 직접 전달하지 마세요. - 하드코딩된 비밀번호 및 토큰
GitHub에 실수로 업로드된 키 하나로 전체 서버가 뚫릴 수 있습니다. 환경변수를 통해 관리하고 .env 파일은 절대 공개하지 않아야 합니다. - 임의 파일 접근 – open(), os.path
사용자 입력을 기반으로 파일을 여는 경우 디렉터리 탈출(Path Traversal) 공격이 가능합니다. - Pickle 모듈 역직렬화
pickle은 매우 위험한 모듈로, 악의적 객체를 역직렬화하면 임의 코드 실행이 가능합니다. 데이터 저장은 JSON 등 안전한 포맷을 사용하세요. - 입력값 검증 누락 (XSS, SQL Injection)
웹 개발 시 form 데이터나 쿼리 파라미터에 대한 검증이 없다면 크로스사이트 스크립팅(XSS)이나 SQL Injection이 발생할 수 있습니다.
위 취약점들은 단 하나만으로도 전체 시스템을 위험에 빠뜨릴 수 있습니다. 따라서 초기 설계 단계부터 시큐어코딩 원칙을 적용해야 합니다.
2. Flask & Django 요청 처리 보안 패턴
웹 프레임워크를 사용할 때 가장 기본이 되는 것은 요청(Request)을 어떻게 안전하게 처리하느냐입니다. 아래는 Flask와 Django에서 반드시 지켜야 할 보안 코딩 패턴입니다.
1) Flask 시큐어코딩 패턴
- CSRF 보호: Flask-WTF 사용 +
{{ form.csrf_token }}템플릿 삽입 필수 - 입력 검증:
request.form,request.args에 대한 정규식 또는 스키마 검증 - 파일 업로드 제한: MIME 타입, 확장자, 용량 제한 +
werkzeug.utils.secure_filename()사용 - 헤더 보안 강화:
Flask-Talisman으로 CSP, HSTS 설정
2) Django 시큐어코딩 패턴
- XSS 방지: 템플릿 자동 escape 기능 유지,
|safe남용 금지 - SQL Injection 방지: ORM(QuerySet) 사용으로 대부분 방지되지만
raw()사용 시 변수 바인딩 필수 - CSRF 토큰:
{% csrf_token %}미삽입 시 요청 차단됨 (기본 보장) - 보안 설정:
SECURE_BROWSER_XSS_FILTER,SECURE_HSTS_SECONDS,SESSION_COOKIE_SECURE설정 권장
Flask는 기본적으로 보안 설정이 약하므로 별도 모듈 추가가 필요하며, Django는 보안 기능이 기본 내장돼 있지만 설정을 잘못하면 취약해질 수 있습니다.
3. 취약 코드 vs 안전한 코드 예제
이제 실제 코드에서 어떤 차이가 보안 취약점이 되고, 어떻게 개선할 수 있는지를 확인해보겠습니다. 아래는 eval() 사용과 Flask 파일 업로드 예제입니다.
[예제 1] eval() 사용 – 취약한 코드
user_input = input("수식을 입력하세요: ")
result = eval(user_input) # 매우 위험
print(result)
→ 안전한 코드
import ast
user_input = input("수식을 입력하세요: ")
try:
node = ast.parse(user_input, mode='eval')
if all(isinstance(n, (ast.Expression, ast.BinOp, ast.Num)) for n in ast.walk(node)):
result = eval(compile(node, '', mode='eval'))
print(result)
else:
print("허용되지 않은 연산입니다.")
except:
print("잘못된 입력입니다.")
[예제 2] Flask 파일 업로드 – 취약한 코드
@app.route('/upload', methods=['POST'])
def upload():
f = request.files['file']
f.save('uploads/' + f.filename) # 파일 이름 검증 없음
→ 안전한 코드
from werkzeug.utils import secure_filename
import os
ALLOWED_EXTENSIONS = {'png', 'jpg', 'pdf'}
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/upload', methods=['POST'])
def upload():
f = request.files['file']
if f and allowed_file(f.filename):
filename = secure_filename(f.filename)
f.save(os.path.join('uploads', filename))
return '업로드 완료'
return '허용되지 않은 파일입니다.'
4. 자주 묻는 질문 (FAQ)
가능하면 수식 파서 라이브러리(ast, numexpr 등)를 사용하는 것이 안전합니다. 특히 외부 입력에 대해선 절대 eval을 직접 쓰지 않아야 합니다.
네, Django는 보안 기능이 기본 내장되어 있지만 설정을 잘못하면 의미가 없습니다. CSRF 토큰, SQL Injection 방어, 세션 보안 설정 등을 반드시 유지해야 합니다.
Flask는 매우 가볍고 유연한 구조지만 보안 설정이 기본으로 적용되지 않기 때문에, Flask-WTF, Flask-Talisman 같은 보안 모듈을 함께 사용하는 것이 좋습니다.
5. 마무리
Python으로 빠르게 코드를 만들 수 있다는 장점은, 보안상 허점을 만들기도 쉽다는 뜻이기도 합니다. 이번 포스팅을 통해 eval, pickle, 입력 검증 같은 요소에서 실무 보안 사고를 방지할 수 있기를 바랍니다.
'시큐어코딩 > Python' 카테고리의 다른 글
| [시큐어코딩]XSS(크로스사이트 스크립팅) 방어 패턴과 Django의 보안 미들웨어 설정법 (1) | 2025.04.21 |
|---|---|
| [시큐어코딩]파이썬 웹개발자가 반드시 알아야 할 SQL Injection 대응법 (0) | 2025.04.21 |