들어가기전
프로젝트에 XSS 취약점을 보완하고 싶어 여러 방법을 생각해보았다. XSS보안 라이브러리를 사용 혹은 정규식으로 취약 문자열 제거 등 여러 방법을 고민을 하다 보안이 뛰어나지만 많은 부분을 생각하고 확인해야하는 라이브러리 말고 특정 문자열을 제거하는 방식으로 진행하게되었고 정리를 위해 포스팅을 하기로 했다.
XSS 공격은 여러가지 공격이 있다.
악성코드(악의적인 스크립트 등)을 URL, HTML, 태그 내 SRC, CSS 값, DOM 등 여러가지 공격 기법이 있어 그에 맞는 대응을 해야한다.
예를 들어 SRC같은 경우 로컬에 있는 경로 또는 화이트 리스트를 만들어 해당하는 URL이 아니라면 제거하는 방식이 필요하다.
HTML을 검증하는 부분은 태그의 값이 아닌 경우는 HTML Entity 인코딩 대응을 해야한다. 이 말은 <, >, ', " 과 같은 태그를 구성하는 특수문자의 경우 <>'" 와 같이 변환하여 HTML로 뿌려준다면 문자열로 인식하여 태그를 만들지 않는다. 이 방식은 따로 포스팅하지 않고 넘어가겠습니다.
이에 간단하게 아래와 같이 SRC, HTML 코드를 검증 하는 코드를 만들어 보았다.
Test Code
<img onpointerover=confirm`XSS` src="x" />
<img src="x" onpointerover=confirm`document.cookie`>
<img src=x onpointerover="window.location.href = 'http://www.abc.com/'">
<IMG """><SCRIPT>alert("XSS")</SCRIPT>"\/>
<a href="javascript:alert('XSS test')">XSS test</a>
<a href="javascript:alert`XSS test`">XSS test</a>
<a href="javascript:'XSS test')">XSS test</a>
<a href="javascript:alert`XSS test${document.cookie}`">XSS test</a>
<img src=x onpointerover=confirm`XSS`>
<img src=x onpointerover=confirm`document.cookie`>
<img src=x onpointerover="window.location.href = 'http://www.abc.com/'">
<svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'/>
<a onmouseover="alert(document.cookie)"\>xxs link\</a\>
<a onmouseover=alert(document.cookie)\>xxs link\</a\>
<SCRIPT>alert`XSS`</SCRIPT>
<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))/>
CKEditor와 같은 에디터를 이용해 코드를 저장하고 사용자 화면에서 보여주는 CMS 구조에는 XSS가 취약할 테니 보안에 신경써야한다고 생각한다!
실제로 위 코드로 CMS에 저장 후 사용자에서 확인했을 때 실행되는 코드가 있을 수 있다.
Example 및 설명
Matcher m;
ArrayList<Pattern> regs = new ArrayList<>();
// 태그 내 사용 금지 함수 및 단어
String blackList = "onload|onfocus|onerror|alert|confirm|prompt|document|window|cookie|session";
// 태그 내 허용 url 리스트
String whiteList = "localhost";
regs.add(Pattern.compile("(?i)<[^>]*("+ blackList +")[^<]*\\/?>", Pattern.DOTALL));
regs.add(Pattern.compile("(?i)(?!<[^>]*)https?\\:\\/\\/(?!(www.)?("+ whiteList +"))[^\'\"\\<\\>]+(?=[^<]*>)", Pattern.DOTALL));
regs.add(Pattern.compile("(?i)<(no)?script[^>]*>.*?</(no)?script>", Pattern.DOTALL));
for (Pattern reg : regs) {
m = reg.matcher(str);
str = m.replaceAll("");
}
return str;
제거할 패턴을 리스트에 넣고 반복문을 돌리면서 전달 받은 해당 문자열에 replace를 하는 방식으로 진행했다.
제거할 list가 많아질 것에 대비하여 작성했다. 정규식을 하나를 설명하자면
정규식 | 설명 |
(?!) | 대소문자 모두 포함 |
<[^>]* | 여는 꺽쇠가 있으면서 닫는 꺽쇠가 아닌 모든 문자가 0개 이상 |
https? | http가 들어가며 s가 있거나 없거나 |
\\:\\/\\/ | java에서 특수 문자를 표기하기 위해 역슬레시가 두개 필요 즉, :// <-를 찾기 위함 |
(?!(www.)?(리스트)) | (?!) 이부분은 negative lookahead로 괄호안에 있는 패턴(문자 혹은 숫자 등)이 아닌 것을 의미한다. 즉, 허용한 list가 아닌 것은 모두 걸린다. |
[^\'\"\\<\\>]+(?=[^<]*> | 홀따움표, 쌍따움표, 여는 꺽쇠, 닫는 꺽쇠가 아닌 문자가 1개 이상이면서 여는 꺽쇠가 아닌 문자가 0개 이상이고 닫는 꺽쇠가 있는 문자열 |
정확한 방법도 아니고 부족한 부분도 많지만 추후 리스트에 계속해서 제거할 문자열이 추가된다면 충분히 대응할 수 있지 않을까... 생각한다.
물론 혼자하는 프로젝트라면 라이브러리 쓰는게 더 좋아보입니다.
'Dev > JAVA' 카테고리의 다른 글
[JAVA] HttpConnect를 통해 API 호출 및 데이터 받기 (0) | 2023.11.09 |
---|---|
[JAVA] 간단한 java Mail 테스트 (메모장으로 메일 테스트) (0) | 2023.07.15 |