SAST๋Š” OWASP Top 10 ์ทจ์•ฝ์ ์„ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ์š”?

๋ณด์•ˆ์„ ์œ„ํ•œ ์ •์  ์ฝ”๋“œ ๋ถ„์„(SAST): SAST๋Š” OWASP Top 10 ์ทจ์•ฝ์ ์„ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ๊นŒ์š”?

๋ณด์•ˆ ์ทจ์•ฝ์ ์€ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์˜ˆ๋ฐฉํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ์‰ฝ์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ ๊ฒ€ํ†  ์ค‘์— ๋ฐœ๊ฒฌ๋œ SQL ์ธ์ ์…˜ ์ทจ์•ฝ์ ์€ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ ๋ช‡ ๋ถ„๋ฐ–์— ๊ฑธ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ ์œ ์ถœ ํ›„์— ๋ฐœ๊ฒฌ๋œ ๋™์ผํ•œ ์ทจ์•ฝ์ ์€ ์‚ฌ๊ณ  ๋Œ€์‘, ๊ทœ์ œ ์กฐ์‚ฌ, ๋ณต๊ตฌ ์ž‘์—…์— ๋ช‡ ์ฃผ๊ฐ€ ์†Œ์š”๋  ๋ฟ ์•„๋‹ˆ๋ผ ๊ทธ ์‚ฌ์ด์— ์œ ์ถœ๋œ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ์†์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •์  ์ฝ”๋“œ ๋ถ„์„์€ ์†Œ์Šค ์ฝ”๋“œ ๊ตฌ์กฐ, ๋ฐ์ดํ„ฐ ํ๋ฆ„, ํŒจํ„ด์„ ์•Œ๋ ค์ง„ ์ทจ์•ฝ์  ์‹œ๊ทธ๋‹ˆ์ฒ˜์™€ ๋น„๊ตํ•˜์—ฌ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ฒด๊ณ„์ ์œผ๋กœ ์ ์šฉํ•˜๋ฉด ๋ณด์•ˆ์„ ์‚ฌํ›„ ๋Œ€์‘์ ์ธ ๋ฐฉ์‹์—์„œ ๊ฐœ๋ฐœ ํ”„๋กœ์„ธ์Šค์— ๋‚ด์žฌ๋œ ์†์„ฑ์œผ๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

OWASP Top 10์€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ์— ์žˆ์–ด ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์œ„ํ—˜ ์š”์†Œ๋“ค์„ ์ •๋ฆฌํ•œ ๊ถŒ์œ„ ์žˆ๋Š” ๋ชฉ๋ก์œผ๋กœ, OWASP(Open Web Application Security Project)์—์„œ ์ˆ˜์ฒœ ๊ฐœ์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์‹ค์ œ ์ทจ์•ฝ์  ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ง€์†์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋ฉ๋‹ˆ๋‹ค. ๋ชฉ๋ก์— ์žˆ๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์€ ์ •์  ๋ถ„์„ ๋„๊ตฌ๋ฅผ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ์ˆ˜์ค€์œผ๋กœ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ๊ฐ OWASP ๋ฒ”์ฃผ๋ฅผ ์ •์  ๋ถ„์„ ๋„๊ตฌ๋กœ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜ ์š”์†Œ์™€ ์—ฐ๊ฒฐํ•˜๊ณ , ์ทจ์•ฝํ•œ ์ฝ”๋“œ ํŒจํ„ด๊ณผ ๊ทธ์— ์ƒ์‘ํ•˜๋Š” ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ๋ฉฐ, ๊ฐ ๊ธฐ๋ฒ•์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๋ฅผ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๊ณต๊ฒฉ์ž๋ณด๋‹ค ๋จผ์ € ์ฃผ์ž… ์ง€์ ์„ ์ฐพ์•„๋‚ด์„ธ์š”

SMART TS XL ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ API๋ถ€ํ„ฐ ์ž๋ฐ” ์„œ๋น„์Šค, COBOL ๋ฐฑ์—”๋“œ์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ์ทจ์•ฝ์ ์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

๋” ๋งŽ์€ ์ •๋ณด

์ฐจ๋ก€

์ •์  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ ํ…Œ์ŠคํŠธ(SAST)๋ž€ ๋ฌด์—‡์ธ๊ฐ€์š”?

์ •์  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ ํ…Œ์ŠคํŠธ(SAST)๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ์†Œ์Šค ์ฝ”๋“œ, ๋ฐ”์ดํŠธ์ฝ”๋“œ ๋˜๋Š” ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ถ„์„์€ ๋ฐ์ดํ„ฐ๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ ํ๋ฅด๋Š”์ง€, ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋–ค ๋ณด์•ˆ์— ๋ฏผ๊ฐํ•œ ์ž‘์—…์— ๋„๋‹ฌํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์™ธ๋ถ€ ์ž…๋ ฅ(์‚ฌ์šฉ์ž ์ž…๋ ฅ, HTTP ๋งค๊ฐœ๋ณ€์ˆ˜, ํŒŒ์ผ ๋‚ด์šฉ, ํ™˜๊ฒฝ ๋ณ€์ˆ˜)์—์„œ ์‹œ์ž‘๋œ ๊ฒฝ๋กœ๊ฐ€ ์ ์ ˆํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋˜๋Š” ๊ฒ€์ฆ ์—†์ด ์œ„ํ—˜ํ•œ ์ž‘์—…(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ, ์‹œ์Šคํ…œ ๋ช…๋ น, HTML ์ถœ๋ ฅ, ์•”ํ˜ธํ™” ํ•จ์ˆ˜)์œผ๋กœ ์ด์–ด์ง€๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.

SAST๋Š” ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ ํ”„๋กœ๊ทธ๋žจ์˜ ํ•œ ๊ณ„์ธต์ž…๋‹ˆ๋‹ค. SAST๊ฐ€ ์–ด๋–ค ์œ„์น˜๋ฅผ ์ฐจ์ง€ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ๋Œ€์•ˆ๋“ค๊ณผ ๋น„๊ตํ•ด ๋ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ ‘๊ทผ๊ทธ๊ฒƒ์ด ์‹คํ–‰๋  ๋•Œ๋ฐœ๊ฒฌํ•œ ๊ฒƒ์ด ์ž‘ํ’ˆ์ด ๋†“์นœ ์ 
SAST(์ •์ )์‹คํ–‰ ์ „, ์†Œ์Šค ์ฝ”๋“œ์—์„œ์ฝ”๋“œ ์ˆ˜์ค€ ์ทจ์•ฝ์ , ์ธ์ ์…˜ ํŒจํ„ด, ์•”ํ˜ธํ™” ์˜ค์šฉ, ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋น„๋ฐ€ ํ‚ค๋Ÿฐํƒ€์ž„์—๋งŒ ๋ฐœ์ƒํ•˜๋Š” ์ทจ์•ฝ์ , ๋ฐฐํฌ ์‹œ ๊ตฌ์„ฑ ๋ฌธ์ œ
DAST(๋™์ )์‹คํ–‰ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด๋Ÿฐํƒ€์ž„ ๋™์ž‘, ์ธ์ฆ ๊ฒฐํ•จ, ์„œ๋ฒ„ ๊ตฌ์„ฑ ๋ฌธ์ œํ…Œ์ŠคํŠธ ์ค‘์— ์ฝ”๋“œ ์ˆ˜์ค€ ํŒจํ„ด์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
SCA(์†Œํ”„ํŠธ์›จ์–ด ๊ตฌ์„ฑ ๋ถ„์„)์˜์กด์„ฑ ๋ฐœํ˜„ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋ฐœ๊ฒฌ๋œ ์•Œ๋ ค์ง„ CVE์‚ฌ์šฉ์ž ์ง€์ • ์ฝ”๋“œ ์ทจ์•ฝ์ 
IAST(๋Œ€ํ™”ํ˜•)๊ณ„์ธก์„ ์‚ฌ์šฉํ•œ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ค‘๋†’์€ ์ •ํ™•๋„๋กœ ๋Ÿฐํƒ€์ž„ ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฆ…๋‹ˆ๋‹ค.์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰์ด ํ•„์š”ํ•˜๋ฉฐ, ํ”ผ๋“œ๋ฐฑ ์†๋„๊ฐ€ ๋А๋ฆฝ๋‹ˆ๋‹ค.

SAST๋Š” ์ทจ์•ฝ์ ์ด ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์—, ์ฆ‰ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์ด๋‚˜ IDE์—์„œ์กฐ์ฐจ ๋ฐฐํฌ๋˜์ง€ ์•Š์€ ์ฝ”๋“œ์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ ๊ฐ€์žฅ ๋น ๋ฅธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์กฐ๊ธฐ ๋ฐœ๊ฒฌ์ด SAST์˜ ์ฃผ์š” ๋ณด์•ˆ ์žฅ์ ์ž…๋‹ˆ๋‹ค.

์ •์  ์ฝ”๋“œ ๋ถ„์„์€ ์–ด๋–ค ์œ ํ˜•์˜ ์œ„ํ˜‘์„ ์™„ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๋Š” SAST์— ๋Œ€ํ•ด ๊ฐ€์žฅ ๋งŽ์ด ๊ฒ€์ƒ‰๋˜๋Š” ์งˆ๋ฌธ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ง์ ‘์ ์ธ ๋‹ต๋ณ€์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ •์  ์ฝ”๋“œ ๋ถ„์„์€ ์†Œ์Šค ์ฝ”๋“œ ํŒจํ„ด ์—์„œ ๋‚˜ํƒ€๋‚˜๋Š” ์œ„ํ˜‘ , ์ฆ‰ SQL, ๋ช…๋ น, XSS ์ธ์ ์…˜ ์ทจ์•ฝ์ , ์•”ํ˜ธํ™” ์˜ค์šฉ, ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ž๊ฒฉ ์ฆ๋ช…, ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์ธ์ฆ ๊ตฌํ˜„, ์ฝ”๋“œ ๋กœ์ง์˜ ์ ‘๊ทผ ์ œ์–ด ์˜ค๋ฅ˜, ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์‹คํŒจ ๋“ฑ์„ ์™„ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋Ÿฐํƒ€์ž„ ๊ตฌ์„ฑ, ๋„คํŠธ์›Œํฌ ํ† ํด๋กœ์ง€ ๋˜๋Š” ์ธํ”„๋ผ ์„ค์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์œ„ํ˜‘์€ ์™„ํ™”ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์ด๋Ÿฌํ•œ ์œ„ํ˜‘์€ ๋™์  ๊ฐ€์šฉ์„ฑ ํ…Œ์ŠคํŠธ(DAST), ์นจํˆฌ ํ…Œ์ŠคํŠธ ๋˜๋Š” ์ธํ”„๋ผ ๋ณด์•ˆ ์Šค์บ”์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

OWASP ์ ์šฉ ๋ฒ”์œ„์— ๋Œ€ํ•œ ์ •์  ๋ถ„์„๊ณผ ๋™์  ๋ถ„์„ ๋น„๊ต

๋™์  ๋ถ„์„(DAST)๊ณผ ์ •์  ๋ถ„์„(SAST)์€ OWASP ์ทจ์•ฝ์ ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ํ•˜์œ„ ์ง‘ํ•ฉ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค. ์–ด๋А ์ชฝ๋„ ๋ชจ๋“  ์ทจ์•ฝ์ ์„ ๋‹ค๋ฃจ์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. OWASP ์›น ๋ณด์•ˆ ํ…Œ์ŠคํŠธ ๊ฐ€์ด๋“œ(WSTG)๋Š” ๋™์  ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ•๋ก  ํ”„๋ ˆ์ž„์›Œํฌ์ด๋ฉฐ, CodeQL, Semgrep, SonarQube์™€ ๊ฐ™์€ SAST ๋„๊ตฌ๋Š” ์†Œ์Šค ์ฝ”๋“œ ๊ณ„์ธต์„ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

OWASP Top 10 ์นดํ…Œ๊ณ ๋ฆฌSAST ์ ์šฉ ๋ฒ”์œ„DAST ์ ์šฉ ๋ฒ”์œ„
์†์ƒ๋œ ์•ก์„ธ์Šค ์ œ์–ด๋ถ€๋ถ„์ ์ธ ์ฝ”๋“œ ๋…ผ๋ฆฌ ์˜ค๋ฅ˜์ข‹์Šต๋‹ˆ๋‹ค, ๋Ÿฐํƒ€์ž„ ๋™์ž‘ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค.
์•”ํ˜ธํ™” ์‹คํŒจ๊ฐ•๋ ฅํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ฐ์ง€์•ฝํ•ด์„œ ์™ธ๋ถ€์—์„œ ๊ด€์ฐฐํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
์ฃผ์ž…๊ฐ•๋ ฅํ•œ ์˜ค์—ผ ๋ถ„์„๊ฐ•๋ ฅํ•˜๊ณ  ๋Šฅ๋™์ ์ธ ํŽ˜์ด๋กœ๋“œ ํ…Œ์ŠคํŠธ
์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๋””์ž์ธ๋ถ€๋ถ„์  ํŒจํ„ด ๊ฐ์ง€์•ฝ์ , ์„ค๊ณ„ ์ง€์‹ ํ•„์š”
๋ณด์•ˆ ๊ตฌ์„ฑ ์˜ค๋ฅ˜๋ถ€๋ถ„์ , ์ฝ”๋“œ ๋‚ด ์„ค์ •๊ฐ•๋ ฅํ•˜๊ณ  ์‹ค์ œ์ ์ธ ํ™˜๊ฒฝ ํ…Œ์ŠคํŠธ
์ทจ์•ฝํ•œ ๊ตฌ์„ฑ์š”์†Œ์•ฝํ•˜๋„ค์š”, SCA๊ฐ€ ๋” ๋‚ซ์Šต๋‹ˆ๋‹ค.์•ฝํ•˜๋„ค์š”, SCA๊ฐ€ ๋” ๋‚ซ์Šต๋‹ˆ๋‹ค.
์ธ์ฆ ์‹คํŒจ๋ถ€๋ถ„์ , ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์ž๊ฒฉ ์ฆ๋ช…, ์ทจ์•ฝํ•œ ํŒจํ„ด๊ฐ•๋ ฅํ•œ ์„ธ์…˜ ๋ฐ ์ธ์ฆ ํ…Œ์ŠคํŠธ
๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์˜ค๋ฅ˜๋ถ€๋ถ„์ , ์—ญ์ง๋ ฌํ™” ํŒจํ„ด์•ฝํ•ด์„œ ์™ธ๋ถ€์—์„œ ๊ฐ์ง€ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
๋กœ๊น… ์‹คํŒจ๋ถ€๋ถ„์ ์ด๊ฑฐ๋‚˜ ๋ˆ„๋ฝ๋œ ๋กœ๊ทธ ๋ฌธ์žฅ์•ฝํ•˜๊ณ , ๊ด€์ฐฐํ•˜๊ธฐ ์–ด๋ ค์šด ๋ถ€์žฌ
SSRFHTTP ํ˜ธ์ถœ์— ์‹ฌ๊ฐํ•œ ์˜ค์—ผ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.๊ฐ•๋ ฅํ•˜๊ณ  ์ ๊ทน์ ์ธ ์š”์ฒญ ํ…Œ์ŠคํŠธ

๊ฒฐ๋ก : SAST์™€ DAST๋Š” ์ƒํ˜ธ โ€‹โ€‹๋ณด์™„์ ์ž…๋‹ˆ๋‹ค. OWASP ์ ์šฉ ๋ฒ”์œ„๋ฅผ ์ตœ๋Œ€ํ•œ ํ™•๋ณดํ•˜๋ ค๋ฉด ๋‘ ๊ฐ€์ง€ ๋ชจ๋‘ ์‹คํ–‰ํ•˜์„ธ์š”. ์˜ˆ์‚ฐ์ด ์ œํ•œ์ ์ธ ํŒ€์ด ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ, SAST๋ฅผ ๋จผ์ € ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. SAST๋Š” ๊ฐœ๋ฐœ์ž ํ”ผ๋“œ๋ฐฑ์„ ๊ฐ€์žฅ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•˜๊ณ  ์ฃผ์ž… ๋ฒ”์œ„๋„ ๊ฐ€์žฅ ๋„“์Šต๋‹ˆ๋‹ค.

OWASP Top 10: ์ •์  ๋ถ„์„์˜ ํ•ต์‹ฌ ๋‚ด์šฉ๊ณผ ํ™œ์šฉ๋ฒ•

A01, ์ ‘๊ทผ ์ œ์–ด ์˜ค๋ฅ˜

์ ‘๊ทผ ์ œ์–ด ์˜ค๋ฅ˜๋Š” OWASP์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์œ„ํ—˜ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ์ •์  ๋ถ„์„์€ ์ฝ”๋“œ ์ˆ˜์ค€์—์„œ ๋‚˜ํƒ€๋‚˜๋Š” ๋ฌธ์ œ์ ๋“ค์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํ•จ์ˆ˜ ๋ฐ ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•œ ๊ถŒํ•œ ๊ฒ€์‚ฌ ๋ˆ„๋ฝ, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์—†์ด ๋‚ด๋ถ€ ID๋ฅผ ๋…ธ์ถœํ•˜๋Š” ๊ฐ์ฒด ์ฐธ์กฐ, ์˜๋„๋œ ๊ถŒํ•œ ๊ตฌ์กฐ๋ฅผ ๋ฌด์‹œํ•˜๋Š” ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์—ญํ•  ํ• ๋‹น ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ •์  ๋ถ„์„์ด ํƒ์ง€ํ•˜๋Š” ์‚ฌํ•ญ: ๊ถŒํ•œ ํ™•์ธ ์—†์ด ๋ฏผ๊ฐํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์„œ๋“œ, ์ ‘๊ทผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์—†์ด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์—์„œ ๊ฐ์ฒด ID๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ง์ ‘์ ์ธ ๊ฐ์ฒด ์ฐธ์กฐ, ์ธ์ฆ ์ƒํƒœ๋Š” ํ™•์ธํ•˜์ง€๋งŒ ๊ฐ์ฒด ์†Œ์œ ๊ถŒ์€ ํ™•์ธํ•˜์ง€ ์•Š๋Š” ๊ฐ•์ œ ํƒ์ƒ‰ ํŒจํ„ด.

์ž๋ฐ”

// Vulnerable: no ownership check -- any authenticated user can access any order
@GetMapping("/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId) {
    return orderRepository.findById(orderId).orElseThrow();
}

// Secure: verify the order belongs to the requesting user
@GetMapping("/orders/{orderId}")
public Order getOrder(@PathVariable Long orderId,
                      @AuthenticationPrincipal UserDetails user) {
    Order order = orderRepository.findById(orderId).orElseThrow();
    if (!order.getOwnerId().equals(user.getUserId())) {
        throw new AccessDeniedException("Order does not belong to requesting user");
    }
    return order;
}

์ •์  ๋ถ„์„์œผ๋กœ ํฌ์ฐฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ: ๋กœ์ง์€ ์˜ฌ๋ฐ”๋ฅด์ง€๋งŒ ์˜์‚ฌ ๊ฒฐ์ •์— ์‚ฌ์šฉ๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์†์ƒ๋œ ๋Ÿฐํƒ€์ž„ ์ ‘๊ทผ ์ œ์–ด ์‹คํŒจ. ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๋ฅผ ํƒ์ง€ํ•˜๋ ค๋ฉด DAST(๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์ œ์–ด ํ…Œ์ŠคํŠธ)์™€ ์นจํˆฌ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

A02, ์•”ํ˜ธํ™” ์˜ค๋ฅ˜

์ทจ์•ฝํ•œ ์•”ํ˜ธํ™” ๋ฐฉ์‹์€ ์†Œ์Šค ์ฝ”๋“œ์—์„œ MD5, SHA-1, DES, ECB ๋ชจ๋“œ, ํ•˜๋“œ์ฝ”๋”ฉ๋œ ํ‚ค์™€ ๊ฐ™์€ ์ทจ์•ฝํ•œ ํŒจํ„ด์„ ์–ดํœ˜์ ์œผ๋กœ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ •์  ๋ถ„์„์„ ํ†ตํ•ด ํ™•์‹คํ•˜๊ฒŒ ํƒ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ

# Vulnerable: MD5 for password hashing (broken algorithm)
import hashlib
password_hash = hashlib.md5(password.encode()).hexdigest()

# Vulnerable: hardcoded encryption key
KEY = b"mysecretkey12345"
cipher = AES.new(KEY, AES.MODE_ECB)  # ECB mode also vulnerable

# Secure: bcrypt for passwords, environment-sourced keys
import bcrypt, os
password_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))

# Secure: AES-GCM with environment-sourced key
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = os.environ["ENCRYPTION_KEY"].encode()
aesgcm = AESGCM(key)

์ •์  ๋ถ„์„ ๊ทœ์น™ ํ”Œ๋ž˜๊ทธ: ๋ณด์•ˆ์— ๋ฏผ๊ฐํ•œ ๋ชฉ์ ์„ ์œ„ํ•œ MD5/SHA-1, DES/3DES/RC4/ECB ๋ชจ๋“œ, ํ•˜๋“œ์ฝ”๋”ฉ๋œ ์•”ํ˜ธํ™” ํ‚ค ๋ฐ ๋น„๋ฐ€ ํ‚ค, ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก์— HTTPS ๋Œ€์‹  HTTP ์‚ฌ์šฉ, ์ธ์ฆ์„œ ๊ฒ€์ฆ ๋น„ํ™œ์„ฑํ™”(verify=False Python requests์—์„œ, setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER) ์ž๋ฐ”์—์„œ).

A03, ์ฃผ์‚ฌ

์ธ์ ์…˜, SQL, OS ๋ช…๋ น, LDAP, XSS, ํ…œํ”Œ๋ฆฟ ์ธ์ ์…˜์€ ํ”„๋กœ์‹œ์ € ๊ฐ„ ์˜ค์—ผ ๋ถ„์„์ด ๊ฐ€์žฅ ์ง์ ‘์ ์œผ๋กœ ๊ฐ€์น˜๋ฅผ ๋ฐœํœ˜ํ•˜๋Š” ๋ฒ”์ฃผ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ทจ์•ฝ์ ์€ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž…๋ ฅ์ด ์†Œ์Šค์—์„œ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ฑฐ์ณ ์œ„ํ—˜ํ•œ ์‹ฑํฌ๋กœ ์ด์–ด์ง€๋Š” ๊ณผ์ •์„ ์ถ”์ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ

// Vulnerable: direct string interpolation in SQL (SQL injection)
app.get('/users', async (req, res) => {
    const name = req.query.name;
    const result = await db.query(`SELECT * FROM users WHERE name = '${name}'`);
    res.json(result.rows);
});

// Secure: parameterized query
app.get('/users', async (req, res) => {
    const name = req.query.name;
    const result = await db.query('SELECT * FROM users WHERE name = $1', [name]);
    res.json(result.rows);
});

PHP๋Š”

// Vulnerable: unescaped output (XSS)
echo "Welcome, " . $_GET['username'];

// Secure: context-appropriate escaping
echo "Welcome, " . htmlspecialchars($_GET['username'], ENT_QUOTES, 'UTF-8');

๋‚ ์นด๋กœ์šด

// Vulnerable: command injection in C#
var process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c " + userInput;
process.Start();

// Secure: avoid shell interpretation, validate and whitelist inputs
var allowedCommands = new HashSet<string> { "report", "export" };
if (!allowedCommands.Contains(userInput))
    throw new ArgumentException("Invalid command");

์ธ์ ์…˜ ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ํ”„๋กœ์‹œ์ € ๊ฐ„ ์˜ค์—ผ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋„๊ตฌ: CodeQL(๊ฐ€์žฅ ์ •ํ™•ํ•จ), ์˜ค์—ผ ๋ชจ๋“œ๊ฐ€ ์žˆ๋Š” Semgrep, Snyk Code, ๋ณด์•ˆ ๊ทœ์น™์ด ์žˆ๋Š” SonarQube.

A04, ๋ถˆ์•ˆ์ •ํ•œ ๋””์ž์ธ

์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์„ค๊ณ„๋Š” ์ฝ”๋“œ ํŒจํ„ด๋ณด๋‹ค๋Š” ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„์™€ ๊ด€๋ จ๋œ ๋ฌธ์ œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ •์  ๋ถ„์„์—์„œ OWASP ๋ฒ”์ฃผ ์ค‘ ๊ฐ€์žฅ ์–ด๋ ค์šด ๋ฒ”์ฃผ์ž…๋‹ˆ๋‹ค. ์ •์  ๋ถ„์„์„ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฆ์ƒ์„ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธ์ฆ ์—”๋“œํฌ์ธํŠธ์— ์†๋„ ์ œํ•œ ๋กœ์ง์ด ์—†๊ฑฐ๋‚˜, ๋กœ๊ทธ์ธ ์‹คํŒจ ํ›„ ๊ณ„์ • ์ž ๊ธˆ์ด ์—†๊ฑฐ๋‚˜, ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋‹จ๊ณ„๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์žˆ๊ฑฐ๋‚˜, ๊ฐ์‚ฌ ๋กœ๊น… ์—†์ด ๊ถŒํ•œ ์žˆ๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์ ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ์ ์€ ๋ˆ„๋ฝ๋œ ํŒจํ„ด์„ ํ†ตํ•ด ํƒ์ง€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ถ€์žฌํ•˜๋Š” ๊ฒƒ์„ ๋ณด๊ณ ํ•˜๋Š” ์ •์  ๋ถ„์„ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์ผ๋ถ€ SAST ๋„๊ตฌ๋Š” ์กฐ์ง์˜ ๋ณด์•ˆ ์„ค๊ณ„ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ง€์ • ๊ทœ์น™์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“  ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์„œ๋“œ๋Š” ๊ถŒํ•œ ๋ถ€์—ฌ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๊ณ , ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์“ฐ๊ธฐ ์ž‘์—…์€ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๊ฑฐ์ณ์•ผ ํ•˜๋ฉฐ, ๋ชจ๋“  ์™ธ๋ถ€ API ํ˜ธ์ถœ์€ ํƒ€์ž„์•„์›ƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์‚ฌ์šฉ์ž ์ง€์ • ๊ทœ์น™์€ ์„ค๊ณ„ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ ์ œ์•ฝ ์กฐ๊ฑด์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

A05, ๋ณด์•ˆ ์„ค์ • ์˜ค๋ฅ˜

์ฝ”๋“œ์˜ ๋ณด์•ˆ ๊ตฌ์„ฑ ์˜ค๋ฅ˜์—๋Š” ๋ณด์•ˆ ๊ธฐ๋Šฅ ๋น„ํ™œ์„ฑํ™”, ํ—ˆ์šฉ์ ์ธ CORS ํ—ค๋”, ๋ณด์•ˆ ์‘๋‹ต ํ—ค๋” ๋ˆ„๋ฝ, ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ๋””๋ฒ„๊ทธ ๋ชจ๋“œ ํ™œ์„ฑํ™”, ์Šคํƒ ์ถ”์ ์„ ๋…ธ์ถœํ•˜๋Š” ์ž์„ธํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ๋“ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ

# Vulnerable: Flask debug mode enables interactive debugger in production
app = Flask(__name__)
app.run(debug=True)  # exposes console access if error occurs

# Vulnerable: overly permissive CORS
from flask_cors import CORS
CORS(app, origins="*")  # allows any origin

# Secure: environment-controlled debug, restricted CORS
import os
debug_mode = os.environ.get("FLASK_DEBUG", "false").lower() == "true"
CORS(app, origins=os.environ.get("ALLOWED_ORIGINS", "").split(","))
app.run(debug=debug_mode)

์ •์  ๋ถ„์„ ๊ทœ์น™ ํ”Œ๋ž˜๊ทธ: ๋””๋ฒ„๊ทธ ๋ชจ๋“œ๊ฐ€ ์„ค์ •๋จ True ์†Œ์Šค ์ฝ”๋“œ์˜ ์™€์ผ๋“œ์นด๋“œ CORS ์ถœ์ฒ˜, HTTP ์‘๋‹ต ๊ตฌ์„ฑ์˜ ๋ณด์•ˆ ํ—ค๋” ๋ˆ„๋ฝ, SSL ์ธ์ฆ์„œ ๊ฒ€์ฆ ๋น„ํ™œ์„ฑํ™” ๋ฐ ๊ตฌ์„ฑ ํŒŒ์ผ์˜ ๊ธฐ๋ณธ ์ž๊ฒฉ ์ฆ๋ช… ๋“ฑ์ด ์›์ธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

A06, ์ทจ์•ฝํ•˜๊ณ  ์˜ค๋ž˜๋œ ๊ตฌ์„ฑ ์š”์†Œ

์ด ๋ฒ”์ฃผ๋Š” ์ „ํ†ต์ ์ธ SAST๋ณด๋‹ค๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ตฌ์„ฑ ๋ถ„์„(SCA)์—์„œ ์ฃผ๋กœ ๋‹ค๋ฃน๋‹ˆ๋‹ค. SCA๋Š” ์Šค์บ”์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. package.json, pom.xml, requirements.txt๊ทธ๋ฆฌ๊ณ  ์œ ์‚ฌํ•œ ๋‚ด์šฉ์ด ์ทจ์•ฝ์  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(๊ตญ๊ฐ€ ์ทจ์•ฝ์  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, GitHub Advisory Database)์— ๋Œ€ํ•ด ๋ณด๊ณ ๋ฉ๋‹ˆ๋‹ค.

SAST๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” API ์‚ฌ์šฉ, ๋ณด์•ˆ ๊ฒฐํ•จ์œผ๋กœ ์ธํ•ด ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ, ๋˜๋Š” ์ตœ์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์กฐ์ฐจ ๋” ์ด์ƒ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š” ์ทจ์•ฝํ•œ ํŒจํ„ด์˜ ์ง์ ‘์ ์ธ ์‚ฌ์šฉ์„ ์‹๋ณ„ํ•จ์œผ๋กœ์จ ๊ธฐ์—ฌํ•ฉ๋‹ˆ๋‹ค.

A06 ์ „์šฉ ๋„๊ตฌ: npm audit, pip-audit, snyk test, OWASP Dependency-CheckGitHub Dependabot ๋ฐ Mend(์ด์ „ WhiteSource)๋„ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

A07, ์‹๋ณ„ ๋ฐ ์ธ์ฆ ์‹คํŒจ

์ •์  ๋ถ„์„์„ ํ†ตํ•ด ์ฝ”๋“œ ์ˆ˜์ค€ ์ธ์ฆ ์•ˆํ‹ฐ ํŒจํ„ด์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์•ˆํ‹ฐ ํŒจํ„ด์—๋Š” ํ•˜๋“œ์ฝ”๋”ฉ๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ, ์ทจ์•ฝํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ, ๋น„์•”ํ˜ธํ•™์  ๋‚œ์ˆ˜๋กœ ์ƒ์„ฑ๋œ ์„ธ์…˜ ํ† ํฐ, ๋กœ๊ทธ์•„์›ƒ ์‹œ ์„ธ์…˜ ๋ฌดํšจํ™” ๋ˆ„๋ฝ, ๊ทธ๋ฆฌ๊ณ  JWT ๊ตฌํ˜„ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜ ๋“ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. none ์—ฐ์‚ฐ.

์ž๋ฐ” ์Šคํฌ๋ฆฝํŠธ

// Vulnerable: JWT accepting 'none' algorithm -- allows signature bypass
const decoded = jwt.verify(token, secret, { algorithms: ['HS256', 'none'] });

// Vulnerable: hardcoded admin credentials
if (username === 'admin' && password === 'admin123') {
    grantAccess();
}

// Secure: algorithm whitelist, no hardcoded credentials
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
    algorithms: ['HS256']  // explicit allowlist only
});

๋‚ ์นด๋กœ์šด

// Vulnerable: weak random for session token generation in C#
var sessionToken = new Random().Next().ToString();

// Secure: cryptographically secure random
using var rng = RandomNumberGenerator.Create();
var bytes = new byte[32];
rng.GetBytes(bytes);
var sessionToken = Convert.ToBase64String(bytes);

A08, ์†Œํ”„ํŠธ์›จ์–ด ๋ฐ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์˜ค๋ฅ˜

์ด ๋ฒ”์ฃผ๋Š” ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ์—ญ์ง๋ ฌํ™” ๋ฐ ๊ฒ€์ฆ๋˜์ง€ ์•Š์€ ์†Œํ”„ํŠธ์›จ์–ด ์—…๋ฐ์ดํŠธ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์ •์  ๋ถ„์„์€ Java๋ฅผ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค. ObjectInputStream ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์†Œ์Šค์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ ์—ญ์ง๋ ฌํ™”, Python pickle.loads() ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ, PHP unserialize() ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ œ์–ด ๊ธฐ๋Šฅ๊ณผ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๋กœ๋”๋ฅผ ์‚ฌ์šฉํ•˜๋Š” YAML ํŒŒ์„œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ

# Vulnerable: pickle deserialization of untrusted data
import pickle
data = pickle.loads(request.data)  # arbitrary code execution risk

# Vulnerable: unsafe YAML loader
import yaml
config = yaml.load(user_input)  # yaml.load without Loader is unsafe

# Secure: safe alternatives
import json
data = json.loads(request.data)  # JSON cannot execute code

import yaml
config = yaml.safe_load(user_input)  # safe_load disables arbitrary object creation

A09, ๋ณด์•ˆ ๋กœ๊น… ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹คํŒจ

๋กœ๊น… ์‹คํŒจ๋Š” ์ •์  ๋ถ„์„์„ ํ†ตํ•ด ๋ˆ„๋ฝ๋œ ํŒจํ„ด์œผ๋กœ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฏผ๊ฐํ•œ ์ž‘์—…, ์ธ์ฆ ์ด๋ฒคํŠธ, ์ ‘๊ทผ ์ œ์–ด ๊ฒฐ์ •, ๋ฐ์ดํ„ฐ ์ˆ˜์ • ๋“ฑ์ด ๋กœ๊ทธ ๋ฌธ ์—†์ด ์ง„ํ–‰๋˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์ •์  ๋ถ„์„ ๊ทœ์น™์„ ์„ค์ •ํ•˜์—ฌ ํŠน์ • ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ํ•ญ์ƒ ๊ฐ์‚ฌ ๋กœ๊ทธ ํ˜ธ์ถœ๊ณผ ํ•จ๊ป˜ ๋ฐœ์ƒํ•˜๋„๋ก ์š”๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ •์  ๋ถ„์„์—์„œ ํƒ์ง€๋˜๋Š” ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ ๋˜๋Š” ํ† ํฐ ๋กœ๊น…(๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ ๋กœ๊น… ๋˜ํ•œ ์ทจ์•ฝ์ ์ž…๋‹ˆ๋‹ค), ๋กœ๊น… ์—†์ด ์˜ค๋ฅ˜๋ฅผ ๋ฌต์‚ดํ•˜๋Š” ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๊ธฐ, ๊ทธ๋ฆฌ๊ณ  ์›์‹œ ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€(๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ์Œ)๋ฅผ ๋กœ๊น…ํ•˜๋Š” catch ๋ธ”๋ก์ž…๋‹ˆ๋‹ค.

์ž๋ฐ”

// Vulnerable: swallowed exception, no logging
try {
    authenticateUser(username, password);
} catch (Exception e) {
    // silent failure -- no log, no audit trail
}

// Vulnerable: logging sensitive data
log.info("User logged in with password: " + password);

// Secure: log the event, not the credential
try {
    authenticateUser(username, password);
    auditLog.info("Authentication success for user: {}", username);
} catch (AuthenticationException e) {
    auditLog.warn("Authentication failure for user: {}", username);
    throw e;  // do not swallow
}

A10, ์„œ๋ฒ„ ์ธก ์š”์ฒญ ์œ„์กฐ(SSRF)

SSRF๋Š” ํ”„๋กœ์‹œ์ € ๊ฐ„ ์˜ค์—ผ ๋ถ„์„์ด ํ•„์š”ํ•œ ๊ฐ•๋ ฅํ•œ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. ์ด ์ทจ์•ฝ์ ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋‚ด์šฉ์„ ์—ฌ๋Ÿฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๊ฑฐ์ณ HTTP ์š”์ฒญ์— ์ด๋ฅด๊ธฐ๊นŒ์ง€ ์ถ”์ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ณ„ ํ•จ์ˆ˜๋งŒ ๋ถ„์„ํ•˜๋Š” ๋„๊ตฌ๋กœ๋Š” URL ๊ตฌ์„ฑ๊ณผ HTTP ํ˜ธ์ถœ์ด ์„œ๋กœ ๋‹ค๋ฅธ ํ•จ์ˆ˜์— ์žˆ๋Š” ๊ฒฝ์šฐ SSRF๋ฅผ ํƒ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํŒŒ์ด์ฌ

# Vulnerable: user-controlled URL in HTTP request (SSRF)
import requests

def fetch_resource(url):
    return requests.get(url).content  # no validation

def api_endpoint(request):
    target = request.json().get("url")    # attacker controls this
    return fetch_resource(target)          # SSRF across function boundary

# Secure: allowlist validation before making the request
from urllib.parse import urlparse

ALLOWED_HOSTS = {"api.internal.example.com", "cdn.example.com"}

def fetch_resource(url: str) -> bytes:
    parsed = urlparse(url)
    if parsed.hostname not in ALLOWED_HOSTS:
        raise ValueError(f"URL host not allowed: {parsed.hostname}")
    return requests.get(url, timeout=5).content

OWASP ๋ณด์•ˆ์„ ์œ„ํ•œ ์ •์  ์ฝ”๋“œ ๋ถ„์„ ๋„๊ตฌ

์•„๋ž˜ ํ‘œ๋Š” ์ฃผ์š” SAST ๋„๊ตฌ๋ฅผ ํ•ด๋‹น ๋„๊ตฌ๊ฐ€ ๊ฐ€์žฅ ํšจ๊ณผ์ ์œผ๋กœ ๋‹ค๋ฃจ๋Š” OWASP ๋ฒ”์ฃผ์™€ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜๋‹จ์ฃผ์š” ์–ธ์–ดOWASP์˜ ๊ฐ•์ ์ ‘๊ทผ
CodeQL์ž๋ฐ”, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ/ํ…์ŠคํŠธ ํŽธ์ง‘, ํŒŒ์ด์ฌ, C/C++, ๊ณ , ๋ฃจ๋น„A03 ์ฃผ์ž…, A10 SSRF (์‹ฌํ•œ ์˜ค์—ผ)์ ˆ์ฐจ ๊ฐ„ ์˜๋ฏธ ๋ถ„์„
์…ˆ๊ทธ๋ ™30 ๊ฐœ ์ด์ƒ์˜ ์–ธ์–ดA03, A02, A07 (ํŒจํ„ด ๊ธฐ๋ฐ˜ + ์˜ค์—ผ ๋ชจ๋“œ)ํŒจํ„ด ๋งค์นญ + ์–•์€ ์–ผ๋ฃฉ
Snyk ์ฝ”๋“œ์ž๋ฐ”, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ/ํ…์ŠคํŠธ ํŽธ์ง‘, ํŒŒ์ด์ฌ, C#A03, A07, A08ML ๊ธฐ๋ฐ˜ ์˜ค์—ผ ๋ถ„์„
์†Œ๋‚˜ํ๋ธŒ30 ๊ฐœ ์ด์ƒ์˜ ์–ธ์–ดA02, A03, A05, A07, A09๊ทœ์น™ ๊ธฐ๋ฐ˜ + ๋ฐ์ดํ„ฐ ํ๋ฆ„
์ฒดํฌ ๋งˆํฌ์Šค30 ๊ฐœ ์ด์ƒ์˜ ์–ธ์–ดOWASP ์ „์ฒด ๋ณด์žฅ์ ˆ์ฐจ ๊ฐ„ ์˜ค์—ผ
๋ฒ ๋ผ์ฝ”๋“œ์ž๋ฐ”, .NET, JS, PHPOWASP ์ „์ฒด ๋ณด์žฅ๋ฐ”์ดํŠธ์ฝ”๋“œ + ์˜ค์—ผ ๋ถ„์„
OWASP ์žฝ์–ธ์–ด์— ๊ตฌ์• ๋ฐ›์ง€ ์•Š์ŒA01, A05, A07 (์‹คํ–‰ ์‹œ๊ฐ„)DAST, ๋™์  ํ…Œ์ŠคํŠธ
SMART TS XLCOBOL, JCL, Java, Python, RPG, SQL์–ธ์–ด ๊ฐ„ ์˜ค์—ผ, ์˜์กด์„ฑ ์œ„ํ—˜์–ธ์–ด ๊ฐ„ ๊ตฌ์กฐ์  + ์˜ค์—ผ

๋ฐฉ๋ฒ• SMART TS XL ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๋ณด์•ˆ ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

๊ธฐ์—… ๋ณด์•ˆ ํ”„๋กœ๊ทธ๋žจ์€ ๋‹จ์ผ ์–ธ์–ด SAST ๋„๊ตฌ๋กœ๋Š” ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ์— ์ง๋ฉดํ•ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ ๊ณต๊ฒฉ ํ‘œ๋ฉด์ด ์—ฌ๋Ÿฌ ์–ธ์–ด์— ๊ฑธ์ณ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด JavaScript๋กœ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋ฐ›์•„ Java๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋ฉ”์‹œ์ง€ ํ๋ฅผ ํ†ตํ•ด DB2 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•ด SQL์„ ์‹คํ–‰ํ•˜๋Š” COBOL ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ธ์ ์…˜ ์ทจ์•ฝ์ ์€ ๋„ค ๊ฐ€์ง€ ์–ธ์–ด ๊ฒฝ๊ณ„๋ฅผ ๋„˜๋‚˜๋“ค๋ฉฐ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์–ด๋–ค ๊ฐœ๋ณ„ ์–ธ์–ด ์Šค์บ๋„ˆ๋„ ์ „์ฒด ์˜ค์—ผ ๊ฒฝ๋กœ๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

SMART TS XL์˜ ์ •์  ์ฝ”๋“œ ๋ถ„์„ ์ด ์ฒด์ธ์˜ ๋ชจ๋“  ์–ธ์–ด๋ฅผ ๋™์‹œ์— ๋‹ค๋ฃน๋‹ˆ๋‹ค. ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ž…๋ ฅ์ด JavaScript API ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ†ตํ•ด Java ์„œ๋น„์Šค๋ฅผ ๊ฑฐ์ณ ๋™์  SQL ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” COBOL ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์ „๋‹ฌ๋  ๋•Œ, SMART TS XL ์ด ๊ธฐ๋Šฅ์€ ์ „์ฒด ์–ธ์–ด ๊ฐ„ ํ˜ธ์ถœ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ฐ€๋กœ์ง€๋ฅด๋Š” ๊ฒฝ๋กœ๋ฅผ ์ถ”์ ํ•˜๋ฉฐ, CodeQL์ด Java ๋‚ด์—์„œ ์ ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ํ”„๋กœ์‹œ์ € ๊ฐ„ ์˜ค์—ผ ์ถ”์  ๊ธฐ๋Šฅ์„ Java, COBOL ๋ฐ SQL์— ๊ฑธ์ณ ํ•จ๊ป˜ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…์†์„ฑ ๋งคํ•‘ ๊ธฐ๋Šฅ์€ ์‹œ์Šคํ…œ ๋‚ด ์–ด๋–ค ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์™ธ๋ถ€ ์ž…๋ ฅ๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š”์ง€, ์–ด๋–ค ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๊ถŒํ•œ ์žˆ๋Š” ์ž‘์—…์— ์ ‘๊ทผํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์‹œ์Šคํ…œ์˜ ์ „์ฒด ๊ณต๊ฒฉ ํ‘œ๋ฉด์ด ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€์— ๋Œ€ํ•œ ๋ณด์•ˆ ๊ด€๋ จ ๊ด€์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์•„ํ‚คํ…์ฒ˜ ๋ณด์•ˆ ๊ด€์ ์€ ์œ„ํ˜‘ ๋ชจ๋ธ๋ง์˜ ๊ธฐ๋ฐ˜์ด ๋˜๋ฉฐ, ์‹œ์Šคํ…œ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋ฉด ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ ์œ„ํ˜‘์„ ๋ชจ๋ธ๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์˜ํ–ฅ ๋ถ„์„ ๊ธฐ๋Šฅ์€ ๋ณด์•ˆ ์ทจ์•ฝ์  ํ•ด๊ฒฐ ํ”„๋กœ๊ทธ๋žจ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ทจ์•ฝ์ ์ด ๋ฐœ๊ฒฌ๋˜๋ฉด ์˜ํ–ฅ ๋ถ„์„์„ ํ†ตํ•ด ํ•ด๋‹น ์ทจ์•ฝ์ ์— ์˜์กดํ•˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‹๋ณ„ํ•˜์—ฌ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์ „์— ํ•ด๊ฒฐ ์ž‘์—… ๋ฒ”์œ„๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด์•ˆ ๊ฒฐํ•จ์ด ์žˆ๋Š” COBOL ํ”„๋กœ๊ทธ๋žจ์ด ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋žจ์— ํฌํ•จ๋œ ๋Œ€๊ทœ๋ชจ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ๊ฒฝ์šฐ, ํ•ด๊ฒฐ ์ž‘์—… ์‹œ์ž‘ ์ „์— ์ „์ฒด ๋ฒ”์œ„๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๊ณผ ์—ฐ์‡„์ ์ธ ์‚ฌ๊ณ  ํ™•์‚ฐ์„ ๋ง‰๋Š” ๋ฐ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ด€๋ฆฌํ•˜๋Š” ์กฐ์ง์˜ ๊ฒฝ์šฐ ๋ ˆ๊ฑฐ์‹œ ํ˜„๋Œ€ํ™” ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐœ๋ฐœํ•  ๋•Œ, ๊ธฐ์กด ์ฝ”๋“œ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ๋ณด์•ˆ ๋ถ„์„์€ ํ•„์ˆ˜ ์กฐ๊ฑด์ด๋ฉฐ, ์‚ฌํ›„ ๊ณ ๋ ค ์‚ฌํ•ญ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ทจ์•ฝํ•œ COBOL ํ”„๋กœ๊ทธ๋žจ์„ Java๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋ฉด ์ทจ์•ฝํ•œ Java ํ”„๋กœ๊ทธ๋žจ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. SMART TS XL๋ณด์•ˆ ๋ถ„์„์„ ํ†ตํ•ด ์ทจ์•ฝ์ ์ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜๋œ ์‹œ์Šคํ…œ์—์„œ ๋ฐœ๊ฒฌ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ํ˜„๋Œ€ํ™” ํ”„๋กœ์„ธ์Šค์˜ ์ผํ™˜์œผ๋กœ ์‹๋ณ„ ๋ฐ ์ˆ˜์ •๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ ๋ผ์ดํ”„์‚ฌ์ดํด์— SAST ํ†ตํ•ฉํ•˜๊ธฐ

์ •์  ๋ณด์•ˆ ๋ถ„์„์€ ์ฝ”๋“œ๊ฐ€ ์ž‘์„ฑ๋˜๊ณ  ๊ฒ€ํ† ๋˜๋Š” ์˜์‚ฌ ๊ฒฐ์ • ์‹œ์ ์— ์‹คํ–‰๋  ๋•Œ ์ตœ๋Œ€์˜ ๊ฐ€์น˜๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ๋ฐฐํฌ ํ›„์— ์‹คํ–‰๋  ๋•Œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

IDE ํ™˜๊ฒฝ์—์„œ๋Š” SonarLint, Snyk์˜ IDE ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ, CodeQL์˜ VS Code ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ ์ทจ์•ฝ์ ์„ ์ฆ‰์‹œ ํ‘œ์‹œํ•ด ์ค๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ทจ์•ฝํ•œ ํŒจํ„ด์„ ์ž…๋ ฅํ•˜๋Š” ์ˆœ๊ฐ„ ๋‚˜ํƒ€๋‚˜๋Š” SQL ์ธ์ ์…˜ ํ”Œ๋ž˜๊ทธ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ๋Š” ๋ช‡ ์ดˆ๋ฐ–์— ๊ฑธ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ’€ ๋ฆฌํ€˜์ŠคํŠธ์—์„œ: GitHub Actions, GitLab CI ๋˜๋Š” Jenkins์— ํ†ตํ•ฉ๋œ SAST๋Š” ๋ชจ๋“  ํ’€ ๋ฆฌํ€˜์ŠคํŠธ์—์„œ ์‹คํ–‰๋˜์–ด ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์„ ์ฝ”๋“œ ๋ฆฌ๋ทฐ ๋Œ“๊ธ€๋กœ ์ธ๋ผ์ธ์— ๊ฒŒ์‹œํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ๋ฐœ๊ฒฌ ์‚ฌํ•ญ์„ ์›์ธ์ด ๋œ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ๋งฅ๋ฝ ์†์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

SonarQube์˜ ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ ๋ชจ๋ธ์€ ์ƒˆ๋กœ์šด ์ค‘์š” ๋ณด์•ˆ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ๋ณ‘ํ•ฉ์„ ์ฐจ๋‹จํ•˜๋Š” ํ’ˆ์งˆ ๊ฒŒ์ดํŠธ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณด์•ˆ์€ ์„ ํƒ์ ์ธ ๊ฒ€ํ†  ๋‹จ๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ๋ณ‘ํ•ฉ ํ”„๋กœ์„ธ์Šค์˜ ๊ตฌ์กฐ์  ์š”๊ตฌ ์‚ฌํ•ญ์ด ๋ฉ๋‹ˆ๋‹ค.

์ •๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ์ž‘์—…์—๋Š” ์‹ฌ์ธต์ ์ธ ํ”„๋กœ์‹œ์ € ๊ฐ„ ๋ถ„์„(CodeQL, Checkmarx, ์ „์ฒด Semgrep ๊ทœ์น™ ์„ธํŠธ)์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด ์ž‘์—…์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์ปค๋ฐ‹๋ณ„ ์‹คํ–‰์—๋Š” ๋„ˆ๋ฌด ๋А๋ฆฌ์ง€๋งŒ, ๋ฉ”์ธ ๋ธŒ๋žœ์น˜์—์„œ ๋งค์ผ ๋ฐค ๋˜๋Š” ๋งค์ฃผ ์‹คํ–‰๋˜์–ด ์ „์ฒด ํ˜ธ์ถœ ๊ทธ๋ž˜ํ”„ ๋ถ„์„์ด ํ•„์š”ํ•œ ์ทจ์•ฝ์ ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.

๊ณ„์ธตํ™”๋œ ์ ‘๊ทผ ๋ฐฉ์‹, IDE ๋ฐ ์ปค๋ฐ‹ ์‹œ ์ ์šฉ๋˜๋Š” ๋น ๋ฅธ ํŒจํ„ด ๊ธฐ๋ฐ˜ ๊ทœ์น™, ํ’€ ๋ฆฌํ€˜์ŠคํŠธ ๋ฐ ๋‚˜์ดํ‹€๋ฆฌ ๋นŒ๋“œ์— ๋Œ€ํ•œ ์‹ฌ์ธต์ ์ธ ์˜ค์—ผ ๋ถ„์„์„ ํ†ตํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•„์š”๋กœ ํ•˜๋Š” ์ฆ‰๊ฐ์ ์ธ ๋Œ€์‘๊ณผ ๋ณด์•ˆ ํ”„๋กœ๊ทธ๋žจ์ด ์š”๊ตฌํ•˜๋Š” ์ฒ ์ €ํ•จ์„ ๋ชจ๋‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.