๋ณด์ ์ทจ์ฝ์ ์ ์์ ํ๋ ๊ฒ๋ณด๋ค ์๋ฐฉํ๋ ๊ฒ์ด ํจ์ฌ ์ฝ์ต๋๋ค. ์ฝ๋ ๊ฒํ ์ค์ ๋ฐ๊ฒฌ๋ 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๊ฐ ๋ ๋ซ์ต๋๋ค. |
| ์ธ์ฆ ์คํจ | ๋ถ๋ถ์ , ํ๋์ฝ๋ฉ๋ ์๊ฒฉ ์ฆ๋ช , ์ทจ์ฝํ ํจํด | ๊ฐ๋ ฅํ ์ธ์ ๋ฐ ์ธ์ฆ ํ ์คํธ |
| ๋ฐ์ดํฐ ๋ฌด๊ฒฐ์ฑ ์ค๋ฅ | ๋ถ๋ถ์ , ์ญ์ง๋ ฌํ ํจํด | ์ฝํด์ ์ธ๋ถ์์ ๊ฐ์งํ๊ธฐ ์ด๋ ต์ต๋๋ค. |
| ๋ก๊น ์คํจ | ๋ถ๋ถ์ ์ด๊ฑฐ๋ ๋๋ฝ๋ ๋ก๊ทธ ๋ฌธ์ฅ | ์ฝํ๊ณ , ๊ด์ฐฐํ๊ธฐ ์ด๋ ค์ด ๋ถ์ฌ |
| SSRF | HTTP ํธ์ถ์ ์ฌ๊ฐํ ์ค์ผ์ด ๋ฐ์ํ์ต๋๋ค. | ๊ฐ๋ ฅํ๊ณ ์ ๊ทน์ ์ธ ์์ฒญ ํ ์คํธ |
๊ฒฐ๋ก : 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, A08 | ML ๊ธฐ๋ฐ ์ค์ผ ๋ถ์ |
| ์๋ํ๋ธ | 30 ๊ฐ ์ด์์ ์ธ์ด | A02, A03, A05, A07, A09 | ๊ท์น ๊ธฐ๋ฐ + ๋ฐ์ดํฐ ํ๋ฆ |
| ์ฒดํฌ ๋งํฌ์ค | 30 ๊ฐ ์ด์์ ์ธ์ด | OWASP ์ ์ฒด ๋ณด์ฅ | ์ ์ฐจ ๊ฐ ์ค์ผ |
| ๋ฒ ๋ผ์ฝ๋ | ์๋ฐ, .NET, JS, PHP | OWASP ์ ์ฒด ๋ณด์ฅ | ๋ฐ์ดํธ์ฝ๋ + ์ค์ผ ๋ถ์ |
| OWASP ์ฝ | ์ธ์ด์ ๊ตฌ์ ๋ฐ์ง ์์ | A01, A05, A07 (์คํ ์๊ฐ) | DAST, ๋์ ํ ์คํธ |
| SMART TS XL | COBOL, 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 ๋ฐ ์ปค๋ฐ ์ ์ ์ฉ๋๋ ๋น ๋ฅธ ํจํด ๊ธฐ๋ฐ ๊ท์น, ํ ๋ฆฌํ์คํธ ๋ฐ ๋์ดํ๋ฆฌ ๋น๋์ ๋ํ ์ฌ์ธต์ ์ธ ์ค์ผ ๋ถ์์ ํตํด ๊ฐ๋ฐ์๊ฐ ํ์๋ก ํ๋ ์ฆ๊ฐ์ ์ธ ๋์๊ณผ ๋ณด์ ํ๋ก๊ทธ๋จ์ด ์๊ตฌํ๋ ์ฒ ์ ํจ์ ๋ชจ๋ ์ ๊ณตํฉ๋๋ค.