-보안공격인 XSS(Cross-Site Scripting)에 대해 알아보고 이를 파이썬에서 막는 방법을 살펴본다.
-CSRF(Cross-Site Request Forgery)와의 차이점을 간단하게 살펴본다.
-생활코딩 파이썬 강의를 바탕으로 학습 및 보충학습 하였다.
-파이썬은 3.9.2 ver를 사용한다.
XSS란?
가장 흔한 보안 공격 중 하나로 공격자가 웹사이트에 스크립트 태그(<script/>)를 사용하여 쿠키탈취나 특정 코드를 실행하여 공격하는 보안 공격을 말한다. 학습 중 CSRF(Cross-Site Request Forgery)라는 보안 공격이 생각나서 차이점을 찾아보았다.
CSRF의 개념 및 XSS와 CSRF 차이점
CSRF는 해석하면 사이트 간 요청 위조이다. 사용자가 자신의 의지와 무관하게 공격자가 의도한 특정 행위(수정,삭제,등록 등)을 특정 웹사이트에 요청하게 하는 공격이다.
차이점은 다음과 같다.
XSS | CSRF |
1.공격대상이 클라이언트이다. 2.사이트변조, 백도어 등으로 클라이언트에 대한 악성공격 |
1.공격대상이 서버이다. 2.요청을 위조하여 사용자 권한을 이용해 서버에 대한 악성공격 |
XSS 공격 예시
아래와 같이 글을 쓴 후 저장해본다.
저 상태에서 제출(저장)을 하면 스크립트 코드가 실행되어 생성된 XSS Attack 목록을 누를 때마다 'XSS Attack!'이라는 alert창이 뜨게 된다.
위와 같이 스크립트 태그가 실행된다는 점을 응용하여 특정 사이트로 보내버리거나(location.href) 쿠키를 보여주는 등 (document.cookie) 여러가지 보안 공격을 할 수 있다. 보통 웹사이트들은 이런 취약 공격에 대처하기 위해 여러가지 XSS 방어 방법을 사용하여 보안을 강화한다.
XSS 방어 방법 - 치환하기
가장 기본적인 방법으로 각 언어마다 갖고 있는 replace() 함수를 활용하여 '<'나 '>' 등의 특수문자를 HTML Entity(HTML 문자참조)로 변환하여 사용하는 것이다. HTML Entity는 특정한 문자들(< & " , >등)이 HTML 태그로 예약되어 있기 때문에 마크업문자와 충돌을 방지하기 위해 쓰이는 문자들이다. 예를들어 <는 <라고 입력하면 실제 사용자에게는 <로 보여지지만 HTML 문서에서는 <라고 보여지기 때문에 일반문자로 인식되어 스크립트 실행이 되지 않는다.
파이썬 예제에서 특수문자 치환은 아래와 같이 한다.(이전 파이썬 포스팅 예제 이어서 사용)
index.py 일부
#3.a태그 클릭시 id값에 따른 pageId 분기처리
form = cgi.FieldStorage()
if 'id' in form:
title = pageId = form["id"].value
description = open('data/'+pageId,'r').read() #open함수로 내용 불러오기
description = description.replace('<','<') #XSS공격을 막기 위한 특수문자 치환
description = description.replace('<','>') #XSS공격을 막기 위한 특수문자 치환
update_link = '<a href="update.py?id={}">update</a>'.format(pageId)
delete_action= '''
<form action="process_delete.py" method="post">
<input type="hidden" name="pageId" value="{}">
<input type="submit" value="delete">
</form>
'''.format(pageId) #delete버튼을 form방식으로 만든다
else :
title = pageId = 'welcome'
description = 'Welcome!'
update_link = ''
delete_action = ''
예제의 index.py에서 목록메뉴를 누를 때마다 실행되는 코드이다. open() 함수로 파일 내용을 읽어온 후, replace 처리를 해주어 특수문자를 일반문자로 해석하게 변경한 후 보여준다. 이러면 script태그가 실행되지 않고 아래와 같이 일반문자로 보이게 된다.
XSS 방어 방법 - HTML_Sanitizer 사용하기
XSS를 방어하기 위해 html_sanitizer라는 패키지를 사용할 수도 있다. 이를 사용하기 위해서 Pypi에서 패키지를 다운로드 받아야 한다.
Pypi는 Python Package Index의 약자로 파이썬으로 만든 각종 패키지들을 다운로드 받을 수 있는 저장소이다. pip라는 명령어를 통해 Pypi에서 원하는 패키지를 받을 수 있다.
윈도우 사용자이기 때문에 CMD창에서 다음과 같이 pip install html_sanitizer라고 입력하면 설치된다. 이미 설치한 경우 아래와 같이 Requirement already satisfied라고 뜬다.
설치할 때 defaulting to user installation because normal site-packages is not writeable라는 에러가 발생하였었는데, 관리자 권한으로 실행하니 설치가 되었다. 또한 설치 이후에 제대로 패키지가 실행되지 않았는데, 기존에 이전 버전 파이썬이 중복 설치되어 있었다. 이런 점들을 잘 확인한 후 설치하면 정상적으로 설치가 될 것이다.
아래와 같이 index.py 일부를 html_sanitizer를 사용하여 수정한다.
index.py 일부
#1.모듈
import cgi, os, view, html_sanitizer #html_sanitizer를 import
sanitizer = html_sanitizer.Sanitizer() #sanitizer사용
#3.a태그 클릭시 id값에 따른 pageId 분기처리
form = cgi.FieldStorage()
if 'id' in form:
title = pageId = form["id"].value
description = open('data/'+pageId,'r').read() #open함수로 내용 불러오기
#description = description.replace('<','<')
#description = description.replace('<','>')
description = sanitizer.sanitize(description) #sanitizer사용
update_link = '<a href="update.py?id={}">update</a>'.format(pageId)
delete_action= '''
<form action="process_delete.py" method="post">
<input type="hidden" name="pageId" value="{}">
<input type="submit" value="delete">
</form>
'''.format(pageId) #delete버튼을 form방식으로 만든다
else :
title = pageId = 'welcome'
description = 'Welcome!'
update_link = ''
delete_action = ''
html_sanitizer를 import한 후, description을 sanitize함수 인자로 넣어서 사용한다. replace치환없이도 XSS가 실행되지 않는 것을 확인할 수 있다. 또한 title이나 기타 XSS공격을 받을 수 있는 부분은 모두 처리해주는 것이 좋다. 최종적인 index.py는 다음과 같다.
index.py
#!Python
print("Content-Type: text/html")
print()
#1.모듈
import cgi, os, view, html_sanitizer #html_sanitizer를 import
sanitizer = html_sanitizer.Sanitizer() #sanitizer사용
#3.a태그 클릭시 id값에 따른 pageId 분기처리
form = cgi.FieldStorage()
if 'id' in form:
title = pageId = form["id"].value
description = open('data/'+pageId,'r').read() #open함수로 내용 불러오기
#description = description.replace('<','<')
#description = description.replace('<','>')
description = sanitizer.sanitize(description) #sanitizer사용
title = sanitizer.sanitize(title) #sanitizer사용
update_link = '<a href="update.py?id={}">update</a>'.format(pageId)
delete_action= '''
<form action="process_delete.py" method="post">
<input type="hidden" name="pageId" value="{}">
<input type="submit" value="delete">
</form>
'''.format(pageId) #delete버튼을 form방식으로 만든다
else :
title = pageId = 'welcome'
description = 'Welcome!'
update_link = ''
delete_action = ''
#4.화면 그리기
print('''<!doctype html>
<html>
<head>
<title>WEB1 - Welcome</title>
<meta charset="utf-8">
</head>
<body>
<h1><a href="index.py">WEB</a></h1>
<ol>
{listStr}
</ol>
<a href="create.py">create</a>
{update_link}
{delete_action}
<h2>{title}</h2>
<p>{desc}
</p>
</body>
</html>
'''.format(
title=title,
desc=description,
listStr=view.getList(), #view모듈에서 getList() 호출
update_link=update_link,
delete_action=delete_action))
'개발자 일지 > Phython' 카테고리의 다른 글
[인프런]파이썬 알고리즘 기초 문법 정리2 (0) | 2021.04.18 |
---|---|
[인프런]파이썬 알고리즘 기초 문법 정리1 (0) | 2021.04.11 |
[파이썬 기초]함수,모듈 작성법 및 활용 (0) | 2021.03.28 |
[파이썬 기초]form 데이터 전송 및 처리방법(CRUD-Delete) (0) | 2021.03.24 |
[파이썬 기초]form 데이터 전송 및 처리방법(CRUD-Update) (0) | 2021.03.24 |
[파이썬 기초]form 데이터 전송 및 처리방법(CRUD-Create,Read) (0) | 2021.03.21 |
[파이썬 기초]반복문(for,range,while) 및 반복문 활용 (0) | 2021.03.19 |
[파이썬 기초]데이터타입 - list, 기타 컨테이너 타입(튜플,딕셔너리) (0) | 2021.03.16 |