XSS / CSRF
서버에서 받아온 데이터를 그냥 innerHTML로 할당하는 것은 지양해야 한다.
XSS
- https://github.com/naver/lucy-xss-filter
- 직접 LucyFilter 객체 가져와서 메서드 불러
dirty -> escaped
로 만들어야 함. - 직접 달아줘야 하기 때문에 달아야 하는 곳에 안달거나, 안달아야 하는 곳에 다는 경우가 있을 수 있음.
- https://github.com/naver/lucy-xss-servlet-filter
- XSS 체크가 요청 파라미터로 넘어오는 모든 것들에 대해서 일괄 적용됨
- 비즈니스 로직에 XSS 체크가 들어가지 않아도 된다!
- https://www.npmjs.com/package/sanitize-html근데 이거 쫌 무겁다.
- https://www.npmjs.com/package/dompurify요건 가벼움.
CSRF
- CSRF의 핵심은 “해당 스크립트를 실행한 클라이언트의 세션으로 서버에 요청한다” 이다.
- 스크립트를 실행하는 클라이언트의 쿠키, 세션, 권한으로 서버에 요청.
브라우저가 페이지를 파싱하다 <img src="URL">
를 만나면 서버에 해당 URL
을 요청하게 되는데, 원래 페이지에 대한 요청과 이 요청 사이의 차이점은 URL이 다르다는 것 뿐이다. 즉, img tag
에 지정된 request도 동일하게 처리한다.
GET method를 사용하는 경우 url로 파라미터를 넘길 수 있기 때문에 src
attribute에 파라미터를 포함한 url을 적는 방법이 많이 쓰이며 이를 transclude라고 한다.
실제 악성파일을 분석하며 가장 흔하게 봤던 유형은 이미지 내에 삽입된 iframe
이었고 대체로 일단 컨트롤 할 수 있는 악성 사이트로 redirect 시키는 방법이 사용되었다. 그래야 헤더 등등을 조작할 수 있으니까.
공격자가 다음과 같은 코드를 미리 작성해 놓으면, 코드를 파싱하는 victim은 서버에 펜 50개를 구매하겠다는 request를 보내게 된다.
1
<img src="http://store.example.org/buy.php?item=pen&quantity=50" />
공격자의 의도 대로 victim의 권한으로 서버에 요청하는 것을 막으려면 token
을 발급하고, client에서 request 시 token
포함하도록 구성한다. 그리고, GET이 아니라 POST 를 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
session\_start();
$token = md5(uniqid(rand(), TRUE));
$\_SESSION['token'] = $token;
$\_SESSION['token\_time'] = time();
?>
<form action="buy.php" method="POST">
<input type="hidden" name="token" value="<?= $token?>"/>
...
</form>
* pw hash가 아니기 때문에 md5를 사용해도 상관 없다. pw hash의 경우는 안전한 hash algorithm에 salt도 추가해서 사용해야 한다.
근데 어차피 token
은 서버에 저장되는건데, 굳이 <?= $token?>
으로 client에 보낸 다음 다시 hidden
으로 이를 받을 필요가 있나 싶지만 토큰을 단순히 서버에서 가지고만 있는 것은 아무 소용이 없다.
중요한 것은 client가 전송하는 요청이 공격자가 미리 만들어 놓은 위조된 요청 인지 아닌지를 확인하는 것이다. token
은 각 사용자마다 다르게 발급되기 때문에 공격자가 미리 만들어 놓을 수는 없다.
1
2
3
4
5
if (isset($\_SESSION['token'] &&
($\_POST['token'] == $\_SESSION['token']) &&
(time() - $\_SESSION['token\_time']) <= 300) {
....
}