프림 알고리즘(Prim Algorithm)이란?

어떠한 그래프에서 최소신장트리(Minimum Spanning Tree)를 찾는 알고리즘이다.

그리디(Greedy) 알고리즘 중 하나이다.

 

프림 알고리즘(Prim Algorithm)의 아이디어

  • 트리중 하나의 노드에서 시작(아무 노드나 상관없음)
  • 우리가 만들어가고 있는 트리에 인접한 edge들 중 가장 작은 weight를 가진 edge를 추가
  • (단, 사이클을 만들지 않아야함)
  • spanning tree가 될때까지 반복 
    출처 : https://en.wikipedia.org/wiki/File:Prim-animation.gif

프림 알고리즘(Prim Algorithm)의 증명

정확성

G : 주어진 그래프(방향성X, 가중치O)

V : 전체 node의 집합

E : 전체 edge의 집합

Y : 방문한 node

F : 방문한 edge

 

G = (V,E)로 나타낼 수 있고, F  E, Y V이다.

G'(만들어가는중인 그래프) = (Y,F)

MST = (V,F') 이라고 정의하자.

 

가장 처음 F는 empty set이므로 F ⊆ F' 이 성립한다. 

 

1. G'에 인접한 edge들 중 가장 가중치가 낮은 edge를 e(v1 Y와 v2 V-Y를 잇는 edge)라고 하자

2. e가 F'의 원소일 경우, F U {e} 도 MST가 될 수 있는 상태이다.

3. e가 F'의 원소가 아닐 경우, F'은 spanning tree이므로 F' U {e}에는 하나의 사이클이 생길것이다.

    이때, F' U {e}에는 사이클에 속하지만 F에 속하지 않는 edge e'가 존재할 것이다.

3-1. F' U {e} - {e'}이 spanning tree가 된다면 e<=e'이므로, F' U {e} - {e'} 이 MST일 것이다.

3-2. F U {e} F' U {e} - {e'} 이므로 F U {e}는 항상 MST가 될 수 있는 상태이다.

 

이를 Y=V가 될 때까지 반복하여 MST를 만들 수 있다.

 

시간복잡도

E = edge, V = vertex

Minimum edge weight data structure Time complexity (total)
adjacency matrix, searching $O(|V|^2)$
binary heap and adjacency list $O((|V|+|E|)log|V|) = O(|E|log|V|)$
Fibonacci heap and adjacency list $O(|E|+|V|log|V|)$

출처 : https://en.wikipedia.org/wiki/Prim%27s_algorithm

구현(백준 1647번)

문제

동물원에서 막 탈출한 원숭이 한 마리가 세상구경을 하고 있다. 그러다가 평화로운 마을에 가게 되었는데, 그곳에서는 알 수 없는 일이 벌어지고 있었다.

마을은 N개의 집과 그 집들을 연결하는 M개의 길로 이루어져 있다. 길은 어느 방향으로든지 다닐 수 있는 편리한 길이다. 그리고 각 길마다 길을 유지하는데 드는 유지비가 있다. 임의의 두 집 사이에 경로가 항상 존재한다.

마을의 이장은 마을을 두 개의 분리된 마을로 분할할 계획을 가지고 있다. 마을이 너무 커서 혼자서는 관리할 수 없기 때문이다. 마을을 분할할 때는 각 분리된 마을 안에 집들이 서로 연결되도록 분할해야 한다. 각 분리된 마을 안에 있는 임의의 두 집 사이에 경로가 항상 존재해야 한다는 뜻이다. 마을에는 집이 하나 이상 있어야 한다.

그렇게 마을의 이장은 계획을 세우다가 마을 안에 길이 너무 많다는 생각을 하게 되었다. 일단 분리된 두 마을 사이에 있는 길들은 필요가 없으므로 없앨 수 있다. 그리고 각 분리된 마을 안에서도 임의의 두 집 사이에 경로가 항상 존재하게 하면서 길을 더 없앨 수 있다. 마을의 이장은 위 조건을 만족하도록 길들을 모두 없애고 나머지 길의 유지비의 합을 최소로 하고 싶다. 이것을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 집의 개수 N, 길의 개수 M이 주어진다. N은 2이상 100,000이하인 정수이고, M은 1이상 1,000,000이하인 정수이다. 그 다음 줄부터 M줄에 걸쳐 길의 정보가 A B C 세 개의 정수로 주어지는데 A번 집과 B번 집을 연결하는 길의 유지비가 C (1 ≤ C ≤ 1,000)라는 뜻이다.

임의의 두 집 사이에 경로가 항상 존재하는 입력만 주어진다.

출력

첫째 줄에 없애고 남은 길 유지비의 합의 최솟값을 출력한다.

예시

 

풀이

MST를 구하는 문제로, kruskal알고리즘 또는 Prim 알고리즘을 사용할 수 있다. 이 글에선 Prim알고리즘을 사용하여 문제를 풀어보았다.

입력받은 값들로 MST를 구한 후 가장 긴 edge를 제거하면 풀리는 문제이다.

#include <iostream>
#include <queue>
#include <vector>

using namespace std;

typedef struct edge {
    int vertex1, vertex2;
    int weight;

    edge() {
        vertex1 = 0;
        vertex2 = 0;
        weight = 0;
    }

    edge(int v1, int v2, int w) {
        vertex1 = v1;
        vertex2 = v2;
        weight = w;
    }

    bool operator < (const edge& e) const {
        return weight < e.weight;
    }
}edge;

int Prim(int* vertex, vector<edge> edges[], int v) {
    int total_weight = 0;
    priority_queue<edge> adj_edges;
    int cur_vertex = 0, max_edge=0;
    vertex[0] = 1;

    for (int j = 0; j < v - 1; j++) {
        for (int i = 0; i < edges[cur_vertex].size(); i++) {
            adj_edges.push(edges[cur_vertex][i]);
        }
        while (!adj_edges.empty() && (vertex[adj_edges.top().vertex1] == 1 && vertex[adj_edges.top().vertex2] == 1)) {
            adj_edges.pop();
        }
        edge e = adj_edges.top();
        adj_edges.pop();
        vertex[e.vertex2] = 1;
        cur_vertex = e.vertex2;
        total_weight += e.weight;
        if(max_edge>e.weight){
            max_edge = e.weight;
        }
    }
    // return MST; 이렇게 하고 싶지만 최대한 빠르게 하기 위해서..total_weight를 리턴하는 걸로 하자
    return  -(total_weight-max_edge);

}

int main()
{
    int v, e;
    int v1, v2, w;
    int total_weight = 0;

    scanf("%d %d", &v, &e);

    int* vertex = new int[v];
    fill(vertex, vertex + v, 0);
    vector<edge> *edges = new vector<edge> [v];

    for (int i = 0; i < e; i++) {
        scanf("%d %d %d", &v1, &v2, &w);
        edges[v1-1].push_back(edge(v1-1, v2-1, -w));
        edges[v2-1].push_back(edge(v2-1, v1-1, -w));
    }

    total_weight = Prim(vertex, edges, v);
    printf("%d\n", total_weight);
}

 

 

 

오류수정은 언제나 환영입니다^^

'CS > Algorithm' 카테고리의 다른 글

합병 정렬(Merge sort)  (0) 2024.10.12
그리디 알고리즘(Greedy Algorithm, 탐욕법)  (0) 2024.07.13

운영체제란?

출처 : https://ko.wikipedia.org/wiki/운영체제

운영체제란 하드웨어와 응용프로그램의 사이에서 작동하며 PC의 하드웨어, 시스템 리소스를 제어하여, 하드웨어가 문제없이 작동하고, 리소스를 효율적으로 사용할 수 있도록 하는 시스템 소프트웨어입니다.

 

우리가 흔히 아는 윈도우,MacOS,리눅스,유닉스 등등이 운영체제입니다.

 

운영체제의 역할

운영체제는 하드웨어와 응용 프로그램의 중간에서 인터페이스를 제공하고 응용 프로그램들이 효율적으로 관리되도록하는 관리자와 같은 역할을 합니다.

응용 프로그램이 직접 하드웨어에 접근해서 작동하게 되면, 프로그램을 만드는 것도 어려워질 뿐만 아니라 하드웨어의 정상적인 작동, 시스템 자원의 효율적인 활용, 보안 등에 심각한 문제가 생기기 때문에, 운영체제는 컴퓨터의 필수적인 요소 입니다.

프로그램 하나 실행했는데 CPU와 메모리를 전부 점유하고 안놔준다거나, 악성 프로그램이 PC를 마음대로 조종하게 되면 큰 문제가 되겠죠.

 

운영체제는 PC에서 아래와 같은 역할을 합니다.

 

  1. 프로세서, 메모리, 디스크, 입출력장치 간의 통신
  2. 시스템 자원 관리(스케줄링 등)
  3. 사용자와 시스템 간의 편리한 인터페이스 제공
  4. 시스템의 오류를 검사 및 복구

 

오류수정은 언제나 환영입니다^^

1. 그리디 알고리즘이란?

  • 최적의 값을 구해야 하는 상황에서 전체적인 상황을 상정하여 구하는 것이 아닌, 각 단계에서 최선의 선택을 하는 근시안적 방법론입니다.
  • 전체적인 상황을 상정하지 않기 때문에 항상 최적의 해를 구하는 것이 보장되어있지 않지만, 근사해를 구하는것이 가능합니다.

아래와 같은 트리에서 각 노드의 합의 최대값을 구하는 상황일때, 탐욕법을 이용하면 각 단계에서 가장 큰 값을 선택하게 되어 5->10->4와 같이 선택하게 됩니다.

최적의 해는 5->7->9이므로 탐욕법을 이용하는것이 항상 최적의 해를 구하는 것은 아님을 보여줍니다.

출처 https://velog.io/@kyunghwan1207/%EA%B7%B8%EB%A6%AC%EB%94%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98Greedy-Algorithm-%ED%83%90%EC%9A%95%EB%B2%95

2. 그리디 알고리즘의 특징

2.1 그리디 알고리즘의 조건

그리디 알고리즘이 근사값이 아닌 최적값을 보장하는 조건 2가지가 있습니다.

 

  • 탐욕 선택 속성 (Greedy Choice Property)
현재의 선택이 미래의 선택에 영향을 끼치지 않는다.
  • 최적 부분 구조 (Optimal Substructure)
부분의 최적해가 모여 전체의 최적해가 된다.

 

문제가 이 두가지의 조건을 만족한다면 그리디 알고리즘을 사용해 최적값을 구할 수 있습니다.

2.2 그리디 알고리즘의 단계

1. 선택절차(Selection Procedure)

현재 상태에서 최적인 선택을 한다. 이 선택은 바뀌지 않는다.

 

2. 적절성 검사(Feasibility Check)

선택한 항목이 문제의 조건을 만족시키는지 확인한다.

 

3. 해답 검사(Solution Check)

모든 선택이 완료되면, 최종 선택이 문제의 조건을 만족시키는지 확인한다.

 

Reference

 

'CS > Algorithm' 카테고리의 다른 글

합병 정렬(Merge sort)  (0) 2024.10.12
프림 알고리즘(Prim Algorithm) 구현과 증명  (0) 2024.09.17

1. 디자인 패턴이란?

객체 지향 프로그래밍 설계를 할 때 자주 발생하는 문제들을 피하기 위해 사용되는 패턴. 개발을 하며 생길 수 있는 반복적인 문제들을 패턴을 통해 설계를 함으로써 미리 예방을 할 수 있게 됩니다..

디자인 패턴을 이용하면 유지보수성이 좋고 이해가 쉬운 코드를 짤 수 있게 됩니다.

 

2. MVC패턴이란?

출처 https://ko.wikipedia.org/wiki/%EB%AA%A8%EB%8D%B8-%EB%B7%B0-%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC

MVC패턴은 데이터를 가지고 있는 Model, 사용자 인터페이스 요소를 가지고 있는 View, View와 Model을 이어주는  Controller의 3가지 요소로 나누어집니다.

이와 같이 3가지 요소로 나누어 사용자 인터페이스와 비즈니스 로직을 분리하여 코드의 의존성을 낮추고 유지보수성을 높이는 효과를 얻게 됩니다.

 

MVC의 작동은 다음과 같이 진행됩니다.

  1. 사용자의 Request(요청)를 Controller가 받는다.
  2. Controller는 비즈니스 로직을 처리한 후 결과를 Model에 담는다.
  3. Model에 저장된 결과를 바탕으로 시각적 요소 출력을 담당하는 View를 제어하여 사용자에게 전달한다.

2.1 Model 모델

Model(모델)은 필요한 데이터에 대해서 Controller의 제어에 따라, DB에게 query를 하여 데이터를 저장, 삭제, 업데이트등을 진행하게 됩니다. View는 이 Model의 데이터를 기반으로 사용자 화면을 구성하게 됩니다.

 

Model의 상태에 변화가 있을 때 컨트롤러와 뷰에 이를 통보합니다. 이와 같은 통보를 통해서 뷰는 최신의 결과를 보여줄 수 있고, 컨트롤러는 모델의 변화에 따른 적용 가능한 명령을 추가·제거·수정할 수 있습니다. 어떤 MVC 구현에서는 통보 대신 뷰나 컨트롤러가 직접 모델의 상태를 읽어오기도 합니다.

 

모델의 규칙

  • 사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 한다.
  • View나 Controller에 대해서 어떤 정보도 알지 말아야 한다.
  • 변경이 일어나면, 변경 통지에 대한 처리방법을 구현해야만 한다.

 

2.2 View 뷰

View(뷰)는 사용자가 직접 보게되는 화면, 사용자 인터페이스를 구성하는 역할을 합니다.

뷰는 컨트롤러를 통해 받은 모델의 값을 통해 화면을 구성하게 됩니다.

 

뷰의 규칙

  • Model이 가지고 있는 정보를 따로 저장해서는 안된다.
  • Model이나 Controller를 알고 있을 필요가 없다.
  • 변경이 일어나면 변경통지에 대한 처리방법을 구현해야만 한다.

 

2.3 Controller 컨트롤러

Controller(컨트롤러)는 뷰와 모델의 사이를 잇는 인터페이스의 역할을 합니다.

모델이 데이터를 어떻게 처리할 것인지를 알려주고, 처리된 모델을 뷰에게 넘겨주게 됩니다.

모델이나 뷰로부터 변경 내용을 통지 받으면 이를 각 구성 요소에게 통지해야 합니다. 사용자가 어플리케이션을 조작하여 발생하는 변경 이벤트들을 처리하는 역할을 수행합니다.

 

컨트롤러의 규칙

  • 모델이나 뷰에 대해서 알고 있어야 한다.
  • 모델이나 뷰의 변경을 모니터링 해야 한다.

 

 

3. MVC 패턴의 장점

  • MVC패턴의 각 컴포넌트는 자신의 역할을 한 후 값을 넘겨주기만 하면 되기 때문에, 시스템 결합도가 낮아집니다.
  • 각 코드가 여러파일에 나누어져 있기 때문에 코드의 가독성이 높아집니다.
  • 유지보수 시 특정 컴포넌트만 수정하면 되기 때문에 유지보수가 쉬워집니다.

 

4. MVC 패턴의 한계

Massive View Controller

대규모 시스템의 경우 컨트롤러가 다수의 모델과 뷰를 컨트롤하여, 컨트롤러의 부담이 커지는 문제가 생기게 됩니다.

또한 다수의 뷰에 다수의 모델이 연결되는 경우가 생겨 서로간의 의존성이 커지는 경우가 발생할 수 있습니다.

 

이를 해결하기 위해 아래와 같은 패턴들이 있습니다.

  • MVVM
  • MVP
  • MVW
  • Flux
  • Redux
  • RxMVVM

 

Reference

더보기

'Dev > Web' 카테고리의 다른 글

REST와 RESTful API  (0) 2025.02.06

1. SQL injection이란

2. SQL injection의 종류

3. 대응방법

1. SQL injection이란

출처:안랩

SQL injection은 Database의 취약점을 이용하여 정상적이지 않은 동작을 하도록 하는 SQL문을 입력하여 공격자가 원하는 작업을 수행하거나 정보를 유출하게되는 공격입니다.

 

SQL injection은 최근까지도 많이 일어나고 있는 공격기법 중 하나입니다.

 

2. SQL injection의 종류

2.1 Normal SQL injection

출처:안랩

Normal SQL injection은 논리적 에러를 이용한 SQL injection으로 위의 로그인 예시에서 ' OR 1=1 --와 같이 값을 입력해주게 되면 OR 1=1에 의해 항상 참, --에 의해 뒷 부분은 주석처리가 되며 로그인에 성공하게 됩니다.

 

2.2 Error based SQL injection

https://www.bugbountyclub.com/pentestgym/view/53

Error based SQL injection은 주로 데이터베이스에 대한 정보를 획득하기 위해 사용됩니다. SQL의 잘못된 문법이나 자료형 불일치 등에 의해 데이터베이스가 알려주는 데이터베이스 오류 메시지에 의존하여 수행되는 공격 기법입니다.

 

2.3 Union based SQL injection

출처 : 안랩

SQL의 Union이라는 구문을 사용하는 공격인 Union based SQL injection은 Union을 이용하여 원래의 요청에 하나의 추가 쿼리를 삽입하는 공격입니다.

이 때 필요한 전제조건으로 Union하는 두 쿼리의 컬럼의 개수와 데이터 형식이 같아야합니다.

 

위의 사진의 경우 게시글을 찾는 쿼리문에 Union을 넣어 Users 테이블의 id, 패스워드를 읽어오는 공격입니다.

 

2.4 Blind SQL injection - Boolean based SQL

출처 : 안랩

 

위의 사진은 MySQL 에서 테이블 명을 조회하는 구문으로 limit 키워드를 통해 하나의 테이블만 조회하고, SUBSTR 함수로 첫 글자만, 그리고 마지막으로 ASCII 를 통해서 ascii 값으로 변환해줍니다

만약에 조회되는 테이블 명이 Users 라면 ‘U’ 자가 ascii 값으로 조회가 될 것이고, 뒤의 100 이라는 숫자 값과 비교를 하게 됩니다.

U의 ascii 값은 125이므로 뒤의 100의 값을 변경해가면 125일때 거짓이 나오므로 첫 글자가 U라는것을 알 수 있습니다.

이를 자동화하여 테이블명을 알아내는 방법입니다.

 

2.5 Blind SQL injection - Time based SQL

출처 : 안랩

위의 그림은 Time based SQL Injection을 사용하여 현재 사용하고 있는 데이터베이스의 길이를 알아내는 방법입니다. 로그인 폼에 주입이 되었으며 임의로 abc123 이라는 계정을 생성해 두었습니다.

악의적인 사용자가 abc123’ OR (LENGTH(DATABASE())=1 AND SLEEP(2)) -- 이라는 구문을 주입하였습니다. 여기서 LENGTH 함수는 문자열의 길이를 반환하고, DATABASE 함수는 데이터베이스의 이름을 반환합니다.

주입된 구문에서, LENGTH(DATABASE()) = 1 가 참이면 SLEEP(2) 가 동작하고, 거짓이면 동작하지 않습니다.

 

이를 통해서 숫자 1 부분을 조작하여 데이터베이스의 길이를 알아 낼 수 있습니다. 만약에 SLEEP 이라는 단어가 치환처리 되어있다면, 또 다른 방법으로 BENCHMARK  WAIT 함수를 사용 할 수 있습니다.

 

3. 대응방법

입력 값에 대한 검증

사용자의 입력이 올바른 값인지 검증합니다. 사용자가 공격할 가능성이 있는 키워드들을 검증하고 차단합니다.

 

 

Prepared Statement 구문사용

 Prepared Statement 구문을 사용하게 되면, 사용자의 입력 값이 데이터베이스의 파라미터로 들어가기 전에DBMS가 미리 컴파일 하여 실행하지 않고 대기합니다. 그 후 사용자의 입력 값을 문자열로 인식하게 하여 공격쿼리가 들어간다고 하더라도, 사용자의 입력은 이미 의미 없는 단순 문자열 이기 때문에 전체 쿼리문도 공격자의 의도대로 작동하지 않습니다.

 

 

Error Message 노출 금지

공격자가 SQL Injection을 수행하기 위해서는 데이터베이스의 정보(테이블명, 컬럼명 등)가 필요합니다. 데이터베이스 에러 발생 시 따로 처리를 해주지 않았다면, 에러가 발생한 쿼리문과 함께 에러에 관한 내용을 반환해 줍니다. 여기서 테이블명 및 컬럼명 그리고 쿼리문이 노출이 될 수 있기 때문에, 데이터 베이스에 대한 오류발생 시 사용자에게 보여줄 수 있는 페이지를 제작 혹은 메시지박스를 띄우도록 하여야 합니다.

 

웹 방화벽 사용

웹 공격 방어에 특화되어있는 웹 방화벽을 사용하는 것도 하나의 방법입니다. 웹 방화벽은 소프트웨어 형, 하드웨어 형, 프록시 형 이렇게 세가지 종류로 나눌 수 있는데 소프트웨어 형은 서버 내에 직접 설치하는 방법이고, 하드웨어 형은 네트워크 상에서 서버 앞 단에 직접 하드웨어 장비로 구성하는 것이며 마지막으로 프록시 형은 DNS 서버 주소를 웹 방화벽으로 바꾸고 서버로 가는 트래픽이 웹 방화벽을 먼저 거치도록 하는 방법입니다.

'Security > Webhacking' 카테고리의 다른 글

CSRF 공격  (0) 2024.05.12
XSS문제 실습  (0) 2024.05.10
Cookie & Session  (0) 2024.05.08
  1. CSRF란
  2. CSRF의 원리
  3. CSRF 방어 방법

1. CSRF란

CSRF는 공격자가 만든 악성 스크립트가 포함된 URL을 사용자가 실행하게 되면, 사용자의 세션을 이용하여 사용자가 의도하지 않은 작업을 수행하는 공격입니다.

대표적으로 패스워드 변경, 송금 등이 있습니다.

 

2. CSRF의 원리

CSRF 공격이 성립하기 위해 충족되야하는 조건이 있습니다.

1. 사용자는 보안이 취약한 서버로부터 이미 로그인되어 있는 상태여야 합니다.
2. 쿠키 기반의 서버 세션 정보를 획득할 수 있어야 합니다.
3. 공격자는 서버를 공격하기 위한 요청 방법에 대해 미리 파악하고 있어야 합니다.

 

위 조건이 만족되었을 때  CSRF공격이 가능하게 됩니다.

 

CSRF공격의 시나리오는 다음과 같습니다. 

1. 사용자가 보안이 취약한 서버에 로그인되어있다.

2. 공격자의 악성 스크립트가 포함된 URL을 사용자가 접속하게된다.

3. 악성 스크립트에 담겨있는 내용이 사용자 세션 ID를 이용해 실행되게된다.

4. 서버는 해당 내용을 사용자가 요청한것으로 인식하고 실행하게 된다.

3. CSRF 방어방법

1. Referrer 검증

Request header에 포함된 Referer는 현재 요청된 페이지의 링크 이전의 웹페이지 주소를 포함합니다.

Referrer를 검증해서 해당 요청이 요청될 수 있는 위치인지 검사를 하면 CSRF를 막을 수 있습니다.

 

2. CSRF 토큰 검증

로그인을 할 때 CSRF 토큰을 생성하여 세션에 저장해 둡니다.

CSRF 토큰을 페이지 요청태그의 hidden값에 넣어줍니다.

Ex) <input type="hidden" name="_csrf" value="${CSRF_TOKEN}" />

이후 요청을 할 때마다 CSRF 토큰을 같이 보내어, 서버에서 토큰을 검증합니다.

'Security > Webhacking' 카테고리의 다른 글

SQL injection 공격  (0) 2024.05.12
XSS문제 실습  (0) 2024.05.10
Cookie & Session  (0) 2024.05.08

XSS(Cross-Site-Scripting)이란


사이트 간 스크립팅, 크로스 사이트 스크립팅(영어: Cross-site scripting XSS)은 웹 애플리케이션에서 많이 나타나는 취약점의 하나로 웹사이트 관리자가 아닌 이가 웹 페이지에 악성 스크립트를 삽입할 수 있는 취약점이다. 이름이 CSS가 아닌 이유는 웹 기술인 CSS와 헷갈릴 수 있어서다. -Wikipedia-

 

 

XSS공격은 위에서 말한것과 같이 관리자가 아닌 사용자가 웹 페이지에 스크립트를 삽입할 수 있는 취약점을 말한다.

 

스크립트를 삽입함으로써 웹 페이지가 공격자가 원하는 임의의 행동을 수행시킬 수 있다. 공격자가 XSS를 이용하여 쿠키를 탈취하게 된다면 세션하이재킹(Session Hijacking) 공격등으로도 이어질 수 있다.

 

XSS는 이름에서 알 수 있듯 자바스크립트를 이용한다.

XSS의 종류와 기법


Stored XSS

Stored XSS, 출처:안랩

 

Stored XSS는 웹 서버에 악성 스크립트를 심어놓고 사용자가 해당 페이지에 접근 할 때마다 스크립트가 실행되는 방식의 공격기법이다.

Stored XSS공격은 보통 악성 스크립트를 게시글 등을 이용하여 사용자가 해당 게시글에 접근하면 스크립트가 작동하는 방식으로 진행이 된다.

 

악성 스크립트가 저장된 게시글 등을 열람한 사용자들은 악성 스크립트가 작동함에 따라 쿠키나 세션 등의 민감 정보를 탈취당하거나 다른 웹사이트로 리다이렉션될 수도 있다.

 

Stored XSS 공격 시나리오

  1. 공격자가 XSS 취약점이 있는 사이트를 발견
  2. 보안이 취약한 사이트에서 제공하는 게시판에 사용자 정보를 빼돌릴 수 있는 스크립트를 작성하여 업로드
  3. 일반 사용자가 공격자가 작성한 게시글을 읽으면, 서버로부터 악성 스크립트가 담긴 게시글 응답을 받음
  4. 일반 사용자의 브라우저에서 응답 메시지를 실행하면서 악성 스크립트 실행
  5. 악성 스크립트를 통해 사용자 정보가 공격자에게 전달됨

 

 

Reflected XSS

Reflected XSS 출처:안랩

Reflected XSS는 스크립트가 포함된 공격용 악성 URL을 만든 뒤, 사용자가 해당 URL을 클릭했을 때 정보를 획득하는 공격이다. 

 

XSS 공격에 취약한 웹 사이트에 악성 스크립트를 실행하는 URL을 직접 사용자가 누르게 만든다. 

URL 링크를 누르게 되면 자동적으로 악성 스크립트가 실행되게 된다.

 

Reflected XSS 공격 시나리오

  1. 공격자가 XSS 취약점이 있는 사이트를 발견
  2. 보안이 취약한 사이트에서 사용자 정보를 빼돌릴 수 있는 스크립트가 담긴 URL을 만들어 일반 사용자에게 스팸 메일등으로 전달
  3. 일반 사용자가 메일을 통해 전달받은 URL 링크를 클릭하게 되면, 일반 사용자 브라우저에서 보안이 취약한 사이트로 요청을 전달
  4. 일반 사용자의 브라우저에서 응답 메시지를 실행하면서 악성 스크립트가 실행
  5. 악성 스크립트를 통해 사용자 정보가 공격자에게 전달됨.

 

DOM based XSS

DOM based XSS 출처:안랩

DOM based XSS공격은 악성 스크립트가 포함된 URL을 일반 사용자가 클릭하였을 때, 웹 서버에서 받아온 페이지를 클라이언트 브라우저에서 DOM을 구성하는 과정에서 일어난다.

 

DOM based XSS 공격 시나리오

  1. 공격자가 XSS 취약점이 있는 사이트를 발견
  2. 보안이 취약한 웹 페이지에서 악성 스크립트가 실행되도록 URL 주소를 만들어 일반 사용자에게 전달.
  3. 일반 사용자가 메일 등을 통해 전달받은 URL 링크를 클릭하여, 서버로부터 HTML 문서를 전달받음.
  4. 사용자의 브라우저가 응답 받은 HTML 문서를 읽으면서 필요한 스크립트를 실행하는 중에 악성 스크립트가 동작합니다.
  5. 악성 스크립트를 통해 사용자 정보가 악의적으로 전달됩니다.

 

위의 Reflected XSS와 차이점이 무엇인지 헷갈리기 쉽다.

Reflected XSS : URL의 값을 서버로 전달해 서버에서 페이지를 처리하여 응답해주면서 일어나는 취약점

DOM based XSS : URL의 값이 서버로 전달되는것이 아닌 클라이언트 측에서 페이지를 처리하며 생기는 취약점

 

예를들어, page.php?value="악성스크립트"와 같은 요청을 할 때,

Reflected XSS의 경우 서버에서 value의 값을 처리하여 응답 페이지에 악성스크립트가 담겨 오게되지만

DOM based XSS의 경우 서버의 응답에는 악성스크립트가 없고 클라이언트 측에서 페이지를 처리하며 악성스크립트가 실행되게 된다

 

XSS 대응방법


  • 웹 서버에서 입력 값에 정의된 문자 길이를 제한 또는 검증하여 클라이언트 측에서 실행될 수 있는 스크립트 명령이 삽입되지 않도록 설정
  • HTML 태그의 사용이 불필요한 경우 사용자의 입력 값에서 HTML 특수 문자들을 HTML Entity로 변환하여 스크립트를 일반 문자열로 인식되도록 하기
  • HTML태그를 사용해야할 경우에는 블랙리스트 또는 화이트리스트를 이용해 특정 태그만 사용할 수 이ㅆ도록 설정
  • 웹 방화벽을 사용하여 비정상적인 데이터가 전송될 경우 차단

https://xss-game.appspot.com/

 

XSS game

Welcome, recruit! Cross-site scripting (XSS) bugs are one of the most common and dangerous types of vulnerabilities in Web applications. These nasty buggers can allow your enemies to steal or modify user data in your apps and you must learn to dispatch the

xss-game.appspot.com

위 사이트에서 진행하였다. 문제는 총 6문제이다.

1번 문제

 

간단하게 <script>alert()</script>를 넣어주면 풀리는 문제

 

2번 문제

 

<script>가 통하지 않아 <img>의 onerror를 이용하여 alert()를 작동시켰다.

 

3번 문제

 

코드를 보면 <img src='/static/level3/cloud{num}.jpg/>로 값을 넣어주는것을 확인할 수 있다.

문제 2번과 마찬가지로 onerror를 쓰면 되는것으로 보이지만 사용자가 입력을 하는 부분이 없다.

 

 

이럴때는 URL을 이용하여 원하는 값을 입력해주면 된다.

frame#뒤에 없는 번호인 5번을 넣어 error를 발생시키고, onerror를 통해 alert()함수를 실행시켜보았다.

 

4번 문제

 

 

위의 input상자에 넣은 값을 <img>의 onload="startTimer('{{timer}}');"에 넣어주는 것을 볼 수 있다.

timer의 따옴표를 탈출하고 alert()를 실행시키기 위해서 -1');를 통해 startTimer('-1');를 만들어주자

이어서 뒤에 alert(' 를 붙여줌으로써 alert('');를 만들어준다

다음과 같이 입력하면 된다.

 

전체 입력 = -1');alert('

입력 시 실행되는 함수 = startTimer('-1');alert('');

 

5번 문제

signup.html

이번 문제에는 3가지 html페이지가 있지만 여기서는 signup.html만 보면 된다.

level.py

level.py의 코드를 보면 next값을 get요청이 들어왔을 때 들어오는 값으로 설정해주고 있는 것을 알 수 있다.

 

signup.html

signup.html의 코드를 보면 <a href="{{next}}">로 되어있는 부분이 있는데, <a>태그의 href에는 주소 뿐만이 아니라 자바스크립트 코드가 들어가서 실행될 수도 있다.

next의 값에 javascript:alert();를 입력하면 되지 않을까?

 

 

URL의 next값에 javascript:alert()를 넣어준 후 next버튼을 눌러주면 alert가 실행되면서 성공하게 된다!

 

6번문제

 

/* This is a completely awesome invisible gadget */

gadget.js

<!doctype html>
<html>
  <head>
    <!-- Internal game scripts/styles, mostly boring stuff -->
    <script src="/static/game-frame.js"></script>
    <link rel="stylesheet" href="/static/game-frame-styles.css" />
 
    <script>
    function setInnerText(element, value) {
      if (element.innerText) {
        element.innerText = value;
      } else {
        element.textContent = value;
      }
    }
 
    function includeGadget(url) {
      var scriptEl = document.createElement('script');
 
      // This will totally prevent us from loading evil URLs!
      if (url.match(/^https?:\/\//)) {
        setInnerText(document.getElementById("log"),
          "Sorry, cannot load a URL containing \"http\".");
        return;
      }
 
      // Load this awesome gadget
      scriptEl.src = url;
 
      // Show log messages
      scriptEl.onload = function() { 
        setInnerText(document.getElementById("log"),  
          "Loaded gadget from " + url);
      }
      scriptEl.onerror = function() { 
        setInnerText(document.getElementById("log"),  
          "Couldn't load gadget from " + url);
      }
 
      document.head.appendChild(scriptEl);
    }
 
    // Take the value after # and use it as the gadget filename.
    function getGadgetName() { 
      return window.location.hash.substr(1) || "/static/gadget.js";
    }
 
    includeGadget(getGadgetName());
 
    // Extra code so that we can communicate with the parent page
    window.addEventListener("message", function(event){
      if (event.source == parent) {
        includeGadget(getGadgetName());
      }
    }, false);
 
    </script>
  </head>
 
  <body id="level6">
    <img src="/static/logos/level6.png">
    <img id="cube" src="/static/level6_cube.png">
    <div id="log">Loading gadget...</div>
  </body>
</html>

index.html

class MainPage(webapp.RequestHandler):
  def render_template(self, filename, context={}):
    path = os.path.join(os.path.dirname(__file__), filename)
    self.response.out.write(template.render(path, context))
 
  def get(self):
    self.render_template('index.html')
 
application = webapp.WSGIApplication([ ('.*', MainPage), ], debug=False)

level.py

 

문제 화면

6번 문제는 URL의 frame#뒤에 넣은 값을 읽어, 해당 주소를 <script> 의 src로 넣고 document.head.appendChild()로 head영역에 더해주게 된다.

즉 src의 값을 alert()를 실행하는 주소의 값으로 넣어주면 된다.

 

내 웹서버에 js파일을 업로드하여 실행해주는 방법도 있지만, 이번엔 Data URL schema방식을 사용했다.

 

Data URL schema문법

data:[<mediatype>][;base64],<data>

 

 

data:text/javascript,alert()를 입력해주어 성공!

'Security > Webhacking' 카테고리의 다른 글

SQL injection 공격  (0) 2024.05.12
CSRF 공격  (0) 2024.05.12
Cookie & Session  (0) 2024.05.08

+ Recent posts