1. 웹 구성요소
웹 구성요소에는 Web Client, Web Server, HTTP, Web Browser, Web Application 등이 있다. 각각이 어떻게 동작하는지 알아보자.
웹 클라이언트는 웹을 사용하는 고객을 의미하며, 고객은 디바이스 장치(노트북, 태블릿, 스마트폰 등)가 될 수 있다.
디바이스 장치에서 동작하는 웹 클라이언트 프로그램을 웹 브라우저라고 하며, 대표적인 웹 브라우저에는 크롬, 사파리, 파이어폭스 등이 있다. 웹 브라우저는 클라이언트의 요청으로 Request를 작성해 웹 서버에 전달한다.
웹 애플리케이션은 사용자의 웹 브라우저에서 실행되는 소프트웨어를 의미한다. 장바구니, 제품 검색과 필터링, 소셜 미디어 뉴스피드 등 일반적으로 사용되는 웹 사이트 기능이 웹 애플리케이션을 기반으로 설계된다. 웹 애플리케이션에 의해 사용자들은 소프트웨어를 추가로 설치하거나 구성하지 않고도 복잡한 기능을 이용할 수 있다.
웹 서버는 "HTTP 서버"라고도 불린다. 클라이언트측에서 수신받은 요청(Request)을 처리하고 웹 클라이언트에게 필요한 데이터를 응답(Response)한다. 이후 웹 브라우저는 웹 서버에서 응답받은 데이터(이미지, 텍스트 등)를 화면에 표시한다.
HTTP(Hyper Transfer Protocol)은 웹에서 이루어지는 데이터 교환 규칙이다. 비연결성과 무상태성의 특징을 가진다.
1.1. 애플리케이션의 종류
설치되는 형태와 개발 방법에 따라 웹 애플리케이션과 네이티브 애플리케이션으로 분류할 수 있다.
웹 애플리케이션은, 브라우저 내에서 실행하므로 앱을 따로 다운로드받지 않아도 된다 (웹 사이트를 앱으로 감까는 형태). 그리고 비용, 개발 기간이 적게 든다는 장점이 있지만, 속도가 느리다는 단점이 있다.
네이티브 애플리케이션은 사용자가 기기에 직접 다운로드하여 사용한다. 운영체제와 직접 통신하므로, 운영체제 별로 플랫폼이 필요하다. 안드로이드에서 설치가 되는 앱이 ios에는 설치가 안되는 경우가 이에 해당한다. 네이티브 애플리케이션은 기능 구현을 위해 많은 양의 코딩작업이 필요하며 이에 따라 개발자의 높은 기술력이 요구된다는 특징이 있다.
1.2. 웹 애플리케이션
웹 애플리케이션은 웹 브라우저를 통해 접속하여 사용하며, 사용자 인터페이스(UI)는 웹 페이지를 통해 구성된다. 웹 애플리케이션은 HTML, CSS, JS 같은 웹 기술을 이용하여 구현되며, 서버 측에서는 PHP, Python, Ruby 등의 프로그래밍 언어를 사용하여 개발된다.
또한 웹 사이트와 웹 애플리케이션은 다른 개념이다.
웹 사이트는 정적인 컨텐츠를 제공하는 웹 페이지나 문서를 의미하며, 일반적으로 사용자는 해당 웹 페이지를 방문하여 정보를 열람하거나 검색하는 등의 기능을 이용할 수 있다. 뉴스 사이트, 쇼핑몰 등이 웹 사이트의 대표적인 예이다.
웹 애플리케이션은 웹 사이트보다 더 많은 기능을 제공한다. 사용자는 웹 브라우저를 통해 특정 기능을 실행하는 웹 애플리케이션을 사용할 수 있다. 웹 애플리케이션은 사용자의 요청에 따라 데이터를 저장, 조작하거나 가공하여 제공하며, DB와 연동하여 사용자에게 동적으로 변하는 정보를 제공한다. 은행의 인터넷 뱅킹, 온라인 게임, 웹 메일등이 웹 애플리케이션의 대표적인 예이다.
1.3. 웹 애플리케이션 동작 과정
웹 애플리케이션에는 클라이언트-서버 아키텍처가 있다.
클라이언트 측 스크립트는 버튼, 드롭다운 상자 등의 사용자 인터페이스 기능을 다룬다. 최종 사용자가 웹 앱 링크를 클릭하면 웹 브라우저는 클라이언트 측 스크립트를 로드하고 사용자 상호 작용을 위해 그래픽 요소와 텍스트를 렌더링한다. 예를 들어 콘텐츠를 읽거나, 동영상을 시청하거나, 문의 양식에 세부 사항을 기입할 수 있다.
서버 측 스크립트는 데이터 처리를 다룬다. 웹 애플리케이션 서버는 클라이언트 요청을 처리하고 응답을 전송한다. 예를 들어 사용자가 '자세히 보기' 버튼을 클릭하면 웹 애플리케이션 서버는 콘텐츠를 사용자에게 전송하여 응답한다.
2. 웹 리소스
URI(Uniform Resource Identifier)는 '통합 자원 식별자'의 줄임말이다. URI는 인터넷 자원을 식별할 수 있는 문자열을 의미하며, 하위 개념으로 URL과 URN이 있다. URI는 어떤 형식이 있다기 보다는 특정 자원을 식별하는 문자열을 의미한다. 그래서 URL도 아니고 URN도 아니면 URI가 된다.
URL(Uniform Resource Locator)은 네트워크 상에서 리소스(웹 페이지, 이미지 파일 등)의 구체적 위치를 서술한다.
리소스의 위치를 옮기면 해당 URL을 더 이상 사용할 수 없다.
URL의 구조는 아래와 같다.
- scheme: 사용할 프로토콜을 뜻하며 웹에서는 http/https를 사용한다.
- host & port: 접근할 대상(서버)의 호스트 명과 포트 번호이다.
- path: 접근할 대상(서버)의 경로에 대한 상세한 정보이다.
- query: 접근할 대상에 전달하는 추가적인 정보이다 (파라미터)
- fragment: 메인 리소스 내에 존재하는 서브 리소스에 접근할 때 이를 식별하기 위한 정보이다.
URN(Uniform Resource Name)은 URI의 표준 포맷 중 하나로, 이름으로 리소스를 특정하는 URI이다. http와 같은 프로토콜을 제외하고 리소스의 name을 가리키는데 사용된다. 아직까지 대중화 되지는 않았다.
URN에는 리소스 접근 방법과, 웹 상의 위치가 표기되지 않기 때문에 실제 자원을 찾기 위해서는 URN을 URL로 변환하여 이용해야한다.
3. SSRF
SSRF( Server-Side Request Forgery )는 단어 그대로 '서버가 위조된 요청을 보내도록 하는 취약점'이다.
CSRF 기법에서, 요청을 보내게 되는 주체만 브라우저(Client)에서 서버(Server)로 바뀌었다고 이해하면 쉽다.
웹 애플리케이션을 구현하다 보면 외부에 있는 데이터(DB에 있는 사용자 정보 등)를 다른 서버에 요청해야 하는 경우가 많이 있다. 데이터를 요청하기 위해서는 해당 자산이 위치한 주소(URL)이 필요한데, 만약 공격자가 이 주소를 수정할 수 있다면...? 서버가 SSRF 공격에 노출되어 있는 상태인 것이다.
주로 웹 상에 이미지를 보여줄 때 URL 요청으로 가져오는 경우, 파일 다운로드 시 파라미터에 URL이 포함되는 경우 등, 서버가 주제가 되는 요청이 수행될 때 이를 위조할 수 있는 상황이 만들어지면 취약점이 발생한다.
해당 애플리케이션은 요청을 보내면 url 파라미터에 해당하는 사진을 띄워준다.
@app.route('/')
def helloworld():
return 'use /image?url='
@app.route('/image')
def get_url():
url = request.args.get('url', '')
if url:
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as response:
data = ("data:" + response.headers['Content-Type'] + ";" + "base64," + base64.b64encode(response.read()).decode())
ret = f"<img src='{data}'/>"
return (ret)
return "no param"
아래 코드는 사용자로부터 URL을 입력 받으면, 해당 URL로 서버가 HTTP Request하고 Request를 브라우저상에 이미지로 나타내준다.
만약 이때 악의적인 사용자가 이미지가 위치해 있는 URL이아닌 다른 URL을 입력한다면(local file의 경로를 요청하는 url등 ) ssrf가 수행될 것이다.
http://vuln.app:8000/image?url=https://picsum.photos/200