안녕하세요. 휴먼스케이프의 개발자 김병하입니다.
이 번 포스트에서는 잘 알려져있지만 그만큼 간과하고 넘어가기도 쉬운 XSS와 CSRF 공격에 대해서 알아보겠습니다.
XSS 공격이란?
XSS(Cross-site Scripting)는 웹사이트에서 의도치 않은 스크립트를 넣는 기법을 말합니다.
웹 애플리케이션 보안 연구재단인 OWASP에 따르면 “크로스 사이트 스크립팅(XSS)는 애플리케이션에서 브라우저로 전송하는 페이지에서 사용자가 입력하는 데이터를 검증하지 않거나, 출력 시 위험 데이터를 무효화 시키지 않을 때 발생한다”라고 설명합니다.
게시판에 글을 올릴 때, 스크립트가 포함된 게시글을 올려서 게시글을 열어보는 유저의 브라우저에서 원치 않는 스크립트를 실행하게 할 수 있습니다. 이런 방식으로 유저의 쿠키 정보를 탈취하거나, 유저 비밀번호를 변경하는 api를 호출하는 식의 행위를 할 수 있습니다.
예를 들어, 게시글에
와 같은 태그를 넣게 되면, 게시판을 열어보는 모든 유저는 의도치 않게 아쟁총각의 노래를 들어야만 합니다.
특정 사이트에서 실행되는 스크립트를 사용자(희생자)의 브라우저가 신뢰하는 점을 노린 공격이라 할 수 있습니다.
XSS 공격 기법
스크립트 태그로 자바스크립트 실행
링크 태그로 자바스크립트 실행
링크
이벤트 속성으로 자바스크립트 실행
임의 태그의 이벤트 속성으로 자바스크립트 실행(이벤트 속성 목록 참고)
휴먼
일부 브라우저에서 javascript: 링크 사이에 공백 문자가 들어갈 수 있고, HTML 인코드를 해도 디코드된 내용이 출력된다는 점을 이용. HTML 인코드한 태그를 삽입하여 자바스크립트 실행
<a href="javascript:alert('hello world')">링크</a>
document.cookie와 같은 특정 단어를 막을 경우, 자바스크립트 난독화(ex aaaencode)를 한 태그를 삽입하여 스크립트 실행
゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]=''';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚ー゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');
XSS 방어 기법
데이터를 입력할 때, DB에 insert할 때, select할 때, 출력할 때 모두 필터를 거치게 하여 XSS 공격을 방어할 수 있습니다.
간단히 생각해서 데이터를 이스케이프하여 모든 태그를 막으면 원천적으로 봉쇄할 수 있지만, 이 경우는 모든 HTML 태그를 막아버리기 때문에, 대부분의 사이트에서 처럼 스타일을 먹여야 하는 경우에는 적용할 수 없습니다.
그렇기 때문에 기본적으로 모든 태그를 막고, 사이트에 필요한 일부 태그만 허용하는 방식으로 필터를 제작할 수 있습니다.
또는 OWASP Antisamy나 NAVER Lucy XSS Filter와 같은 신뢰할 수 있는 기존 라이브러리를 사용하는 것도 좋은 방법입니다.
Django의 XSS 방어
Django 프레임워크는 HTML 템플릿에 랜더 되는 텍스트는 자동 이스케이프(Automatic HTML escaping)를 적용하여 XSS 공격을 방지합니다. 자동 이스케이프 적용시, 스타일에 필요한 태그는 그대로 랜더하고, 위에서 기술하거나 그 외에 알려진 XSS 공격 시도는 이스케이핑하여 XSS 공격을 무력화합니다.
신뢰할 수 있는 데이터의 경우 아래와 같이 safe 템플릿 태그를 이용하여 자동 이스케이프를 거치지 않게 할 수 있습니다.
{{ text | safe }}
혹은, 블럭 단위로 자동 이스케이프를 무효화하고 싶을 경우 아래와 같이 autoescape 템플릿 태그를 이용할 수 있습니다.
{% autoescape off %} {{ title|escape }} // auto escape 적용 {{ text }} // auto escape 적용 안됨 {% endautoescape %}
CSRF 공격이란?
CSRF(Cross-Site Request Forgery)는 사이트 사용자(희생자)가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 만드는 공격입니다. 해커(공격자)는 CSRF를 통해 사용자의 권한을 도용하여 의도하지 않은 기능을 실행하게 만듭니다.
2008년에 발생한 옥션의 개인정보 유출 사건에서도 관리자 계정을 탈취하는 데 이 방법이 사용되었습니다.
예를 들어, www.csrf.io 라는 사이트에서 회원 비밀번호를 수정하는 api를 www.csrf.io/user/reset?id=ddd&password=1111 라는 식으로 제공한다면, XSS 공격이나 이메일을 통해, 해당 사이트에 로그인한 유저가 api를 호출하게 만들어서 사용자의 비밀번호를 수정하게 만들 수 있습니다.
XSS를 이용한 공격이 사용자가 특정 웹사이트를 신용하는 점을 노린 것이라면, 사이트간 요청 위조는 특정 웹사이트가 사용자의 웹 브라우저를 신용하는 상태를 노린 것이라 할 수 있습니다.
CSRF 방어 기법
Referer 체크
HTTP 헤더에 있는 referer 정보를 체크하여, 해당 요청이 신뢰할만한 페이지에서 발생한 것인지 확인합니다. 단 referer 정보는 조작이 가능하다는 단점이 있습니다.
토큰 발급
로그인한 유저에게 토큰을 발급하여, 요청을 보낼 때 해당 토큰을 함께 보내야만 요청을 실행합니다.
CAPTCHA
특정 요청을 처리할 때, CAPTCHA 단어를 요청과 함께 보내도록 하여 의도한 페이지에서 보내는 요청인지 확인합니다.
Django의 CSRF 방어
Django에서는 페이지를 제공할 때, 쿠키에 csrf token을 함께 제공하여 해당 Django 웹 어플리케이션에서 제공한 페이지에서만 기능을 실행하도록 하여 CSRF 공격을 방지합니다.
앱에서 api를 사용하거나, 브라우저에서 쿠키 사용을 허용하지 않는 등의 이유로 Django에서 기본적으로 제공하는 csrf token을 사용할 수 없을 땐, 토큰을 별도로 만들어서 CSRF 공격을 방지할 수 있습니다.
이 때는, 해당 기능을 실행할 때 Django csrf token을 검증하지 않도록 아래와 같이 예외 처리를 해줘야 합니다.
@csrf_exempt def reset_password(request):
마무리
잘 알려진 웹 취약점 공격 중 XSS와 CSRF에 대해서 알아봤습니다. 유저의 소중한 정보를 다루는 만큼 보안은 아무리 신경써도 과하지 않은 것 같습니다.
제 포스팅에서 부족한 부분은 댓글로 지적 부탁드립니다.
감사합니다.
Get to know us better! Join our official channels below.
Telegram(EN) : t.me/Humanscape KakaoTalk(KR) : open.kakao.com/o/gqbUQEM Website : humanscape.io Medium : medium.com/humanscape-ico Facebook : www.facebook.com/humanscape Twitter : twitter.com/Humanscape_io Reddit : https://www.reddit.com/r/Humanscape_official Bitcointalk announcement : https://bit.ly/2rVsP4T Email : support@humanscape.io