๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์ผ/javascript

JSP + JavaScript ํ™˜๊ฒฝ์—์„œ XSS ๋ฐฉ์–ด ์‹คํŒจ ์›์ธ๊ณผ ํ•ด๊ฒฐ

๐Ÿ“Œ JSP + JavaScript ํ™˜๊ฒฝ์—์„œ XSS ๋ฐฉ์–ด ์‹คํŒจ ์›์ธ๊ณผ ํ•ด๊ฒฐ

1. ๋ฌธ์ œ ์ƒํ™ฉ

  • JSP์—์„œ ${ajaxId} ๊ฐ’์„ JavaScript ๋ฐ HTML์— ์ „๋‹ฌ
  • <c:out> ๋ฐ hidden input ์‚ฌ์šฉํ–ˆ์Œ์—๋„ XSS ๋ฐฉ์–ด ์‹คํŒจ
  • ์˜ˆ:
ajaxId: '<c:out value="${ajaxId}"/>'
 

2. ์›์ธ ๋ถ„์„

๐Ÿ”ฅ (1) ์ปจํ…์ŠคํŠธ ๋ถˆ์ผ์น˜ (ํ•ต์‹ฌ ์›์ธ)

  • <c:out>์€ HTML escape๋งŒ ์ˆ˜ํ–‰
  • ํ•˜์ง€๋งŒ ์•„๋ž˜๋Š” JavaScript ๋ฌธ์ž์—ด ์ปจํ…์ŠคํŠธ
'${ajaxId}'
 

๐Ÿ‘‰ HTML escape ≠ JavaScript escape
→ XSS ๋ฐฉ์–ด ์‹คํŒจ


๐Ÿ”ฅ (2) EL ์ง์ ‘ ์ถœ๋ ฅ (${ajaxId})

 
<input value="${ajaxId}">
 
  • EL์€ escape ์—†์Œ
  • ์•…์„ฑ ๊ฐ’ ์‚ฝ์ž… ์‹œ ๊ทธ๋Œ€๋กœ DOM์— ๋ฐ˜์˜

๐Ÿ”ฅ (3) ์„œ๋ฒ„ ์ธก ๊ฒ€์ฆ ๋ถ€์žฌ

  • ajaxId์— ๋Œ€ํ•œ ์ œํ•œ ์—†์Œ
  • ์˜ˆ:
"><script>alert(1)</script>
 

๐Ÿ‘‰ escape ์ด์ „์— ์ž…๋ ฅ ์ž์ฒด๋ฅผ ์‹ ๋ขฐํ•˜๋ฉด ์•ˆ ๋จ


3. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

โœ… (1) JavaScript ์ง์ ‘ ์‚ฝ์ž… ์ œ๊ฑฐ (๊ฐ€์žฅ ์ค‘์š”)

โŒ ์ž˜๋ชป๋œ ๋ฐฉ์‹

ajaxId: '${ajaxId}'
 

โœ… ๊ฐœ์„ 

var ajaxId = document.querySelector('input[name="ajaxId"]').value;
 

๐Ÿ‘‰ DOM ๊ธฐ๋ฐ˜ ์ ‘๊ทผ์œผ๋กœ ์ „ํ™˜


โœ… (2) JSP ์ถœ๋ ฅ ์‹œ escape ์ ์šฉ

 
<input type="hidden" name="ajaxId"
value="<c:out value='${fn:escapeXml(ajaxId)}'/>"/>
 

๐Ÿ‘‰ HTML ์ปจํ…์ŠคํŠธ ์•ˆ์ „์„ฑ ํ™•๋ณด


โœ… (3) ์„œ๋ฒ„ ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์ถ”๊ฐ€ (ํ•„์ˆ˜)

if (!ajaxId.matches("^[a-zA-Z0-9_-]+$")) {
	throw new IllegalArgumentException("Invalid ajaxId");
}
 

๐Ÿ‘‰ ๊ณต๊ฒฉ ๋ฒกํ„ฐ ์›์ฒœ ์ฐจ๋‹จ


โœ… (4) ์—ญํ•  ๋ถ„๋ฆฌ ์›์น™ ์ ์šฉ

์˜์—ญ์ฑ…์ž„
์„œ๋ฒ„ ์ž…๋ ฅ๊ฐ’ ๊ฒ€์ฆ (Validation)
JSP ์ถœ๋ ฅ ์‹œ escape
JavaScript ๋ฐ์ดํ„ฐ ์ง์ ‘ ์‚ฝ์ž… ๊ธˆ์ง€

4. ์ž˜๋ชป๋œ ๋Œ€์‘ ์‚ฌ๋ก€

๋ฐฉ๋ฒ•๋ฌธ์ œ
<c:out>๋งŒ ์‚ฌ์šฉ JS ์ปจํ…์ŠคํŠธ์—์„œ ๋ฌด๋ ฅ
hidden input ์‚ฌ์šฉ๋งŒ ๋ฏฟ์Œ ๊ฐ’ ์ž์ฒด๊ฐ€ ์˜ค์—ผ๋˜๋ฉด ๋ฌด์˜๋ฏธ
MultipartFilter ์ถ”๊ฐ€ XSS์™€ ๋ฌด๊ด€ (ํŒŒ์ผ ์—…๋กœ๋“œ์šฉ)

5. ์ตœ์ข… ๊ตฌ์กฐ (๊ถŒ์žฅ ํŒจํ„ด)

JSP

 
<input type="hidden" name="ajaxId"
value="<c:out value='${fn:escapeXml(ajaxId)}'/>"/>

JavaScript

 
const ajaxId = document.querySelector('input[name="ajaxId"]').value;
ajaxLoadHttpConn({
	ajaxId: ajaxId
});
 

Server

 
if (!ajaxId.matches("^[a-zA-Z0-9_-]+$")) {
	throw new SecurityException("Invalid ajaxId");
}

6. ํ•ต์‹ฌ ๊ตํ›ˆ

  • Escape๋Š” ๋งŒ๋Šฅ์ด ์•„๋‹ˆ๋‹ค (Context-aware escaping ํ•„์š”)
  • XSS ๋ฐฉ์ง€๋Š” ์ถœ๋ ฅ ๋‹จ๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ์ž…๋ ฅ + ์ถœ๋ ฅ ๋ชจ๋‘ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค
  • JavaScript ์ปจํ…์ŠคํŠธ์—์„œ๋Š” HTML escape๊ฐ€ ๋ฌด๋ ฅํ™”๋  ์ˆ˜ ์žˆ๋‹ค
  • ๋ฐ์ดํ„ฐ๋Š” ์ฝ”๋“œ์— ์‚ฝ์ž…ํ•˜์ง€ ๋ง๊ณ , DOM์„ ํ†ตํ•ด ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค
  • ๋ณด์•ˆ์€ ํ•„ํ„ฐ ํ•˜๋‚˜๋กœ ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š”๋‹ค (๋‹ค์ธต ๋ฐฉ์–ด ํ•„์š”)