보안정보

전문화된 보안 관련 자료, 보안 트렌드를 엿볼 수 있는
차세대 통합보안관리 기업 이글루코퍼레이션 보안정보입니다.

웹 템플릿 엔진 기반의 SSTI 취약점 분석

2022.09.03

13,883

01. SSTI 취약점을 이해하기 위한 사전 단계

SSTI(Server Side Template Injection)취약점은 웹 어플리케이션에 적용되어 있는 웹 템플릿 엔진(Web Template Engine)에 공격자의 공격 코드가 템플릿에 포함된 상태에서 서버 측에서 템플릿 인젝션이 발현되는 공격을 의미한다. SSTI 취약점을 이해하기 위해서는 취약점이 발현되는 템플릿의 용도와 활용방법에 대한 이해가 필요하기 때문에 본격적으로 SSTI취약점을 소개하기에 앞서 템플릿 엔진의 등장배경과 사용방법에 대해서 간략하게 소개하고자 한다.

1990년경 팀 버너스-리(Tim Berners-Lee)에 의해 세계 최초의 브라우저인 월드와이드웹(WWW)이 세상에 공개되었을 때는 현재의 웹 브라우저처럼 사용자의 동작에 반응하는 기능들이 현저히 낮았다. 단지 정적인 기능만 수행할 수 있는 HTML, CSS로 구동 되었으며, 이후 인터넷의 대중화로 사용자와 상호작용 및 접근성과 유연성을 갖춘 동적 페이지 형태의 웹 브라우저로 발전하였다. 웹 브라우저의 발전의 기반에는 자바스크립트 등 프레임워크 및 라이브러리 등의 브라우징 기술과 템플릿 엔진의 기술이 존재한다.

템플릿 양식과 특정 데이터 모델에 따른 입력자료를 합성하여 결과 문서를 출력하는 소프트웨어 및 컴포넌트를 템플릿 엔진이라고 하는데 웹 템플릿 엔진은 브라우저에서 출력되는 웹 문서를 위한 템플릿 엔진을 의미하게 된다. 정리하자면 고정적으로 사용되는 웹 문서를 템플릿으로 미리 작성해 두고 동적으로 변경되는 데이터 영역만 필요 시에 결합해서 웹 문서를 구성하고 화면에 출력하게 되는 것이다. 보다 자세하게 웹 템플릿 엔진이 무엇인지 간단한 사례를 통해서 사용 목적과 구조에 대해서 다시 한 번 살펴보고자 한다. 또한, 앞으로 본 문서에서 특별히 설명이 필요한 경우가 아니라면 웹 템플릿 엔진을 템플릿으로 지칭해서 사용하도록 하겠다.

[그림 1] Web Template Engine 구조

02. Web Template Engine 구조와 적용방안

[그림 2] HTML의 4가지 구조

먼저 Template을 설명하기 전에 잠시 HTML 구조를 살펴보겠다. HTML 문서의 구조는 △ 문서의 시작과 끝을 알려주는 <html> 태그, △ 문서의 형태, 타이틀 정보, 스타일 정보 등이 들어가 있는 <head> 태그, △ 인터페이스 요소를 구성해 브라우저로 출력되며, 정보 전달을 위한 데이터를 표현해주는 <body> 태그, 마지막으로 △ 서버와의 비동기 통신 등 동적인 기능을 제공하기 위한 <script> 태그의 4가지로 구성되어 있다.

웹 문서를 작성하기 위해서는 크게 [그림 2]와 같이 4가지의 큰 틀 안에서 필요한 코드를 작성하게 된다. 또한, 단순히 소개 글 하나만 보여주려는 사이트가 아니라면 목적에 따라 위와 같은 웹 문서 여러 개를 작성하게 되는데 웹 문서마다 반복적으로 사용되는 코드들이 존재한다. 예를 들어, <head> 태그에 들어가는 , <meta>, <title> 태그와 외부 script 파일을 불러오는 <script src=> 태그가 일반적으로 반복해서 사용되는 코드들이다.

[그림 3] Web Template Engine을 적용한 샘플용 직원 게시판

Template을 살펴보기 위해서 [그림 3]과 같이 게시글 작성 기능, 회원가입, 로그인, 검색, 질문 등록하기 등의 기능이 구현되어 있는 샘플 게시판을 활용하였다. [그림 3]의 상단에 출력되는 네비게이션바는 사용자가 웹 사이트에서 가장 많이 사용하는 기능을 웹 페이지 상단에 고정시키는 기능을 지원한다. 웹 문서를 구성할 때마다 네비게이션바를 새로 구성해야 한다면 반복 구문수행으로 인해 편의성과 효율성이 낮아지게 되는데 이러한 반복작업을 최소화 할 수 있는 것이 바로 Web Template Engine라고 할 수 있다. 네비게이션바와 같이 반복적인 요소를 템플릿화 시켜서 미리 작성해 두고 동적으로 변경되는 데이터 부분만 결합해서 출력하기 때문에 개발자는 소스코드를 좀더 효율적으로 관리할 뿐만 아니라 직관적으로 확인이 가능하기 때문에 코드의 복잡성이 낮아질 수 있게 된다.

지금까지 간단하게 Template의 기본적인 기능 및 사용목적에 대해서 살펴보았다. 이제는 Template의 구성 방법을 간략히 알아보고 공격자 관점에서 Template구문에 공격 코드를 삽입하는 SSTI취약점에 대해서 알아보겠다.

[그림 4] Template이 적용된 ‘[그림 2]’의 소스코드 상세내역

[그림 4]는 [그림 2]를 Template으로 구성했을 때의 모습을 보여준다. 작성한 <body> 태그는 {% block content %}구문에 삽입되고 <script> 태그의 코드는 {% block script %} 구문을 통해 고정 Template에 삽입된다. 이렇게 반복적으로 사용되는 코드들을 Template 문서로 구성하고 그 외 동적인 요소들은 따로 작성해 후에 결합하여 사용하는 Template의 구조와 적용 방안에 대해서 알아봤다.

그렇다면 이렇게 편리한 기능을 제공하는 Template에 어떤 잠재적인 위협이 있는 것일까? 한 번 같이 생각을 해보자. 만약 Template을 구성하는 코드에 우리가 입력한 값이 삽입되고 삽입된 코드가 Template구문이라서 서버의 주요 설정에 관여할 수 있다는 점은 상상만으로도 무서운 일이다. SSTI는 이러한 Web Template Engine을 공격하는 행위이기 때문에 위험하다고 볼 수 있다. 이제 본격적으로 Web Template Engine기반의 SSTI 취약점의 공격방법에 대해서 상세하게 분석해보고자 한다.

03. SSTI (Server Side Template Injection) 취약점 분석

[그림 5] SSTI 공격 구성도

SSTI(Server Side Template Injection)취약점은 서버 측에 Template이 구성되어 있고 사용자 입력 값이 기존 Template에 삽입되는 경우 공격자는 Template 구문을 이용해 악성 페이로드를 삽입하여 공격자가 원하는 액션을 수행하도록 하는 공격이다. [그림 5]의 SSTI 공격 구성도와 같이 공격자가 kw코드에 {{ 2*2 }}라는 Template구문을 입력하면 사칙연산 결과인 4라는 값이 회신되면서 공격자가 삽입한 Template구문이 실행되는 과정을 확인할 수 있다.

[표 1] 최근 5년간 공개된 CVE 중 SSTI 취약점이 발생된 목록

SSTI 취약점이 발생하는 경우 Server-Side 측의 웹 문서 로드 시 동작하는 렌더링에 관여할 수 있기 때문에 단순히 Client-Side 취약점 공격(XSS, CSRF) 뿐만 아니라, Server-Side의 취약점 공격(RCE, SSRF)으로도 연결될 수 있어서 위험도가 높다. SSTI 취약점 점검 시 사용하는 악성 페이로드는 Template마다 구문이 상이해 Template 별 문법을 숙지하고 있어야한다. 다음 장에서는 Template 별 문법과 특징 및 공격 구문에 대해서 알아보도록 하겠다.

[그림 6] Template Engine 별 사용되는 Template 문법

[그림 6]은 Template Engine별로 사용되는 Template문법유형을 정리한 내용이다. 정리된 내용에서 알 수 있듯이 사용하는 웹 언어나 프레임워크 종류에 따라 다양한 Template 문법을 사용할 수 있으며, 문법체계는 환경에 따라 조금씩 다를수 있으나 큰 틀에서는 괄호나 중괄호 안의 값이 동적으로 실행되여 화면에 출력해준다는 점은 동일하다. 따라서 백엔드(Back-end)시스템에 대한 디테일한 정보가 없는 경우에는 여러가지 Template문법을 삽입하여 서버로부터 회신되는 결과값을 통해서 유추할 수 있게 된다. 본 문서에서는 웹 어플리케이션에서 사용되는 다수의 Template환경 중에서도 ‘Jinja Template’ 사용 시 발생될 수 있는 SSTI 취약점에 대해 다루고자 한다.

Jinja Template은 Flask 프레임워크와 관련된 Python 웹 프로그래밍 Template Engine이다. Flask는 Python 웹 어플리케이션 개발 시 Django에 이어서 가장 많이 사용되는 프레임워크로 본 문서에서도 취약점 테스트 진행을 위해 Python Flask 모듈을 사용했다. 먼저 Jinja Template의 간단한 문법 예제를 살펴보도록 하겠다.

[표 2] 자주 사용되는 Jinja Template 문법 예제

Template 구문에서 사용하는 제어문(if 구문)은 Python에서 사용하는 제어문 문법과 동일하다. 차이점이 있다면 제어문의 끝을 명시하는 ‘{% endif %}’문을 항상 제어문 마지막 줄에 작성해줘야 한다는 것이다. 반복문(for 구문)도 Python의 문법 체계와 동일하지만 제어문과 마찬가지로 반복문의 종료지점을 명시하는 ‘{% endfor %}’를 반복문 마지막 줄에 작성해줘야 한다. 표현식 ‘{{ … }}’은 중괄호 안의 변수나 표현식의 결과를 출력하기 때문에 연산의 결과값이나 객체의 속성을 표현하는데 사용된다. 주석의 경우 일반적인 언어의 주석표현과 동일하게 ‘#’을 사용하여 주석처리를 할 수 있다.

지금 소개한 문법 이외에도 공백제거나 이스케이프 표현식 등의 문법들이 존재하지만 본 문서에서 SSTI취약점을 이해하는데는 [표 2]에서 설명된 문법정도만 가지고도 충분하다. 다음으로는 SSTI공격시에 공격구문의 핵심요소인 ‘{{ … }}’표현식에 대해서 자세히 알아보고자 한다.

[그림 7] SSTI 테스팅을 위한 코드 예시
[표 3] Template 구문 해석 예시

표현식 ‘{{ … }}’를 이해하기 위해 하나의 예시를 준비했다. [그림 7] 코드는 사용자에게 입력 받은 값이 age 변수에 삽입되고 삽입된 age 값이 Template 구문에 의해 해석되어 HTML 문서에 삽입되는 구조이다. [표 3]는 [그림 7] 코드에 사용자가 상수와 사칙 연산을 입력 했을 때의 차이를 보여주고 있다. 사용자가 상수를 입력했을 때는 age 변수 값을 그대로 가지고 오는 반면에 사칙 연산을 입력했을 때는 변수에 입력된 값 5*5를 반환하는 것이 아닌 사칙 연산 결과를 반환한다. 이렇듯 Template 구문은 단순 호출 뿐만 아니라 사칙 연산도 가능하며 중괄호 안의 값을 동적으로 화면에 표현해 주는 기능을 가지고 있다.

앞서 Template 구문이 어떻게 해석되어 표현되는지 살펴봤다. ‘{{ … }}’ 구문은 단순 연산도 가능하지만 클래스 객체의 속성(함수, 변수)을 이용한 명령어 실행도 가능하다. 이제는 샘플용 직원 게시판 사이트를 이용해 SSTI 취약점을 점검해보고 발현된 취약점을 이용해 원격코드 실행이 가능한 RCE공격까지 테스트를 진행해보도록 하자.

[그림 8] Template을 적용한 샘플용 직원 게시판

[그림 3]에서도 잠시 소개했던 샘플 직원 게시판 사이트이다. 해당 사이트는 회원가입, 로그인, 게시글 작성, 댓글 작성, 검색 등의 기능을 가지고 있고 이 중 검색 기능은 사용자가 입력한 키워드를 화면에 그대로 출력해준다. [그림 9]는 이와 관련된 검색 기능 코드 중 일부이다.

[그림 9] 직원 게시판의 검색 기능 코드 중 일부

[그림 9]의 코드를 살펴보면 6~8번 라인에서 사용자에게 입력 받은 값이 kw 파라미터에 삽입되어 GET 방식으로 요청이 보내진다. 요청에 의해 1~4번 라인의 _list() 함수가 동작해 kw 파라미터 값이 kw 변수에 삽입되어 지며, kw 변수는 format 함수에 의해 문자열과 합쳐져 search 변수에 삽입된다. 그 후 filter 함수를 통해 kw 변수 값이 포함된 게시글을 찾게 된다. 그리고 9~11 라인에 의해 2번 라인에서 선언된 kw 변수가 HTML 코드에 삽입되고 13번 라인 render_template_string() 함수에 의해 템플릿이 해석되어 화면에 출력된다. render_template_string() 함수는 별도의 파일을 만들지 않고 소스 내에서 템플릿을 출력하기 위해 사용되며, 삽입되어 있는 Template 구문을 자동으로 해석해 주는 기능을 가지고 있다.

[그림 10] render_template_string() 함수에 의해 해석된 템플릿 구문

[그림 10]을 보면 {{55}}로 검색한 키워드가 render_template_string() 함수에 의해 템플릿 구문이 해석되어 55 연산의 결과가 HTML 코드에 삽입된 것을 확인할 수 있다. 일반적으로, SSTI 취약점 진단 시 [그림 10]와 같이 계산식을 넣어 서버의 리턴 결과를 토대로 취약점 발현 유무를 확인하게 된다. 검색 기능이 SSTI에 취약하다는 것을 알았으니 서버의 중요 정보들이 포함되어 있는 config 클래스를 출력해 보겠다.

[그림 11] Template 구문에 의해 해석되어 출력된 config 클래스

대체로 Flask의 경우 app.n에 저장되는 대부분의 정보들이 config 클래스에 포함되어 진다. 출력된 SECRET_KEY, BASE_DIR, SQLALCHEMY_DATABASE_URI 변수를 통해 CSRF Token, 웹 어플리케이션이 동작하는 실제 경로 및 DATABASE 정보 등을 확인 할 수 있다.

[그림 12] str 클래스 접근

다음으로 빈 문자열(“”)에 __class__ 속성을 사용하면 문자열 인스턴스 클래스를 사용할 수 있다는 응답을 받게 된다. str 클래스는 Python 내장 클래스로, 객체를 만들고 그 객체의 정보를 알고 싶을 때 문자열로 반환해주는 기능을 가지고 있다.

[그림 13] 문자열 인스턴스 클래스 접근

str 클래스에 __base__ 속성을 사용하면 부모 클래스(super class)를 알 수 있으며, 부모 클래스가 object라는 응답을 받게 된다. object 클래스는 Python의 최상위 클래스로 특별한 메소드와 속성을 가지고 있다. built-in 되어있는 메소드 및 속성은 시스템 설정 확인부터 명령어 실행까지 가능하기 때문에 이를 이용하면 원하는 동작을 하게끔 만들 수 있게 된다.

[그림 14] object 클래스의 서브 클래스 목록 출력

__subclasses__()를 사용하면 해당 클래스의 서브 클래스 목록을 딕셔너리 형태로 반환 받을 수 있는데 [그림 14]은 object 클래스의 서브 클래스 목록이 출력된 것이다.

[그림 15] subprocess 모듈의 Popen 클래스 확인

반환된 object 서브 클래스 목록 중 index 428번에 subprocess.Popen 클래스가 존재하는 것을 확인할 수 있다.(index 값은 서버 환경에 따라 달라질 수 있다.) Popen 클래스는 새로운 프로세스를 생성하고 입출력 파이프를 연결하여 리턴 코드를 획득할 수 있도록 해준다. 여기서 우리는 원격 코드를 실행하고 결과 값을 받기 위해 해당 클래스를 사용할 것이다.

[그림 16] dir 명령을 통해 출력된 현재 디렉터리의 파일 목록

작성한 Popen 클래스의 구문을 확인해보면 첫 번째 인자 args는 명령 행 문자열을 받고, 두 번째 인자인 shell=True는 별도의 서브 쉘을 실행하고 해당 쉘 위에서 첫 번째 인자로 받은 args 명령 행을 실행할 수 있도록 해준다. 마지막 세 번째 인자인 stdout은 표준 출력을 뜻하며, 명령 실행 결과를 반환하게 된다. 추가로 communicate 메소드는 Popen 생성자가 프로세스를 시작하면 자식 프로세스의 출력을 읽어와 종료할 때 까지 대기하게 된다. 여기서는 첫 번째 인자 값으로 dir 명령어를 입력해줌으로써, 현재 디렉터리의 목록 결과 값을 리턴 코드로 받게 된 것이다.

[그림 18] globals 클래스를 통해 선언된 os 모듈 확인

codecs.IncrementalDecoder 클래스(index 109번)를 사용하면 raw bytes로 encode된 문자열을 decode하여 출력할 수 있다.

[그림 18] globals 클래스를 통해 선언된 os 모듈 확인

추가적으로 다른 공격 구문도 살펴보겠다. globals 클래스는 선언된 변수 객체 정보와 함수 객체 정보를 가지고 있는데 여기에는 os 모듈도 포함되어 있다. os 모듈은 운영체제에서 제공되는 여러 기능을 Python에서 수행할 수 있도록 제공해주며 파일 이동, 복사, 디렉터리 생성, 목록 출력 등이 가능해진다. Flask 경우 웹 어플리케이션 구축 시 DB 연결, 파일 업로드 기능을 위해 일반적으로, os 모듈을 사용한다.

[그림 19] dir 명령을 통해 출력된 현재 디렉터리 목록

os 모듈이 제공하는 기능 중에는 명령 파이프를 통해 시스템 명령을 실행시켜 결과 값을 출력해주는 popen 메소드가 있다. 첫 번째 인자 값으로 명령어를 전달해주면 바이너리 값으로 출력 해주는데 이때, read() 메소드를 사용하면 문자열로 읽어와 출력해준다.

[표 4] Python 외부 명령 호출 모듈 및 메소드
[그림 20] Jinja Template에서 사용되는 Payload

[그림 20]는 Jinja Template 환경에서 SSTI 취약점 발생 시 자주 사용되는 공격 페이로드들을 모아놓은 것이다. 더 자세한 공격 구문을 보고 싶거나, 다른 Template의 공격 구문들을 확인하고 싶다면 ‘4.참고 자료’의 12,13 링크를 통해 확인 할 수 있다.

04. SSTI 취약점 대응방안

SSTI 취약점은 대다수 Injection 종류의 공격과 동일하게 Sanitization, Input Validation, Sandbox을 다중으로 적용하는 것이 가장 좋은 형태의 대응방안이다. 본 문서에서는 구축된 환경 특성상 소스코드 레벨 단위에서의 대응방안만을 다루며 SandBox는 다루지 않는다.

1) Sanitization

Sanitization의 영어사전 뜻은 살균이지만, 프로그래밍 쪽에서는 코드 안전성 검사를 뜻한다. 쉽게 말해, 안정성이 확인되지 않은 값을 검사해서 DOM 또는 HTML에 적용할 수 있는 안전한 값으로 변환하는 것을 말하며, SSTI 취약점 대응 관점으로는 사용자 입력으로 부터 Template을 생성하고 해석되어 삽입되지 않도록 처리해야한다. Jinja Template 경우 render_template_string() 함수가 아닌 render_template() 함수를 사용하면 사용자가 입력한 Template 구문을 명령어가 아닌 문자열로 해석해준다. 간단한 예시를 통해 render_template() 함수를 알아보겠다.

[그림 21] 취약한 샘플 직원 게시판 코드 중 일부

[그림 21]은 샘플 직원 게시판의 구현된 코드 중 일부이다. 34번 라인을 보면 template 변수가 선언되어 있고 해당 변수에는 Template 구문이 포함된 HTML 코드가 삽입되어 있다. 그리고 template 변수는 201번 라인의 render_template_string() 함수의 첫 번째 인자 값으로 전달되어 Template 구문이 해석되고 사용자에게 출력된다. 이때, 렌더링한 문자열을 반환하면서 사용자가 입력한 Template 구문도 해석되기 때문에 취약점이 발생하게 된다. 반대로, render_template() 함수는 templates에 저장된 HTML 문서를 렌더링하게 되며, 이미 작성된 Template 구문 외 삽입되는 Template 구문은 모두 문자열로 치환되어 안전하다.

[그림 22] 샘플 직원 게시판의 HTML 문서 코드 중 일부

[그림 22]는 templates에 저장된 샘플 직원 게시판의 HTML 문서이다. 여기서 말하는 templates는 render_template() 함수와 연동되는 디렉터리를 말하며, Template 문서 렌더링 시 참조하는 기본 경로(디렉터리)이다.

[그림 23] render_template() 함수를 사용하도록 구현된 샘플 직원 게시판

[그림 23]의 16~33번 라인은 사용자가 입력한 검색어를 포함한 게시글이 존재하는지 찾는 로직이다. 34번 라인을 보면 render_template() 함수를 사용하고 있으며, 미리 작성된 HTML 문서를 렌더링해서 읽어와 사용자에게 출력해 준다.

[그림 24] render_template() 함수가 적용된 페이지

[그림 24]를 보면 이전과 다르게 연산 결과가 출력되는게 아닌 사용자가 입력한 검색어가 그대로 출력되는 것을 볼 수 있다. 이렇게 render_template() 함수를 사용하게 되면, HTML 문서 내에 작성된 Template 구문 외 Template 구문은 해석되지 않고 문자열로 받아들이게 된다.

2) Input Validation

Input Validation은 사용자 입력 값 유효성 검증으로 사용자가 입력한 특수문자 구문들을 Escape 처리하는 것을 말한다. SSTI 공격 구문에 사용되는 핵심 특수문자로는 ‘{}’, ‘[]’ 등이 있으며, 일부 XSS, SQLi에 대응하는 방식과 동일하게 공격 구문에 사용되는 특수문자들을 필터링 치환해야 한다. 하나의 예시로 문서가 Template으로 구성되어 있고, 사용자 입력 값을 받는 폼이 존재한다면 [그림 26]의 SSTI 공격에 주로 사용되는 대표적인 특수문자들을 정규 표현식으로 필터링해 Error Page Return 또는 문자열(String, Hex 등)로 치환 및 제거할 수 있는 로직을 추가한다.

[그림 25] re 모듈을 사용한 정규 표현식 로직
[그림 26] 정규 표현식에 의해 필터링 되고 있는 특수문자

[그림 25]는 Python 내장 모듈인 re를 사용해 SSTI 공격에 자주 사용되는 특수문자들을 필터링해 제거하는 로직을 추가해 준 것이다. re 모듈은 Python에서 정규 표현식이 필요할 때 사용하는 모듈로 주로 변수 값에 특정 문자열이 포함되어 있는지 확인할 때 사용한다.

[그림 27] 정규 표현식 필터링 로직에 의해 제거된 특수문자

[그림 27]은 특수문자 필터링 로직이 적용되어 사용자가 입력한 특수문자들이 제거되어 출력된 모습이다.

[그림 28] 403 Error Page 리다이렉트 로직

[그림 28]은 이전 특수문자 제거 로직과 동일하게 re 모듈을 사용해 명시된 특수문자가 사용자 입력 값에 존재할 경우 403 Error Page로 리다이렉트 시키는 로직을 추가한 것이다.

[그림 29] 리다이렉트된 페이지

05. 마무리

지금까지 Web Template Engine 기반에서 발생될 수 있는 SSTI 취약점에 대해 살펴보았다. SSTI취약점은 웹 어플리케이션 환경에서 발생하는 XSS, SQLi와 같이 사용자의 입력값 검증누락으로 인해 발생되는 취약점들처럼 자주 사용되는 공격방식은 아니다. 하지만 웹 브라우징 기술이 발전하고 그에 따라 웹 어플리케이션 개발환경에 사용되는 기술요소들을 악용한 공격기술들도 발전하면서 나타난 공격기법이라고 볼 수 있다. SSTI취약점은 공격 접근성과 비례하여 공격영향도도 높은 취약점이므로 웹 어플리케이션의 구현기술에 따른 대응전략이 필요하다. 본 문서에서는 ‘Jinja Template’환경을 기반으로 발생될 수 있는 SSTI공격기법에 대해서만 소개하였으나, 이외에도 다양한 Web Template Engine들이 존재하기 때문에 Web Template Engine을 악용한 공격기법들을 지속적으로 모니터링하고 대응해야 할 것이다.

06. 참고자료

[1] HTML의 역사
https://velog.io/@simoniful/HTML의-역사
[2] Web System Architecture History
https://velog.io/@ahnjh/Web-웹-서비스의-역사와-발전
[3] Template Engine
https://gmlwjd9405.github.io/2018/12/21/template-engine.html
[4] Web Template Engine
https://yangbox.tistory.com/47
[5] Python Popen Class
http://theyoonicon.com/python-popen-클래스/
[6] Python String Encode
https://elliot-kim.github.io/python3/lpthw-7/
[7] 코드 안전성 검사와 보안 정책
https://angular.kr/guide/security#코드 -안전성-검사와-보안-정책
[8] SSTI(Server Side Template Injection) 취약점
https://me2nuk.com/SSTI-Vulnerability/
[9] SSTI(Server Side Template Injection) 취약점2
https://www.hahwul.com/cullinan/ssti/
[10] SSTI(Server Side Template Injection) 취약점3
https://core-research-team.github.io/2021-05-01/Server-Side-Template-Injection(SSTI)
[11] Python 외부 명령 호출
http://daplus.net/python-파이썬에서 -외부-명령-호출/
[12] Web Template Engine 별 구문 및 공격 기법
https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server Side Template Injection
[13] SSTI Payloads
https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt