XSS 공격

 

- 웹 상에서 가장 기초적인 취약점 공격 방법의 일종으로 악의적인 사용자가 공격하려는 사이트에 스크립트를 넣는 기법

- 공격 성공 -> 사이트에 접속한 사용자는 삽입된 코드 실행 -> 의도치 않은 행동을 수행시킴 or 쿠키나 세션 토큰 등의 민감한 정보 탈취

- 자바스크립트 사용하는 경우 많음

 

종류

- 저장 XSS 공격 (Stored XSS) -> 보안상 가장 위협

악의적인 스크립트코드가 웹에 입력되면서 DB에 저장된다. 불특정 다수가 공격자의 게시물에 접근하면 지속적으로 악의적인 스크립트가 실행되어 위협이 큰 편이다.

ex) 랜섬웨어

 

<공격 단계>

  1. 게시판, 프로필, 댓글 등에 악성 스크립트를 삽입
  2. 사용자가 사이트를 방문하여 저장되어 있는 페이지에 정보를 요청할 때(게시판 글 읽기 등)
  3. 서버는 악성 스크립트를 사용자에게 전달하여 사용자 브라우저에서 스크립트가 실행되면서 공격

 

- 반사 XSS 공격 (Reflected XSS)

웹페이지 URL에 존재하는 파라미터의 악의적인 스크립트 코드를 입력하여 사용자가 URL을 클릭하면 그 코드가 실행되게 하는 공격이다.

 

<공격 단계>

  1. 취약점이 있는 A사이트를 발견
  2. 민감한 정보를 획득할 수 있는 공격용 악성 URL을 생성
  3. 공격자는 이 URL을 이메일, SMS 등에 포함하여 배포하고 클릭 유도
  4. 피해자가 URL을 클릭하면, 바로 공격 스크립트가 피해자로 반사되어 A 사이트에 관련된 민감한 정보(ID/패스워드, 세션 정보)를 공격자에게 전송

- DOM 기반 XSS 공격 ( DOM Based XSS)

DOM 환경에서 URL을 해 사용자의 브라우저를 공격하는 것이다.

 

DOM : W3C 표준으로 HTML 및 XML 문서에 접근방법을 표준으로 정의하는 문서객체모델

W3C에서는 DOM을 '프로그램 및 스크립트가 문서의 컨텐츠, 구조 및 형식을 동적으로 접근 및 업데이트할 수 있도록 하는 언어 중립적인 인터페이스다'라고 정의되어 있다. DOM은 HTML문서를 계층적으로 보면서 컨텐츠를 동적으로 변경할 수 있다.

'Web Hacking > WEB Hacking 기초' 카테고리의 다른 글

[SISS] XSS Game 05, 06  (0) 2022.01.22
[SISS] XSS Game 03, 04  (0) 2022.01.10
[SISS] 생활코딩 DATABASE-MySQL 정리  (0) 2022.01.08
[SISS] XSS Game 01, 02  (0) 2022.01.03
[SISS] 생활코딩 WEB2-PHP 정리  (0) 2021.12.28

PHP의 원리

> .html

- 웹브라우저에서 html파일을 요청 -> 웹서버가 확장자를 확인, 자신이 처리할 수 있는 html임을 판단 -> htdocs 디렉토리에서 읽고 웹브라우저에 전송

 

> .php

- 웹브라우저에서 php파일을 요청 -> 웹서버가 확장자를 확인, 자신이 처리할 수 없기 때문에 PHP에게 파일에 대한 처리를 위임 -> PHP가 htdocs 디렉토리에서 읽고 PHP 문법에 따라 해석하고 html파일을 생산 -> 그 html을 웹서버가 웹브라우저에게 전송

 

<? php //php 코드 시작
	echo date('Y-m-d H:i:s')
?> //php 코드 끝

- 동적으로 웹페이지를 생성할 수 있음 (html은 정적)

 

PHP의 데이터 타입

> 숫자 표현

<? php
	echo 1; //1출력
    print(1); //1출력
    echo 1+1; //2출력
?>

- 산술 연산자 : +, -, *, /

 

> 문자 표현

<? php
	'Hello World' // error
    
    echo 'Hello world'; // single quotes
    echo "Hello world"; // double quotes
    
    echo "Hello 'w'orld"; // Hello 'w'orld 출력
    echo "Hello "w"orld"; // error
    
    //concatenation operator
    echo "Hello"."world"; // .으로 이어진 좌항과 우항을 연결해서 하나의 문자열을 만들어냄
    
    //strlen 함수
    echo strlen("Hello world"); // 문자열 길이인 11출력
?>

- 문자열 결합 연산자 : .

 

PHP의 변수

<?php
    $a=10; // 변수 a에 10 할당
    echo $a+1; // 11출력
?>
<?php
    $name ="이름";
    echo "name 출력".$name; // $name에 '이름'이라고 출력
?>

- 변수 선언 : $변수이름 = 값;

 

URL 파라미터

안녕하세요. <?php echo $_GET[‘name’]; ?>님

- 주소가 바뀜에 따라 name에 들어가는 문자가 달라짐

 

함수

> strlen, nl2br 함수

<?php 
$str="Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
 tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 
 quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 
 
 consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 
 cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non 
 proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
 echo $str;
 echo strlen($str); 
 echo nl2br($str); 
?>

 

- strlen 함수 : 문자열 길이 확인 함수 
- nl2br 함수 : 자동으로 줄바꿈을 해주는 함수

 

> file_get_contents 함수

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <title></title>
 </head>
 <body>
   <h1>WEB</h1>
   <ol>
     <li><a href="index.php?id=HTML">HTML</a></li>
     <li><a href="index.php?id=CSS">CSS</a></li>
     <li><a href="index.php?id=Java">Java</a></li>
   </ol>
   <h2>
     <?php
     echo $_GET['id'];
     ?>
   </h2>
    <?php
      echo file_get_contents("data/".$_GET['id']); 
    ?>
 </body>
</html>

- file_get_contents 함수 :  문자열로 전체 파일을 읽어주는 함수

여기서는 id로 들어오는 값을 경로로 전환해 주고 data파일 내에 있는 해당 파일을 찾아서 표현해주는 역할을 하였다.

 

Boolean과 비교 연산자

<?php
  var_dump(11); // 출력 : int(11)
  var_dump('11'); // 출력 : string(2) "11"
  var_dump(1==2); // 출력 : bool(false)
  var_dump(1<2); // 출력 : bool(true)
?>

- var_dump 함수 : 괄호 내 값의 데이터 형식과 함께 같이 출력시켜주는 함수 (주로 개발할 때 쓰임)

 

제어문 - 조건문과 반복문

> 조건문

<?php
  echo '1<br>';
  if(true){
      echo '2<br>'
  }
  else{
      echo '3<br>'
  }
?>

true일 경우, 1과 2가 출력되고 false일 경우, 1과 3이 출력된다.

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <title></title>
 </head>
 <body>
   <h1><a href="index.php">WEB</a></h1>
   <ol>
     <li><a href="index.php?id=HTML">HTML</a></li>
     <li><a href="index.php?id=CSS">CSS</a></li>
     <li><a href="index.php?id=Java">Java</a></li>
   </ol>
   <h2>
     <?php
     	if(isset($_GET['id'])){ //id값이 있는지
        	echo $_GET['id'];
        }
        else{
        	echo "Welcome";
        }
     ?>
   </h2>
    <?php
    	if(isset($_GET['id'])){
        	echo $_GET['id'];echo file_get_contents("data/".$_GET['id']); 
        else{
        	echo "Hello, PHP";
        }
    ?>
 </body>
</html>

- isset 함수 : 해당 값이 존재하는 지를 판별하는 함수

 

> 반복문

<?php
    echo '1<br>';
    $i=0;
    while($i<3){
    	echo '2<br>';
        $i=$i+1;
    }
?>

1 출력 후  $i가 0, 1, 2일 때 2가 총 세 번 출력된다. 

 

> 배열

 

<?php
	$coworkers = array('egoing', 'leezche', 'duru', 'taeho');
    echo $coworkers[1].'<br>'; // 출력 : leezche
    echo $coworkers[3].'<br>'; // 출력 : taeho 
    var_dump(count($coworkers)); // 출력 : int(4)
    array_push($coworkers, 'graphittie'); // 배열에 원소 추가
?>

 

> 활용

<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <title></title>
 </head>
 <body>
   <h1><a href="index.php">WEB</a></h1>
   <ol>
   	<?php
    	$list = scandir('./data'); // data 하위 파일들 읽어옴
        
        $i = 0;
        while($i < count($list)) // list 개수만큼 반복
        {
        	if($list[$i] != '.'){ // 현재디렉토리 제외
            	if($list[$i] != '..'){ //부모디렉도리 제외
                  echo "<li><a href=\"index.php?id=$list[$i]\">$list[$i]</a></li>\n";
                }
            }
            $i = $i + 1;
        }
     ?>
   </ol>
   <h2>
     <?php
     	if(isset($_GET['id'])){ //id값이 있는지
        	echo $_GET['id'];
        }
        else{
        	echo "Welcome";
        }
     ?>
   </h2>
    <?php
    	if(isset($_GET['id'])){
        	echo $_GET['id'];echo file_get_contents("data/".$_GET['id']); 
        else{
        	echo "Hello, PHP";
        }
    ?>
 </body>
</html>

이 코드를 이용하면(<ol>태그 부분) data디렉토리 아래에 새로운 파일을 추가해도(데이터가 달라져도) 자동으로 웹에 추가된다.

 

함수

<?php
    function basic(){
    	print("abc1<br>");
        print("abc2<br>");
    }
    basic(); // 함수 내 코드 실행
    
    function sum($left, $right){
      print($left+$right);
      print("<br>");
    }
    sum(2,4); // 출력 : 6
    sum(4,6); // 출력 : 10
?>

 

> 활용

<? php
    function print_title(){
   	 	if(isset($_GET['id'])){ //id값이 있는지
        	echo $_GET['id'];
        }
        else{
        	echo "Welcome";
        }
    }
    function print_description(){
    	if(isset($_GET['id'])){
        	echo $_GET['id'];echo file_get_contents("data/".$_GET['id']); 
        else{
        	echo "Hello, PHP";
        }
    }
    function print_list(){
    	$list = scandir('./data'); // data 하위 파일들 읽어옴
        
        $i = 0;
        while($i < count($list)) // list 개수만큼 반복
        {
        	if($list[$i] != '.'){ // 현재디렉토리 제외
            	if($list[$i] != '..'){ //부모디렉도리 제외
                  echo "<li><a href=\"index.php?id=$list[$i]\">$list[$i]</a></li>\n";
                }
            }
            $i = $i + 1;
        }
    }
?>
<!DOCTYPE html>
<html>
 <head>
   <meta charset="utf-8">
   <title>
   	print_title();
   </title>
 </head>
 <body>
   <h1><a href="index.php">WEB</a></h1>
   <ol>
     <?php
    	print_list();
     ?>
   </ol>
   <h2>
     print_title();
   </h2>
    <?php
    	print_description();
    ?>
 </body>
</html>

함수로 코드를 정리하였다.

 

Form과 POST

<!doctype html>
<html>
  <body>
    <form action="form.php" method="post">
      <p><input type="text" name="title" placeholder="Title"></p>
      <p><textarea name="description"></textarea></p>
      <p><input type="submit"></p>
    </form>
  </body>
</html>
<?php
  file_put_contents('data/'.$_POST['title'], $_POST['description']);
?>

URL을 통해 데이터를 전송하는 방식은 사용자가 서버로 데이터를 보낼 때 쓰면 안된다. 데이터를 서버쪽으로 전송할 때, 주소의 title 혹은 파라미터 정보가 포함되어 있으면 사용자들이 자신이 원하지 않았는데 글이 써지는 등의 일이 발생할 수 있기 때문이다. -> 해결 방법 : form 태그에 method를 post로 지정

 

글 생성, 수정, 삭제

//index.php

<?php
function print_title(){
  if(isset($_GET['id'])){
    echo $_GET['id'];
  } else {
    echo "Welcome";
  }
}
function print_description(){
  if(isset($_GET['id'])){
    echo file_get_contents("data/".$_GET['id']);
  } else {
    echo "Hello, PHP";
  }
}
function print_list(){
  $list = scandir('./data');
  $i = 0;
  while($i < count($list)){
    if($list[$i] != '.') {
      if($list[$i] != '..') {
        echo "<li><a href=\"index.php?id=$list[$i]\">$list[$i]</a></li>\n";
      }
    }
    $i = $i + 1;
  }
}
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      <?php
      print_title();
      ?>
    </title>
  </head>
  <body>
    <h1><a href="index.php">WEB</a></h1>
    <ol>
      <?php
      print_list();
      ?>
    </ol>
    <a href="create.php">create</a>
    <?php if(isset($_GET['id'])) { ?> //인자로 들어오는 값이 있는지 확인
      <a href="update.php?id=<?=$_GET['id']?>">update</a>
      <form action="delete_process.php" method="post">
        <input type="hidden" name="id" value="<?=$_GET['id']?>">
        <input type="submit" value="delete">
      </form>
    <?php } ?>
    <h2>
      <?php
      print_title();
      ?>
    </h2>
    <?php
    print_description();
     ?>
  </body>
</html>

update의 경우 해당 항목을 클릭했을 때만 수정항목을 보이도록 하기위해 조건문에 isset을 이용해 인자로 들어오는 값이 있는지를 확인해준다.

 

//create, update.php

<?php
function print_title(){
  if(isset($_GET['id'])){
    echo $_GET['id'];
  } else {
    echo "Welcome";
  }
}
function print_description(){
  if(isset($_GET['id'])){
    echo file_get_contents("data/".$_GET['id']);
  } else {
    echo "Hello, PHP";
  }
}
function print_list(){
  $list = scandir('./data');
  $i = 0;
  while($i < count($list)){
    if($list[$i] != '.') {
      if($list[$i] != '..') {
        echo "<li><a href=\"index.php?id=$list[$i]\">$list[$i]</a></li>\n";
      }
    }
    $i = $i + 1;
  }
}
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
      <?php
      print_title();
      ?>
    </title>
  </head>
  <body>
    <h1><a href="index.php">WEB</a></h1>
    <ol>
      <?php
      print_list();
      ?>
    </ol>
    <a href="create.php">create</a>
    <?php if(isset($_GET['id'])) { ?>
      <a href="update.php?id=<?=$_GET['id']?>">update</a>
    <?php } ?>
    <h2> //수정 폼
     <form action="update_process.php" method="post">
       <input type="hidden" name="old_title" value="<?=$_GET['id']?>">
       <p>
         <input type="text" name="title" placeholder="Title" value="<?php print_title(); ?>">
       </p>
       <p>
         <textarea name="description" placeholder="Description"><?php print_description(); ?></textarea>
       </p>
       <p>
         <input type="submit">
       </p>
     </form>
  </body>
</html>

삭제는 form을 거칠 필요 없다.

//create_process.php

<?php
file_put_contents('data/'.$_POST['title'], $_POST['description']);
header('Location: /index.php?id='.$_POST['title']);
?>

header를 이용해서 사용자를 다른페이지로 보낼 수 있다. 

//update_process.php

<?php
rename('data/'.$_POST['old_title'], 'data/'.$_POST['title']); //파일명 수정
file_put_contents('data/'.$_POST['title'], $_POST['description']); //내용 수정
header('Location: /index.php?id='.$_POST['title']);
?>

submit했을 때 id가 old_title로 전송된다.

//delete_process.php

<?php
unlink('data/'.$_POST['id']);
header('Location: /index.php');
?>

unlink를 통해 내용을 삭제할 수 있다.

 

파일의 모듈화 - require

- 중복의 제거

재사용할만한 코드를 정리정돈하여 사용

<?php
require('lib/print.php'); //재사용할만한 코드 정리
?>

-> 모든 페이지를 통합적으로 관리할 수 있다.

 

cf) 한번 만들어진 함수는 다시 재정의할 수 없다. -> error

-> 해결방법 : require을 require_once로 변경

 

보안 XSS

> Cross Site Scripting : 웹사이트에 스크립트 태그를 주입하는 것

<script>
location.href="https://opentutorials.org/course/";
</script>

위와 같은 코드를 작성하여 버튼을 누르면 아예 다른 웹페이지로 넘어가게 된다.

 

> 문제점

- 로그인을 대신 하는 경우 발생

- 글을 지우는 경우 발생

- 정보 유출 경우 발생

 

-> 사용자가 입력한 정보는 모두 불신해야 한다.

 

> 예방 방법

<?php
echo htmlspecialchars('<script>alert("babo");</script>');
?>

'<'를 특수한 코드로 바꾸어버려 그 자바스크립트를 인식하지 못하도록 한다.

 

보안 파일 경로 보호

 

<?php
function print_title(){
  if(isset($_GET['id'])){
    echo htmlspecialchars($_GET['id']);
  } else {
    echo "Welcome";
  }
}
function print_description(){
  if(isset($_GET['id'])){
    $basename = basename($_GET['id']);
    echo htmlspecialchars(file_get_contents("data/".$basename));
  } else {
    echo "Hello, PHP";
  }
}
function print_list(){
  $list = scandir('./data');
  $i = 0;
  while($i < count($list)){
    $title = htmlspecialchars($list[$i]);
    if($list[$i] != '.') {
      if($list[$i] != '..') {
        echo "<li><a href=\"index.php?id=$title\">$title</a></li>\n";
      }
    }
    $i = $i + 1;
  }
}
?>

- basename 함수 : 파일의 경로에서 파일명을 추출해주는 함수

이를 이용해 부모디렉토리로 가는 등의 악용을 막을 수 있다.

 

'Web Hacking > WEB Hacking 기초' 카테고리의 다른 글

[SISS] XSS Game 05, 06  (0) 2022.01.22
[SISS] XSS Game 03, 04  (0) 2022.01.10
[SISS] 생활코딩 DATABASE-MySQL 정리  (0) 2022.01.08
[SISS] XSS Game 01, 02  (0) 2022.01.03
[SISS] XSS 공부  (0) 2021.12.31

+ Recent posts