XSS(크로스 사이트 스크립트) 란?
- 검증되지 않은 입력 값으로 인해 사용자의 웹 브라우저에서 의도하지 않은 악성 스크립트가 실행되는 취약점
- 외부 입력이 동적 웹 페이지 생성에 사용될 경우, 전송된 동적 웹 페이지를 열람하는 접속자의 권한으로 부적절한 스크립트가 수행되는 취약점
- 공격을 통해 사용자의 개인정보 및 쿠키정보 탈취, 악성코드 감염, 웹 페이지 변조 등이 발생
- 공격 대상은 서버가 아니라, 클라이언트이다.
https://github.com/naver/lucy-xss-servlet-filter
의존성 설정
<dependency>
<groupId>com.navercorp.lucy</groupId>
<artifactId>lucy-xss-servlet</artifactId>
<version>2.0.0</version>
</dependency>
lucy-xss-servlet-filter-rule.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.navercorp.com/lucy-xss-servlet">
<defenders>
<!-- XssPreventer 등록 -->
<defender>
<name>xssPreventerDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssPreventerDefender</class>
</defender>
<!-- XssSaxFilter 등록 -->
<defender>
<name>xssSaxFilterDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssSaxFilterDefender</class>
<init-param>
<param-value>lucy-xss-superset-sax.xml</param-value> <!-- lucy-xss-filter의 sax용 설정파일 -->
<param-value>false</param-value> <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
</init-param>
</defender>
<!-- XssFilter 등록 -->
<defender>
<name>xssFilterDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssFilterDefender</class>
<init-param>
<param-value>lucy-xss.xml</param-value> <!-- lucy-xss-filter의 dom용 설정파일 -->
<param-value>false</param-value> <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
</init-param>
</defender>
<defender>
<name>xssFilterDefender</name>
<class>com.navercorp.lucy.security.xss.servletfilter.defender.XssFilterDefender</class>
<init-param>
<param-value>lucy-xss.xml</param-value> <!-- lucy-xss-filter의 dom용 설정파일 -->
<param-value>false</param-value> <!-- 필터링된 코멘트를 남길지 여부, 성능 효율상 false 추천 -->
</init-param>
</defender>
</defenders>
<!-- default defender 선언, 필터링 시 지정한 defender가 없으면 여기 정의된 default defender를 사용해 필터링 한다. -->
<default>
<defender>xssPreventerDefender</defender>
</default>
<!-- global 필터링 룰 선언 -->
<global>
<!-- 모든 url에서 들어오는 globalParameter 파라메터는 필터링 되지 않으며
또한 globalPrefixParameter1로 시작하는 파라메터도 필터링 되지 않는다.
globalPrefixParameter2는 필터링 되며 globalPrefixParameter3은 필터링 되지 않지만
더 정확한 표현이 가능하므로 globalPrefixParameter2, globalPrefixParameter3과 같은 불분명한 표현은 사용하지 않는 것이 좋다. -->
<params>
<param name="globalParameter" useDefender="false" />
<param name="globalPrefixParameter1" usePrefix="true" useDefender="false" />
<param name="globalPrefixParameter2" usePrefix="true" />
<param name="globalPrefixParameter3" usePrefix="false" useDefender="false" />
</params>
</global>
<!-- url 별 필터링 룰 선언 -->
<url-rule-set>
<!-- url disable이 true이면 지정한 url 내의 모든 파라메터는 필터링 되지 않는다. -->
<!-- <url-rule>
<url disable="true">/login/login/loginAjax</url>
</url-rule> -->
</url-rule-set>
</config>
lucy-xss-sax.xml
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns="http://www.nhncorp.com/lucy-xss"
extends="lucy-xss-default-sax.xml">
<elementRule>
<element name="body" disable="true" /> <!-- <BODY ONLOAD=alert("XSS")>, <BODY BACKGROUND="javascript:alert('XSS')"> -->
<element name="embed" disable="true" />
<element name="iframe" disable="true" /> <!-- <IFRAME SRC=”http://hacker-site.com/xss.html”> -->
<element name="meta" disable="true" />
<element name="object" disable="true" />
<element name="script" disable="true" /> <!-- <SCRIPT> alert(“XSS”); </SCRIPT> -->
<element name="style" disable="true" />
<element name="link" disable="true" />
<element name="base" disable="true" />
</elementRule>
<attributeRule>
<attribute name="data" base64Decoding="true">
<notAllowedPattern><![CDATA[(?i:s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
<notAllowedPattern><![CDATA[(?i:d\\*a\\*t\\*a\\*:)]]></notAllowedPattern>
<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
</attribute>
<attribute name="src" base64Decoding="true">
<notAllowedPattern><![CDATA[(?i:s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
<notAllowedPattern><![CDATA[(?i:d\\*a\\*t\\*a\\*:)]]></notAllowedPattern>
<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
</attribute>
<attribute name="style">
<notAllowedPattern><![CDATA[(?i:j\\*a\\*v\\*a\\*s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
<notAllowedPattern><![CDATA[(?i:e\\*x\\*p\\*r\\*e\\*s\\*s\\*i\\*o\\*n)]]></notAllowedPattern>
<notAllowedPattern><![CDATA[&[#\\%x]+[\da-fA-F][\da-fA-F]+]]></notAllowedPattern>
</attribute>
<attribute name="href">
<notAllowedPattern><![CDATA[(?i:j\\*a\\*v\\*a\\*s\\*c\\*r\\*i\\*p\\*t\\*:)]]></notAllowedPattern>
</attribute>
</attributeRule>
</config>
네이버 lucy 한계 .. 필요하다면 직접 스크립트 단에서 막아야 한다. form 태그에서 가능하다. 하지만 요청 json 형태로 들어오면 불가능 !!!
board.js
let index = {
init: function() {
$("#btn--save").bind("click", () => {
this.save();
});
$("#btn--delete").bind("click", () => {
this.deleteById();
});
$("#btn--update").bind("click", () => {
this.update();
});
$("#btn-reply-save").bind("click", () => {
this.replySave();
});
},
save : function() {
let xCheckTitle = XSSCheck( $("#title").val());
let data = {
title: xCheckTitle,
content: $("#content").val()
};
// ajax 통신 요청
$.ajax({
type:"POST",
url: "/api/board",
data: JSON.stringify(data),
contentType : "application/json; charset=utf-8",
dataType: "json"
}).done(function(data, textSatus, xhr) {
if(data.status == "OK") {
alert("글쓰기 성공");
location.href = "/";
}
}).fail((error) => {
console.log(error);
alert(error.responseJSON.error);
} );
},
deleteById: function () {
let id = $("#board-id").val();
// 통신 ---> ajax
$.ajax({
type: "DELETE",
url: "/api/board/" + id
}).done(function(data, textStatus, xhr) {
if(data.status == "OK") {
alert("글 삭제가 완료 되었습니다");
location.href = "/";
}
}).fail(function(error) {
alert("글 삭제하기에 실패 하였습니다");
});
},
update: function() {
// HTML 태그에 직접 속성을 정의할 수 있다. 규칙은 data-*
// data-* 값을 가지고 오기 위해서 Jquery --> (선택자).attr("data-[id]")
let boardId = $("#board-id").attr("data-id");
let data = {
title : $("#title").val(),
content : $("#content").val()
}
$.ajax({
type: "PUT",
url : "/api/board/" + boardId,
data : JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json"
}).done(function(data, textStatus, xhr) {
if(data.status) {
alert("글 수정이 완료 되었습니다");
location.href = "/";
}
}).fail(function(error) {
console.log(error);
alert("글 수정에 실패 하였습니다");
});
},
replySave : function() {
let replyData = {
boardId: $("#board-id").val(), // fk (board pk )
content: $("#content").val()
};
// ajax 통신 요청
$.ajax({
type:"POST",
url: `/api/board/${replyData.boardId}/reply`,
data: JSON.stringify(replyData),
contentType : "application/json; charset=utf-8",
dataType: "json"
}).done(function(data, textSatus, xhr) {
if(data.status == "OK") {
alert("댓글 작성이 완료 되었습니다");
location.href = `/board/${replyData.boardId}`;
}
}).fail((error) => {
console.log(error);
alert("댓글 작성에 실패 하였습니다");
} );
},
replyDelete: function(boardId, replyId) {
$.ajax({
type: 'DELETE',
url: `/api/board/${boardId}/reply/${replyId}`,
dataType: 'json'
}).done(function(resData) {
if(resData.status == "OK") {
alert("댓글 삭제 성공 하였습니다");
location.href = `/board/${boardId}`
}
}).fail(function(error) {
alert("댓글 삭제 실패 ");
});
}
}
function XSSCheck(str, level) {
if (level == undefined || level == 0) {
str = str.replace(/\<|\>|\"|\'|\%|\;|\(|\)|\&|\+|\-/g,"");
} else if (level != undefined && level == 1) {
str = str.replace(/\</g, "<");
str = str.replace(/\>/g, ">");
}
return str;
}
index.init();
'개발일지 > 스프링' 카테고리의 다른 글
csrf적용한 로그인(아웃), 회원가입,댓글(작,삭),게시글(작,수,삭),회원정보(수정) (1) | 2022.12.20 |
---|---|
spring boot 댓글 삭제기능 (0) | 2022.12.19 |
카카오 로그인 기능 생성 및 셋팅(인가코드 발급받기, 토큰발급받기) (0) | 2022.12.15 |
스프링 RestTemplate (0) | 2022.12.15 |
JPA 네이밍전략, 네이티브 쿼리 사용하기 (0) | 2022.12.12 |
댓글