설명
외부에서 제어할 수 있는 텍스트를 Jinja 템플릿 소스로 전달하면 서버사이드 템플릿 인젝션(SSTI)이 발생할 수 있습니다. 공격자는 서버가 평가하는 {{ ... }}, {% ... %} 등의 표현식이나 구문을 주입할 수 있습니다. 영향은 템플릿에 노출된 데이터, 전역 변수, 호출 가능한 객체에 따라 달라집니다.
Jinja의 자동 이스케이프는 렌더링 결과의 HTML 컨텍스트를 보호하는 기능입니다. 신뢰할 수 없는 텍스트가 먼저 템플릿 소스로 해석되는 SSTI를 방지하지는 않습니다.
잠재적 영향
- 템플릿에 노출된 데이터나 설정 정보가 유출될 수 있습니다.
- 노출된 객체의 부작용 있는 메서드가 호출되거나, 조건에 따라 코드 실행으로 이어질 수 있습니다.
- 작은 템플릿으로도 큰 출력이나 높은 CPU·메모리 사용을 유발할 수 있습니다.
해결 방법
- 템플릿 소스는 개발자가 통제해야 합니다. 고정된 템플릿을 이름이나 파일로 로드하고, 신뢰할 수 없는 값은 컨텍스트 데이터로만 전달합니다.
- 요청 데이터로 템플릿 소스를 만들거나
render_template_string(...),stream_template_string(...)같은 문자열 렌더링 API에 전달하지 않습니다. 구분자 제거, HTML 이스케이프, 이름만sanitize인 함수는 안전한 대책이 아닙니다. - 허용 목록은 사용자가 개발자가 작성한 완전한 템플릿 중 하나를 선택하는 경우에만 사용합니다. 임의의 사용자 작성 템플릿을 문자 단위 허용 목록으로 안전하게 만들려고 하지 않습니다.
- 사용자 작성 템플릿이 제품 요구 사항이라면 기능이 제한된 전용 템플릿 언어를 우선 검토합니다. Jinja를 사용해야 한다면
SandboxedEnvironment또는ImmutableSandboxedEnvironment를 사용하고, 부작용 있는 메서드가 없는 최소한의 데이터만 노출하며, 렌더링 오류를 처리하고, 격리된 서비스에서 CPU·메모리·출력량을 제한합니다. Jinja 샌드박싱만으로 완전한 격리를 제공할 수는 없습니다.
예시
변경 전
python
from flask import Flask, render_template_string, request
app = Flask(__name__)
@app.get("/greeting")
def bad_greeting():
return render_template_string(request.args["template"])
변경 후
python
from flask import Flask, render_template, request
app = Flask(__name__)
@app.get("/greeting")
def safe_greeting():
return render_template(
"greeting.html",
name=request.args.get("name", ""),
)
templates/greeting.html은 애플리케이션이 배포한 고정 파일입니다.
html
Hello {{ name }}
설명:
- 변경 전: 요청 값을 템플릿 소스로 전달하므로 공격자가 Jinja 구문을 정의할 수 있습니다.
- 변경 후: 템플릿 소스는 배포된 파일로 고정하고 요청 값은
name컨텍스트 데이터로만 전달합니다.
템플릿 소스와 데이터
source=에는 개발자가 통제하는 템플릿을 전달하세요. 사용자 값은 템플릿 문자열에 연결하지 말고 별도의 컨텍스트 데이터로 전달하세요.
python
from flask import request
from jinja2 import Environment
env = Environment()
def unsafe_keyword_source():
return env.from_string(globals={}, source=request.args["template"])
def safe_keyword_context():
return env.from_string(
globals={"name": request.args["name"]}, source="Hello {{ name }}"
)
두 번째 호출은 템플릿 문자열을 고정하고 사용자 값을 데이터로 전달합니다. 렌더링 결과를 HTML로 전달한다면 자동 이스케이프 등 출력 문맥에 맞는 보호도 적용해야 합니다.
제한 사항
사용자 작성 템플릿을 허용하는 서비스는 샌드박스 사용 여부와 관계없이 노출 데이터, 호출 가능한 객체, 예외 처리, 리소스 제한과 격리를 함께 검토해야 합니다. 고정 템플릿을 사용하더라도 HTML 등 출력 문맥에 맞는 보호는 별도로 필요합니다.