Ver3.0 ๐ก๏ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฉํ๋ฒฝ(WAF) ์ค์ ๊ณผ ํ์ฉ๋ฒ: ๋น์ ์ ์น์ฌ์ดํธ๋ฅผ ์งํค๋ ์ต๊ฐ ๋ฐฉํจ ๐

๐ก๏ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฉํ๋ฒฝ(WAF) ์ค์ ๊ณผ ํ์ฉ๋ฒ: ๋น์ ์ ์น์ฌ์ดํธ๋ฅผ ์งํค๋ ์ต๊ฐ ๋ฐฉํจ ๐
ํด์ปค๋ค์ ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ ํ๊ฒ ๋ณดํธํ๋ ์ค์ ๊ฐ์ด๋
๐ฏ ์ด ๊ธ์์ ๋ฐฐ์ธ ๋ด์ฉ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฉํ๋ฒฝ(WAF)์ ํ๋ ์น ๋ณด์์ ํต์ฌ ๋ฐฉ์ด์ ์ด์์. SQL ์ธ์ ์ , XSS ๊ณต๊ฒฉ, DDoS ๋ฑ ๋ค์ํ ์น ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ์ฌ๋ฌ๋ถ์ ์์คํ ์๋น์ค๋ฅผ ์ง์ผ์ฃผ๋ ๊ฐ๋ ฅํ ๋ณด์ ๋๊ตฌ์ฃ . ์ด ๊ธ์์๋ WAF์ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ์ค์ ์ค์ ๋ฐฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ ํจ๊ณผ์ ์ธ ํ์ฉ ์ ๋ต๊น์ง ์น๊ตฌ์๊ฒ ์ค๋ช ํ๋ฏ ์ฝ๊ณ ์ฌ๋ฏธ์๊ฒ ์๋ ค๋๋ฆด๊ฒ์! ๐ช
๐ค WAF๊ฐ ๋ญ๊ธธ๋ ์ด๋ ๊ฒ ์ค์ํ ๊น?
์น ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฉํ๋ฒฝ(Web Application Firewall, WAF)์ ์ดํดํ๋ ค๋ฉด ๋จผ์ ์ผ๋ฐ ๋ฐฉํ๋ฒฝ๊ณผ์ ์ฐจ์ด๋ฅผ ์์์ผ ํด์. ์ผ๋ฐ ๋ฐฉํ๋ฒฝ์ด ๋คํธ์ํฌ ๊ณ์ธต์์ IP ์ฃผ์์ ํฌํธ ๋ฒํธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํธ๋ํฝ์ ํํฐ๋งํ๋ค๋ฉด, WAF๋ HTTP/HTTPS ํ๋กํ ์ฝ ์์ค์์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ผ๋ก ๋ค์ด์ค๋ ์์ฒญ์ ๋ถ์ํ๊ณ ์ฐจ๋จํ๋ ํนํ๋ ๋ณด์ ์๋ฃจ์ ์ด์์.
์๊ฐํด๋ณด์ธ์. ์ฌ๋ฌ๋ถ์ด ์ด์ํ๋ ์ผํ๋ชฐ ์น์ฌ์ดํธ๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ณผ๊ฒ์. ์ผ๋ฐ ๋ฐฉํ๋ฒฝ์ ๊ฑด๋ฌผ ์ ๊ตฌ์ ๊ฒฝ๋น์์ฒ๋ผ "์ด ์ฌ๋์ ๋ค์ด์๋ ๋๊ณ , ์ ์ฌ๋์ ์ ๋ผ"๋ผ๊ณ ํ๋จํ์ง๋ง, WAF๋ ๊ฑด๋ฌผ ์์์ ๊ฐ ์ธต๋ง๋ค ๋ฐฐ์น๋ ๋ณด์์์์ฒ๋ผ "์ด ์ฌ๋์ด ํ๋ ค๋ ํ๋์ด ์ ์์ ์ธ๊ฐ? ์์ํ๊ฐ?"๋ฅผ ์ค์๊ฐ์ผ๋ก ์ฒดํฌํ๋ ๊ฑฐ์ฃ . ๐ต๏ธ
๐ก ์ฌ๋ฅ๋ท TIP ํ๋ก๊ทธ๋๋ฐ๊ณผ ๋ณด์ ๋ถ์ผ์ ์ ๋ฌธ๊ฐ๋ฅผ ์ฐพ๊ณ ๊ณ์ ๊ฐ์? ์ฌ๋ฅ๋ท์์๋ WAF ์ค์ ๋ถํฐ ์น ๋ณด์ ์ปจ์คํ ๊น์ง ๋ค์ํ ๋ณด์ ์ ๋ฌธ๊ฐ๋ค์ ์ฌ๋ฅ์ ๋ง๋๋ณผ ์ ์์ด์. ์ค์ ๊ฒฝํ์ด ํ๋ถํ ์ ๋ฌธ๊ฐ๋ค๊ณผ ํจ๊ป๋ผ๋ฉด ์ฌ๋ฌ๋ถ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์ฑ ์์ ํ๊ฒ ๋ณดํธํ ์ ์๋ต๋๋ค! ๐
๐ฏ WAF๊ฐ ๋ง์์ฃผ๋ ์ฃผ์ ๊ณต๊ฒฉ ์ ํ๋ค
WAF๊ฐ ์ด๋ค ๊ณต๊ฒฉ๋ค์ ๋ฐฉ์ดํ๋์ง ๊ตฌ์ฒด์ ์ผ๋ก ์์๋ณผ๊น์? ๊ฐ ๊ณต๊ฒฉ ์ ํ์ ์ดํดํ๋ฉด WAF์ ์ค์์ฑ์ด ๋์ฑ ๋ช ํํด์ง ๊ฑฐ์์.
๐ SQL ์ธ์ ์ (SQL Injection)
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ์ ์ ์์ ์ธ SQL ์ฝ๋๋ฅผ ์ฝ์ ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์ทจํ๊ฑฐ๋ ์กฐ์ํ๋ ๊ณต๊ฒฉ์ด์์. ์๋ฅผ ๋ค์ด ๋ก๊ทธ์ธ ํผ์ ' OR '1'='1 ๊ฐ์ ์ฝ๋๋ฅผ ์ ๋ ฅํด์ ์ธ์ฆ์ ์ฐํํ๋ ค๋ ์๋์ฃ .
WAF ๋ฐฉ์ด ๋ฐฉ์: SQL ๊ตฌ๋ฌธ ํจํด์ ๋ถ์ํ๊ณ ์์ฌ์ค๋ฌ์ด ์ฟผ๋ฆฌ ๋ฌธ์์ด์ ์ฐจ๋จํด์.
โก ํฌ๋ก์ค ์ฌ์ดํธ ์คํฌ๋ฆฝํ (XSS)
์ ์ฑ ์คํฌ๋ฆฝํธ๋ฅผ ์นํ์ด์ง์ ์ฝ์ ํ์ฌ ๋ค๋ฅธ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์์ ์คํ์ํค๋ ๊ณต๊ฒฉ์ด์์. ์ฌ์ฉ์์ ์ฟ ํค๋ ์ธ์ ์ ๋ณด๋ฅผ ํ์ทจํ ์ ์์ด ๋งค์ฐ ์ํํด์.
WAF ๋ฐฉ์ด ๋ฐฉ์: JavaScript ์ฝ๋ ํจํด์ ๊ฐ์งํ๊ณ HTML ํ๊ทธ ์ฝ์ ์๋๋ฅผ ์ฐจ๋จํฉ๋๋ค.
๐ DDoS ๊ณต๊ฒฉ
๋๋์ ํธ๋ํฝ์ ๋์์ ๋ฐ์์์ผ ์๋ฒ๋ฅผ ๋ง๋น์ํค๋ ๊ณต๊ฒฉ์ด์์. ์ ์์ ์ธ ์ฌ์ฉ์๋ค์ด ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์๊ฒ ๋ง๋๋ ๊ฑฐ์ฃ .
WAF ๋ฐฉ์ด ๋ฐฉ์: ๋น์ ์์ ์ธ ํธ๋ํฝ ํจํด์ ๊ฐ์งํ๊ณ ์์ฒญ ์๋๋ฅผ ์ ํ(Rate Limiting)ํด์.
๐ ํ์ผ ์ ๋ก๋ ๊ณต๊ฒฉ
์ ์ฑ ํ์ผ์ ์๋ฒ์ ์ ๋ก๋ํ์ฌ ์์คํ ์ ์ฅ์ ํ๋ ค๋ ์๋์์. ์น์(Web Shell)์ ์ ๋ก๋ํด์ ์๋ฒ๋ฅผ ์๊ฒฉ ์ ์ดํ๋ ค๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์.
WAF ๋ฐฉ์ด ๋ฐฉ์: ํ์ผ ํ์ฅ์, MIME ํ์ , ํ์ผ ๋ด์ฉ์ ๊ฒ์ฌํ์ฌ ์์ฌ์ค๋ฌ์ด ์ ๋ก๋๋ฅผ ์ฐจ๋จํฉ๋๋ค.
๐ ๋๋ ํ ๋ฆฌ ํธ๋๋ฒ์ค
URL ๊ฒฝ๋ก ์กฐ์์ ํตํด ์๋ฒ์ ๋ฏผ๊ฐํ ํ์ผ์ ์ ๊ทผํ๋ ค๋ ๊ณต๊ฒฉ์ด์์. ../../etc/passwd ๊ฐ์ ๊ฒฝ๋ก๋ก ์์คํ ํ์ผ์ ์ฝ์ผ๋ ค๊ณ ์๋ํ์ฃ .
WAF ๋ฐฉ์ด ๋ฐฉ์: ๊ฒฝ๋ก ๋ฌธ์์ด ํจํด์ ๋ถ์ํ๊ณ ์์ ๋๋ ํ ๋ฆฌ ์ ๊ทผ ์๋๋ฅผ ์ฐจ๋จํด์.
๐ญ ์ธ์ ํ์ด์ฌํน
์ ์ ์ฌ์ฉ์์ ์ธ์ ID๋ฅผ ํ์ทจํ์ฌ ํด๋น ์ฌ์ฉ์๋ก ์์ฅํ๋ ๊ณต๊ฒฉ์ด์์. ๋ก๊ทธ์ธ ์์ด ๋ค๋ฅธ ์ฌ๋์ ๊ณ์ ์ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ ๊ฑฐ์ฃ .
WAF ๋ฐฉ์ด ๋ฐฉ์: ์ธ์ ์ฟ ํค์ ๋น์ ์์ ์ธ ์ฌ์ฉ ํจํด์ ๊ฐ์งํ๊ณ ์ฐจ๋จํฉ๋๋ค.
โ ๏ธ ์ฃผ์์ฌํญ WAF๋ ๊ฐ๋ ฅํ ๋ณด์ ๋๊ตฌ์ง๋ง ๋ง๋ฅ์ ์๋์์. WAF๋ง์ผ๋ก๋ 100% ์๋ฒฝํ ๋ณด์์ ๋ณด์ฅํ ์ ์์ผ๋ฉฐ, ์์ ํ ์ฝ๋ฉ ๊ดํ, ์ ๊ธฐ์ ์ธ ๋ณด์ ์ ๋ฐ์ดํธ, ์นจํฌ ํ ์คํธ ๋ฑ ๋ค์ธต์ ์ธ ๋ณด์ ์ ๋ต์ด ํจ๊ป ํ์ํด์. WAF๋ ๋ณด์์ ํ ์ธต(Layer)์ผ ๋ฟ์ด๋ผ๋ ์ ์ ๊ธฐ์ตํ์ธ์! ๐ฏ
๐๏ธ WAF์ ์ฃผ์ ๊ตฌ์ฑ ์์์ ์๋ ์๋ฆฌ
WAF๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๋ค์ฌ๋ค๋ณผ๊น์? ๋ณต์กํด ๋ณด์ด์ง๋ง ์๋ฆฌ๋ฅผ ์ดํดํ๋ฉด ์ค์ ๊ณผ ๊ด๋ฆฌ๊ฐ ํจ์ฌ ์ฌ์์ ธ์.
๐ 1. ๊ท์น ์์ง (Rule Engine)
WAF์ ๋๋๋ผ๊ณ ํ ์ ์๋ ๋ถ๋ถ์ด์์. ๋ฏธ๋ฆฌ ์ ์๋ ๊ท์น(Rule)๋ค์ ๊ธฐ๋ฐ์ผ๋ก ๋ค์ด์ค๋ HTTP ์์ฒญ์ ๋ถ์ํ๊ณ ํ๋จํด์. ๊ท์น์ ํฌ๊ฒ ์ธ ๊ฐ์ง ์ ํ์ผ๋ก ๋๋์ด์:
๐น ์๊ทธ๋์ฒ ๊ธฐ๋ฐ ๊ท์น (Signature-based Rules)
์๋ ค์ง ๊ณต๊ฒฉ ํจํด์ ํน์ง(์๊ทธ๋์ฒ)์ ๋ฐ์ดํฐ๋ฒ ์ด์คํํด์ ๋งค์นญํ๋ ๋ฐฉ์์ด์์. ์๋ฅผ ๋ค์ด SQL ์ธ์ ์
๊ณต๊ฒฉ์์ ์์ฃผ ์ฌ์ฉ๋๋ UNION SELECT, DROP TABLE ๊ฐ์ ํค์๋๋ฅผ ๊ฐ์งํ๋ ๊ฑฐ์ฃ .
์ฅ์ : ๋น ๋ฅด๊ณ ์ ํํ๋ฉฐ ์คํ(False Positive)์ด ์ ์ด์.
๋จ์ : ์๋ก์ด ๊ณต๊ฒฉ ๊ธฐ๋ฒ(Zero-day)์๋ ๋์ํ๊ธฐ ์ด๋ ค์์.
๐น ํ์ ๊ธฐ๋ฐ ๊ท์น (Behavior-based Rules)
์ ์์ ์ธ ํธ๋ํฝ ํจํด์ ํ์ตํ๊ณ , ์ด์ ํ์(Anomaly)๋ฅผ ๊ฐ์งํ๋ ๋ฐฉ์์ด์์. ์๋ฅผ ๋ค์ด ํ์์๋ ์ด๋น 10๊ฐ์ ์์ฒญ์ ๋ณด๋ด๋ IP๊ฐ ๊ฐ์๊ธฐ ์ด๋น 1000๊ฐ์ ์์ฒญ์ ๋ณด๋ด๋ฉด ์์ฌ์ค๋ฝ๋ค๊ณ ํ๋จํ๋ ๊ฑฐ์ฃ .
์ฅ์ : ์๋ ค์ง์ง ์์ ์๋ก์ด ๊ณต๊ฒฉ๋ ํ์งํ ์ ์์ด์.
๋จ์ : ํ์ต ๊ธฐ๊ฐ์ด ํ์ํ๊ณ ์คํ๋ฅ ์ด ๋์ ์ ์์ด์.
๐น ํํ ๊ธฐ๋ฐ ๊ท์น (Reputation-based Rules)
IP ์ฃผ์, ๋๋ฉ์ธ, URL์ ํํ ์ ๋ณด๋ฅผ ํ์ฉํ๋ ๋ฐฉ์์ด์์. ์ด๋ฏธ ์
์ฑ์ผ๋ก ์๋ ค์ง IP ์ฃผ์๋ ๋ด๋ท์์ ์ค๋ ํธ๋ํฝ์ ์ฐจ๋จํ๋ ๊ฑฐ์ฃ .
์ฅ์ : ์๋ ค์ง ์
์ฑ ์์ค๋ฅผ ๋น ๋ฅด๊ฒ ์ฐจ๋จํ ์ ์์ด์.
๋จ์ : ํํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ต์ ์ฑ์ด ์ค์ํด์.
๐ 2. ํธ๋ํฝ ๋ถ์ ์์ง
HTTP/HTTPS ์์ฒญ์ ๋ชจ๋ ๋ถ๋ถ์ ์ธ๋ฐํ๊ฒ ๋ถ์ํ๋ ์ปดํฌ๋ํธ์์. ๋ค์๊ณผ ๊ฐ์ ์์๋ค์ ๊ฒ์ฌํด์:
| ๊ฒ์ฌ ๋์ | ์ค๋ช | ์์ |
|---|---|---|
| HTTP ํค๋ | ์์ฒญ ํค๋์ ๊ตฌ์กฐ์ ๋ด์ฉ์ ๊ฒ์ฌ | User-Agent, Referer, Cookie ๋ฑ |
| URL ํ๋ผ๋ฏธํฐ | ์ฟผ๋ฆฌ ์คํธ๋ง์ ๊ฐ๊ณผ ํจํด ๋ถ์ | ?id=1&name=test |
| POST ๋ฐ์ดํฐ | ์์ฒญ ๋ณธ๋ฌธ(Body)์ ๋ด์ฉ ๊ฒ์ฌ | ํผ ๋ฐ์ดํฐ, JSON, XML ๋ฑ |
| ์ฟ ํค | ์ฟ ํค ๊ฐ์ ๋ฌด๊ฒฐ์ฑ๊ณผ ์ ํจ์ฑ ๊ฒ์ฆ | ์ธ์ ID, ์ธ์ฆ ํ ํฐ ๋ฑ |
| ํ์ผ ์ ๋ก๋ | ์ ๋ก๋๋๋ ํ์ผ์ ํ์ ๊ณผ ๋ด์ฉ ๊ฒ์ฌ | ํ์ฅ์, MIME ํ์ , ํ์ผ ๋ด์ฉ |
โ๏ธ 3. ์ ์ฑ ๊ด๋ฆฌ ์์คํ
๋ณด์ ์ ์ฑ ์ ์ ์ํ๊ณ ๊ด๋ฆฌํ๋ ๋ถ๋ถ์ด์์. ๊ด๋ฆฌ์๋ ์ฌ๊ธฐ์ ๋ค์๊ณผ ๊ฐ์ ์ค์ ์ ํ ์ ์์ด์:
๐๏ธ ๋ณด์ ๋ ๋ฒจ ์ค์
- Paranoid (ํธ์ง์ฆ ๋ชจ๋): ๋งค์ฐ ์๊ฒฉํ ๊ฒ์ฌ, ์คํ ๊ฐ๋ฅ์ฑ ๋์
- High (๋์): ์๊ฒฉํ ๋ณด์, ์ผ๋ถ ์ ์ ํธ๋ํฝ ์ฐจ๋จ ๊ฐ๋ฅ
- Medium (์ค๊ฐ): ๊ท ํ์กํ ๋ณด์, ๋๋ถ๋ถ์ ํ๊ฒฝ์ ์ ํฉ
- Low (๋ฎ์): ๋์จํ ๋ณด์, ๋ช
ํํ ๊ณต๊ฒฉ๋ง ์ฐจ๋จ
๐ญ ๋์ ๋ชจ๋ ์ค์
- Detection Only (ํ์ง๋ง): ๊ณต๊ฒฉ์ ํ์งํ๊ณ ๋ก๊ทธ๋ง ๊ธฐ๋ก, ์ฐจ๋จํ์ง ์์
- Prevention (์ฐจ๋จ): ๊ณต๊ฒฉ์ ํ์งํ๊ณ ์ฆ์ ์ฐจ๋จ
- Learning (ํ์ต): ์ ์ ํธ๋ํฝ ํจํด์ ํ์ตํ๋ ๋ชจ๋
๐ 4. ๋ก๊น ๋ฐ ๋ชจ๋ํฐ๋ง ์์คํ
๋ชจ๋ ๋ณด์ ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋กํ๊ณ ์ค์๊ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํ๋ ์์คํ ์ด์์. ๋ค์๊ณผ ๊ฐ์ ์ ๋ณด๋ค์ด ๋ก๊ทธ์ ๊ธฐ๋ก๋ผ์:
[2024-01-15 14:23:45] ALERT - SQL Injection Detected
Source IP: 192.168.1.100
Target URL: /login.php?id=1' OR '1'='1
Rule ID: 981242
Action: BLOCKED
Severity: CRITICAL
Request Headers: {
"User-Agent": "Mozilla/5.0...",
"Referer": "http://attacker.com"
}
์ด๋ฐ ๋ก๊ทธ๋ฅผ ๋ถ์ํ๋ฉด ๊ณต๊ฒฉ ํจํด์ ํ์ ํ๊ณ ๋ณด์ ์ ์ฑ ์ ๊ฐ์ ํ ์ ์์ด์. ๐
๐ WAF ๋ฐฐํฌ ๋ฐฉ์: ์ด๋ค ๊ฑธ ์ ํํด์ผ ํ ๊น?
WAF๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ์ธ ๊ฐ์ง๊ฐ ์์ด์. ๊ฐ๊ฐ์ ์ฅ๋จ์ ์ ๋น๊ตํด์ ์ฌ๋ฌ๋ถ์ ํ๊ฒฝ์ ๋ง๋ ๋ฐฉ์์ ์ ํํ์ธ์!
โ๏ธ ํด๋ผ์ฐ๋ ๊ธฐ๋ฐ WAF (Cloud-based WAF)
AWS WAF, Cloudflare, Akamai ๊ฐ์ ํด๋ผ์ฐ๋ ์๋น์ค ํํ๋ก ์ ๊ณต๋๋ WAF์์. ๊ฐ์ฅ ์ธ๊ธฐ ์๊ณ ๊ตฌ์ถ์ด ์ฌ์ด ๋ฐฉ์์ด์ฃ .
โ
์ฅ์ :
โข ๋น ๋ฅธ ๊ตฌ์ถ: DNS๋ง ๋ณ๊ฒฝํ๋ฉด ๋ช ๋ถ ์์ ์ ์ฉ ๊ฐ๋ฅํด์
โข ๊ด๋ฆฌ ํธ์์ฑ: ์ธํ๋ผ ๊ด๋ฆฌ๊ฐ ํ์ ์๊ณ ์๋ ์
๋ฐ์ดํธ๋ผ์
โข ํ์ฅ์ฑ: ํธ๋ํฝ ์ฆ๊ฐ์ ์๋์ผ๋ก ๋์ํด์
โข ๊ธ๋ก๋ฒ ๋คํธ์ํฌ: ์ ์ธ๊ณ ์ฃ์ง ์๋ฒ๋ฅผ ํตํ ๋น ๋ฅธ ์๋ต
โข DDoS ๋ฐฉ์ด: ๋๊ท๋ชจ DDoS ๊ณต๊ฒฉ๋ ํจ๊ณผ์ ์ผ๋ก ๋ฐฉ์ดํด์
โ ๋จ์ :
โข ๋น์ฉ: ํธ๋ํฝ์ ๋ฐ๋ผ ๋น์ฉ์ด ์ฆ๊ฐํ ์ ์์ด์
โข ์ปค์คํฐ๋ง์ด์ง ์ ํ: ์ธ๋ฐํ ์ค์ ์ ํ๊ณ๊ฐ ์์ ์ ์์ด์
โข ๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์: ๋ชจ๋ ํธ๋ํฝ์ด ์ 3์๋ฅผ ๊ฑฐ์ณ๊ฐ์
โข ๋ฒค๋ ์ข
์: ํน์ ํด๋ผ์ฐ๋ ์๋น์ค์ ์์กดํ๊ฒ ๋ผ์
๐ฐ ๋น์ฉ ์์:
- AWS WAF: ์น ACL๋น $5/์ + ๊ท์น๋น $1/์ + ์์ฒญ 100๋ง ๊ฑด๋น $0.60
- Cloudflare: ๋ฌด๋ฃ ํ๋๋ถํฐ Enterprise๊น์ง ๋ค์
- Akamai: ์ํฐํ๋ผ์ด์ฆ๊ธ, ๋ง์ถคํ ๊ฐ๊ฒฉ
๐ฏ ์ถ์ฒ ๋์: ์ค์๊ท๋ชจ ์น์ฌ์ดํธ, ๋น ๋ฅธ ๊ตฌ์ถ์ด ํ์ํ ๊ฒฝ์ฐ, ๊ด๋ฆฌ ๋ฆฌ์์ค๊ฐ ๋ถ์กฑํ ํ
๐ฅ๏ธ ์จํ๋ ๋ฏธ์ค WAF (On-premise WAF)
์์ฒด ๋ฐ์ดํฐ์ผํฐ์ ํ๋์จ์ด ์ดํ๋ผ์ด์ธ์ค๋ ์ํํธ์จ์ด๋ฅผ ์ค์นํ๋ ๋ฐฉ์์ด์์. F5, Imperva, Barracuda ๊ฐ์ ์ ํ๋ค์ด ์์ด์.
โ
์ฅ์ :
โข ์์ ํ ์ ์ด: ๋ชจ๋ ์ค์ ์ ์ธ๋ฐํ๊ฒ ์ปค์คํฐ๋ง์ด์ง ๊ฐ๋ฅํด์
โข ๋ฐ์ดํฐ ๋ณด์: ํธ๋ํฝ์ด ์ธ๋ถ๋ก ๋๊ฐ์ง ์์์
โข ๊ท์ ์ค์: ๊ธ์ต, ์๋ฃ ๋ฑ ์๊ฒฉํ ๊ท์ ์ฐ์
์ ์ ํฉํด์
โข ์ฑ๋ฅ ์ต์ ํ: ๋ด๋ถ ๋คํธ์ํฌ์ ์ต์ ํ๋ ์ฑ๋ฅ
โข ์ผํ์ฑ ๋น์ฉ: ์ด๊ธฐ ํฌ์ ํ ์ถ๊ฐ ๋น์ฉ์ด ์ ์ด์
โ ๋จ์ :
โข ๋์ ์ด๊ธฐ ๋น์ฉ: ํ๋์จ์ด์ ๋ผ์ด์ ์ค ๋น์ฉ์ด ๋น์ธ์
โข ๊ด๋ฆฌ ๋ถ๋ด: ์ ๋ฌธ ์ธ๋ ฅ์ด ํ์ํ๊ณ ์ ์ง๋ณด์๊ฐ ๋ณต์กํด์
โข ํ์ฅ์ฑ ์ ํ: ํ๋์จ์ด ์ฉ๋์ ์ ํ์ด ์์ด์
โข ์
๋ฐ์ดํธ: ์๋์ผ๋ก ํจ์น์ ์
๋ฐ์ดํธ๋ฅผ ๊ด๋ฆฌํด์ผ ํด์
โข ๊ตฌ์ถ ์๊ฐ: ์ค์น์ ์ค์ ์ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ ค์
๐ฐ ๋น์ฉ ์์:
- F5 BIG-IP ASM: $10,000 ~ $100,000+ (์ฉ๋์ ๋ฐ๋ผ)
- Imperva SecureSphere: $15,000 ~ $50,000+
- ์ฐ๊ฐ ์ ์ง๋ณด์: ์ด๊ธฐ ๋น์ฉ์ 15-20%
๐ฏ ์ถ์ฒ ๋์: ๋๊ธฐ์ , ๊ธ์ต/์๋ฃ ๊ธฐ๊ด, ๋์ ๋ณด์ ์๊ตฌ์ฌํญ, ๋ด๋ถ ๋ฐ์ดํฐ ๋ณดํธ๊ฐ ์ค์ํ ๊ฒฝ์ฐ
๐ง ํธ์คํธ ๊ธฐ๋ฐ WAF (Host-based WAF)
์น ์๋ฒ์ ์ง์ ์ค์นํ๋ ์ํํธ์จ์ด ํํ์ WAF์์. ModSecurity๊ฐ ๋ํ์ ์ธ ์คํ์์ค ์๋ฃจ์ ์ด์ฃ .
โ
์ฅ์ :
โข ์ ๋ ดํ ๋น์ฉ: ์คํ์์ค๋ ๋ฌด๋ฃ, ์์ฉ๋ ์ ๋ ดํด์
โข ๊น์ ํตํฉ: ์น ์๋ฒ์ ๊ธด๋ฐํ๊ฒ ํตํฉ๋ผ์
โข ์ธ๋ฐํ ์ ์ด: ์ ํ๋ฆฌ์ผ์ด์
๋ ๋ฒจ์์ ์ ๋ฐํ ์ ์ด ๊ฐ๋ฅ
โข ํ์ต ๊ธฐํ: ์ง์ ์ค์ ํ๋ฉด์ ๋ณด์ ์ง์์ ์์ ์ ์์ด์
โข ์คํ๋ผ์ธ ํ๊ฒฝ: ์ธํฐ๋ท ์ฐ๊ฒฐ ์์ด๋ ์๋ํด์
โ ๋จ์ :
โข ์๋ฒ ๋ฆฌ์์ค: CPU์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ถ๊ฐ๋ก ์๋นํด์
โข ๊ด๋ฆฌ ๋ณต์ก๋: ๊ฐ ์๋ฒ๋ง๋ค ๊ฐ๋ณ ๊ด๋ฆฌ๊ฐ ํ์ํด์
โข ์ ๋ฌธ ์ง์: ์ค์ ๊ณผ ํ๋์ ์ ๋ฌธ ์ง์์ด ํ์ํด์
โข DDoS ์ทจ์ฝ: ๋๊ท๋ชจ DDoS ๊ณต๊ฒฉ์๋ ํจ๊ณผ๊ฐ ์ ํ์ ์ด์์
โข ํ์ฅ์ฑ: ์๋ฒ๊ฐ ๋ง์์ง๋ฉด ๊ด๋ฆฌ๊ฐ ์ด๋ ค์์ ธ์
๐ฐ ๋น์ฉ ์์:
- ModSecurity: ๋ฌด๋ฃ (์คํ์์ค)
- NAXSI: ๋ฌด๋ฃ (์คํ์์ค)
- ์์ฉ ์๋ฃจ์
: $500 ~ $5,000/์๋ฒ
๐ฏ ์ถ์ฒ ๋์: ์คํํธ์ , ๊ฐ๋ฐ์, ํ์ต ๋ชฉ์ , ์์ฐ์ด ์ ํ์ ์ธ ๊ฒฝ์ฐ, ์๊ท๋ชจ ์๋ฒ ํ๊ฒฝ
โก ์ค์ ! ModSecurity๋ก WAF ๊ตฌ์ถํ๊ธฐ
์ด์ ์ค์ ๋ก WAF๋ฅผ ์ค์ ํด๋ณผ๊น์? ๊ฐ์ฅ ์ธ๊ธฐ ์๋ ์คํ์์ค WAF์ธ ModSecurity๋ฅผ Apache ์น ์๋ฒ์ ์ค์นํ๋ ๊ณผ์ ์ ๋จ๊ณ๋ณ๋ก ์์๋ณผ๊ฒ์. ๐ ๏ธ
๐ฆ 1๋จ๊ณ: ModSecurity ์ค์น
Ubuntu/Debian ๊ธฐ๋ฐ ์์คํ ์์ ์ค์นํ๋ ๋ฐฉ๋ฒ์ด์์:
# ํจํค์ง ์
๋ฐ์ดํธ
sudo apt update
# Apache์ ModSecurity ์ค์น
sudo apt install apache2 libapache2-mod-security2 -y
# ModSecurity ๋ชจ๋ ํ์ฑํ
sudo a2enmod security2
# Apache ์ฌ์์
sudo systemctl restart apache2
# ์ค์น ํ์ธ
apachectl -M | grep security
๋ง์ง๋ง ๋ช ๋ น์ด๋ฅผ ์คํํ์ ๋ security2_module์ด ๋ณด์ด๋ฉด ์ฑ๊ณต์ด์์! ๐
โ๏ธ 2๋จ๊ณ: ๊ธฐ๋ณธ ์ค์ ํ์ผ ๊ตฌ์ฑ
ModSecurity์ ์ค์ ํ์ผ์ ๋ณต์ฌํ๊ณ ๊ธฐ๋ณธ ์ค์ ์ ํด๋ณผ๊ฒ์:
# ๊ธฐ๋ณธ ์ค์ ํ์ผ ๋ณต์ฌ
sudo cp /etc/modsecurity/modsecurity.conf-recommended \
/etc/modsecurity/modsecurity.conf
# ์ค์ ํ์ผ ํธ์ง
sudo nano /etc/modsecurity/modsecurity.conf
์ค์ ํ์ผ์์ ์ค์ํ ๋ถ๋ถ๋ค์ ์ดํด๋ณผ๊น์:
# ๋ณด์ ์์ง ํ์ฑํ (DetectionOnly์์ On์ผ๋ก ๋ณ๊ฒฝ)
SecRuleEngine On
# ์์ฒญ ๋ณธ๋ฌธ ๊ฒ์ฌ ํ์ฑํ
SecRequestBodyAccess On
# ์๋ต ๋ณธ๋ฌธ ๊ฒ์ฌ ํ์ฑํ (์ฑ๋ฅ ์ํฅ ์์, ํ์์์๋ง)
SecResponseBodyAccess Off
# ์ต๋ ์์ฒญ ๋ณธ๋ฌธ ํฌ๊ธฐ (13MB)
SecRequestBodyLimit 13107200
# ํ์ผ ์
๋ก๋ ํฌ๊ธฐ ์ ํ (100MB)
SecRequestBodyNoFilesLimit 131072
# ๋ก๊ทธ ๋๋ ํ ๋ฆฌ ์ค์
SecAuditLog /var/log/apache2/modsec_audit.log
# ๋ก๊ทธ ๋ ๋ฒจ (0=์์, 9=๋ชจ๋)
SecAuditLogRelevantStatus "^(?:5|4(?!04))"
# ๋๋ฒ๊ทธ ๋ก๊ทธ (๋ฌธ์ ํด๊ฒฐ์ ์ ์ฉ)
SecDebugLog /var/log/apache2/modsec_debug.log
SecDebugLogLevel 0
๐ก Pro Tip ์ฒ์์๋ SecRuleEngine DetectionOnly๋ก ์ค์ ํด์ ์ค์ ๋ก ์ฐจ๋จํ์ง ์๊ณ ๋ก๊ทธ๋ง ๊ธฐ๋กํ๋ ๊ฒ์ ์ถ์ฒํด์. ์ ์ ํธ๋ํฝ์ด ์ฐจ๋จ๋๋ ์คํ(False Positive)์ ํ์ธํ๊ณ ๊ท์น์ ํ๋ํ ํ์ On์ผ๋ก ๋ณ๊ฒฝํ์ธ์! ๐ฏ
๐ 3๋จ๊ณ: OWASP Core Rule Set (CRS) ์ค์น
OWASP CRS๋ ModSecurity๋ฅผ ์ํ ํฌ๊ด์ ์ธ ๋ณด์ ๊ท์น ์ธํธ์์. ๋๋ถ๋ถ์ ์ผ๋ฐ์ ์ธ ์น ๊ณต๊ฒฉ์ ๋ฐฉ์ดํ ์ ์๋ ๊ท์น๋ค์ด ํฌํจ๋์ด ์์ฃ :
# CRS ๋ค์ด๋ก๋
cd /tmp
wget https://github.com/coreruleset/coreruleset/archive/v3.3.4.tar.gz
# ์์ถ ํด์
tar -xvzf v3.3.4.tar.gz
# ModSecurity ๋๋ ํ ๋ฆฌ๋ก ์ด๋
sudo mv coreruleset-3.3.4 /etc/modsecurity/crs
# ๊ธฐ๋ณธ ์ค์ ํ์ผ ๋ณต์ฌ
cd /etc/modsecurity/crs
sudo cp crs-setup.conf.example crs-setup.conf
# Apache ์ค์ ์ CRS ํฌํจ
sudo nano /etc/apache2/mods-enabled/security2.conf
security2.conf ํ์ผ์ ๋ค์ ๋ด์ฉ์ ์ถ๊ฐํ์ธ์:
<IfModule security2_module>
# ModSecurity ๊ธฐ๋ณธ ์ค์
Include /etc/modsecurity/modsecurity.conf
# OWASP CRS ์ค์
Include /etc/modsecurity/crs/crs-setup.conf
Include /etc/modsecurity/crs/rules/*.conf
</IfModule>
๐จ 4๋จ๊ณ: ๋ณด์ ๋ ๋ฒจ ์ค์ (Paranoia Level)
CRS๋ Paranoia Level์ด๋ผ๋ ๊ฐ๋ ์ผ๋ก ๋ณด์ ๊ฐ๋๋ฅผ ์กฐ์ ํด์. ๋ ๋ฒจ์ด ๋์์๋ก ๋ ๋ง์ ๊ท์น์ด ํ์ฑํ๋์ง๋ง ์คํ ๊ฐ๋ฅ์ฑ๋ ๋์์ ธ์:
# crs-setup.conf ํ์ผ ํธ์ง
sudo nano /etc/modsecurity/crs/crs-setup.conf
# Paranoia Level ์ค์ (1~4)
# Level 1: ๊ธฐ๋ณธ, ๋๋ถ๋ถ์ ํ๊ฒฝ์ ์ ํฉ
# Level 2: ์ถ๊ฐ ๋ณด์, ์ผ๋ถ ์คํ ๊ฐ๋ฅ
# Level 3: ๋์ ๋ณด์, ์คํ ์ฃผ์ ํ์
# Level 4: ์ต๊ณ ๋ณด์, ๋ง์ ์คํ ์์
SecAction \
"id:900000,\
phase:1,\
nolog,\
pass,\
t:none,\
setvar:tx.paranoia_level=1"
๐ง 5๋จ๊ณ: ์ปค์คํ ๊ท์น ์์ฑ
์์ ๋ง์ ๋ณด์ ๊ท์น์ ์์ฑํ ์๋ ์์ด์. ์๋ฅผ ๋ค์ด ํน์ IP๋ฅผ ์ฐจ๋จํ๊ฑฐ๋ ํน์ URL ํจํด์ ๋ณดํธํ๋ ๊ท์น์ ๋ง๋ค์ด๋ณผ๊ฒ์:
# ์ปค์คํ
๊ท์น ํ์ผ ์์ฑ
sudo nano /etc/modsecurity/custom-rules.conf
๋ค์์ ์ ์ฉํ ์ปค์คํ ๊ท์น ์์๋ค์ด์์:
# 1. ํน์ IP ์ฃผ์ ์ฐจ๋จ
SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \
"id:1001,\
phase:1,\
deny,\
status:403,\
log,\
msg:'Blocked IP address'"
# 2. SQL ์ธ์ ์
ํจํด ๊ฐ์ง
SecRule ARGS "@rx (?i)(union.*select|insert.*into|delete.*from)" \
"id:1002,\
phase:2,\
deny,\
status:403,\
log,\
msg:'SQL Injection attempt detected'"
# 3. ๊ด๋ฆฌ์ ํ์ด์ง ์ ๊ทผ ์ ํ (ํน์ IP๋ง ํ์ฉ)
SecRule REQUEST_URI "@beginsWith /admin" \
"id:1003,\
phase:1,\
chain,\
deny,\
status:403,\
log,\
msg:'Admin access denied'"
SecRule REMOTE_ADDR "!@ipMatch 10.0.0.0/8"
# 4. ํ์ผ ์
๋ก๋ ํ์ฅ์ ์ ํ
SecRule FILES_NAMES "@rx (?i)\.(php|exe|sh|bat)$" \
"id:1004,\
phase:2,\
deny,\
status:403,\
log,\
msg:'Dangerous file upload blocked'"
# 5. Rate Limiting (์ด๋น ์์ฒญ ์ ํ)
SecAction "id:1005,\
phase:1,\
nolog,\
pass,\
initcol:ip=%{REMOTE_ADDR}"
SecRule IP:REQUEST_COUNT "@gt 100" \
"id:1006,\
phase:1,\
deny,\
status:429,\
log,\
msg:'Rate limit exceeded',\
setvar:ip.request_count=+1"
# 6. User-Agent ๊ฒ์ฌ (๋ด ์ฐจ๋จ)
SecRule REQUEST_HEADERS:User-Agent "@rx (?i)(bot|crawler|spider|scraper)" \
"id:1007,\
phase:1,\
deny,\
status:403,\
log,\
msg:'Bot detected and blocked'"
# 7. XSS ๊ณต๊ฒฉ ํจํด ๊ฐ์ง
SecRule ARGS "@rx (?i)(<script|javascript:|onerror=|onload=)" \
"id:1008,\
phase:2,\
deny,\
status:403,\
log,\
msg:'XSS attack detected'"
์ปค์คํ ๊ท์น์ Apache ์ค์ ์ ํฌํจ์ํค์ธ์:
sudo nano /etc/apache2/mods-enabled/security2.conf
# ๋ค์ ์ค ์ถ๊ฐ
Include /etc/modsecurity/custom-rules.conf
๐งช 6๋จ๊ณ: ํ ์คํธ ๋ฐ ๊ฒ์ฆ
์ค์ ์ด ์ ๋๋ก ์๋ํ๋์ง ํ ์คํธํด๋ณผ๊น์:
# Apache ์ค์ ๋ฌธ๋ฒ ๊ฒ์ฌ
sudo apachectl configtest
# ๋ฌธ์ ๊ฐ ์์ผ๋ฉด Apache ์ฌ์์
sudo systemctl restart apache2
# ๋ก๊ทธ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง
sudo tail -f /var/log/apache2/modsec_audit.log
์ด์ ์ค์ ๊ณต๊ฒฉ์ ์๋ฎฌ๋ ์ด์ ํด์ WAF๊ฐ ์๋ํ๋์ง ํ์ธํด๋ด์:
# SQL ์ธ์ ์
ํ
์คํธ
curl "http://your-domain.com/test?id=1' OR '1'='1"
# XSS ํ
์คํธ
curl "http://your-domain.com/test?name=<script>alert('XSS')</script>"
# ๋๋ ํ ๋ฆฌ ํธ๋๋ฒ์ค ํ
์คํธ
curl "http://your-domain.com/../../etc/passwd"
์ด๋ฐ ์์ฒญ๋ค์ด ์ฐจ๋จ๋๊ณ ๋ก๊ทธ์ ๊ธฐ๋ก๋๋ฉด ์ฑ๊ณต์ด์์! ๐
โ ๏ธ ์ค์ํ ์ฃผ์์ฌํญ ํ๋ก๋์ ํ๊ฒฝ์์ ํ ์คํธํ์ง ๋ง์ธ์! ์ค์ ์๋น์ค ์ค์ธ ์น์ฌ์ดํธ์์ ๊ณต๊ฒฉ ์๋ฎฌ๋ ์ด์ ์ ํ๋ฉด ์ ์ ์ฌ์ฉ์์๊ฒ ์ํฅ์ ์ค ์ ์์ด์. ๋ฐ๋์ ๊ฐ๋ฐ ํ๊ฒฝ์ด๋ ์คํ ์ด์ง ํ๊ฒฝ์์ ์ถฉ๋ถํ ํ ์คํธํ ํ์ ํ๋ก๋์ ์ ์ ์ฉํ์ธ์. ๐จ
โ๏ธ AWS WAF ์ค์ ๊ฐ์ด๋
ํด๋ผ์ฐ๋ ํ๊ฒฝ์์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋๋ AWS WAF ์ค์ ๋ฐฉ๋ฒ๋ ์์๋ณผ๊ฒ์. AWS WAF๋ CloudFront, Application Load Balancer(ALB), API Gateway์ ํตํฉํด์ ์ฌ์ฉํ ์ ์์ด์.
๐ฌ 1๋จ๊ณ: Web ACL ์์ฑ
AWS Management Console์์ WAF & Shield ์๋น์ค๋ก ์ด๋ํ ํ:
1๏ธโฃ Web ACL ์์ฑ ์์
โข "Create web ACL" ๋ฒํผ ํด๋ฆญ
โข Name: ์) my-web-app-waf
โข CloudWatch metric name: ์๋ ์์ฑ๋จ
โข Resource type: CloudFront ๋๋ Regional resources ์ ํ
โข Region: ๋ฆฌ์์ค๊ฐ ์๋ ๋ฆฌ์ ์ ํ (CloudFront๋ Global)
2๏ธโฃ ๋ณดํธํ ๋ฆฌ์์ค ์ฐ๊ฒฐ
โข Add AWS resources ํด๋ฆญ
โข ALB, CloudFront distribution, ๋๋ API Gateway ์ ํ
โข ์ฌ๋ฌ ๋ฆฌ์์ค๋ฅผ ๋์์ ๋ณดํธํ ์ ์์ด์
๐ 2๋จ๊ณ: ๊ท์น ์ถ๊ฐ
AWS WAF๋ ๋ค์ํ ๋ฐฉ์์ผ๋ก ๊ท์น์ ์ถ๊ฐํ ์ ์์ด์:
๐ก๏ธ AWS Managed Rules ์ฌ์ฉ (์ถ์ฒ)
AWS๊ฐ ๊ด๋ฆฌํ๋ ์ฌ์ ๊ตฌ์ฑ๋ ๊ท์น ์ธํธ์์. ๊ฐ์ฅ ์ฝ๊ณ ๋น ๋ฅธ ๋ฐฉ๋ฒ์ด์ฃ :
โข Core rule set (CRS): OWASP Top 10 ์ํ ๋ฐฉ์ด
โข Known bad inputs: ์๋ ค์ง ์
์ฑ ์
๋ ฅ ์ฐจ๋จ
โข SQL database: SQL ์ธ์ ์
๋ฐฉ์ด
โข Linux operating system: Linux ๊ด๋ จ ๊ณต๊ฒฉ ๋ฐฉ์ด
โข PHP application: PHP ์ทจ์ฝ์ ๋ฐฉ์ด
โข WordPress application: WordPress ํนํ ๋ณดํธ
Add rules โ Add managed rule groups โ AWS managed rule groups์์ ํ์ํ ๊ท์น ์ ํ
โ๏ธ ์ปค์คํ
๊ท์น ์์ฑ
์์ ๋ง์ ๊ท์น์ ๋ง๋ค ์๋ ์์ด์. ์์๋ฅผ ๋ณผ๊น์:
# IP ๊ธฐ๋ฐ ์ฐจ๋จ ๊ท์น
{
"Name": "BlockSpecificIP",
"Priority": 1,
"Statement": {
"IPSetReferenceStatement": {
"Arn": "arn:aws:wafv2:region:account:regional/ipset/blocked-ips/..."
}
},
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BlockSpecificIP"
}
}
# Rate limiting ๊ท์น
{
"Name": "RateLimitRule",
"Priority": 2,
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP"
}
},
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimitRule"
}
}
# ํน์ ๊ฒฝ๋ก ๋ณดํธ ๊ท์น
{
"Name": "ProtectAdminPath",
"Priority": 3,
"Statement": {
"AndStatement": {
"Statements": [
{
"ByteMatchStatement": {
"SearchString": "/admin",
"FieldToMatch": {
"UriPath": {}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "LOWERCASE"
}
],
"PositionalConstraint": "STARTS_WITH"
}
},
{
"NotStatement": {
"Statement": {
"IPSetReferenceStatement": {
"Arn": "arn:aws:wafv2:region:account:regional/ipset/admin-ips/..."
}
}
}
}
]
}
},
"Action": {
"Block": {}
}
}
โ๏ธ 3๋จ๊ณ: ๊ธฐ๋ณธ ๋์ ์ค์
๊ท์น์ ๋งค์นญ๋์ง ์๋ ์์ฒญ์ ๋ํ ๊ธฐ๋ณธ ๋์์ ์ค์ ํด์:
โข Allow: ๋ชจ๋ ํธ๋ํฝ ํ์ฉ (๊ท์น์ผ๋ก ์ฐจ๋จํ ๊ฒ๋ง ์ฐจ๋จ)
โข Block: ๋ชจ๋ ํธ๋ํฝ ์ฐจ๋จ (๊ท์น์ผ๋ก ํ์ฉํ ๊ฒ๋ง ํ์ฉ)
๋๋ถ๋ถ์ ๊ฒฝ์ฐ Allow๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ค์ ํ๊ณ , ํน์ ๊ณต๊ฒฉ ํจํด๋ง ์ฐจ๋จํ๋ ๋ฐฉ์์ ์ฌ์ฉํด์.
๐ 4๋จ๊ณ: ๋ก๊น ๋ฐ ๋ชจ๋ํฐ๋ง ์ค์
AWS WAF์ ํ๋์ ์ถ์ ํ๊ณ ๋ถ์ํ๊ธฐ ์ํ ๋ก๊น ์ ์ค์ ํด์:
# CloudWatch Logs๋ก ๋ก๊น
์ค์
aws wafv2 put-logging-configuration \
--logging-configuration \
ResourceArn=arn:aws:wafv2:region:account:regional/webacl/...,\
LogDestinationConfigs=arn:aws:logs:region:account:log-group:aws-waf-logs-...
# S3๋ก ๋ก๊น
(Kinesis Data Firehose ์ฌ์ฉ)
aws wafv2 put-logging-configuration \
--logging-configuration \
ResourceArn=arn:aws:wafv2:region:account:regional/webacl/...,\
LogDestinationConfigs=arn:aws:firehose:region:account:deliverystream/aws-waf-logs-...
CloudWatch์์ ๋ค์๊ณผ ๊ฐ์ ๋ฉํธ๋ฆญ์ ๋ชจ๋ํฐ๋งํ ์ ์์ด์:
โข AllowedRequests: ํ์ฉ๋ ์์ฒญ ์
โข BlockedRequests: ์ฐจ๋จ๋ ์์ฒญ ์
โข CountedRequests: ์นด์ดํธ๋ง ๋ ์์ฒญ ์
โข PassedRequests: ๊ท์น ํ๊ฐ๋ฅผ ํต๊ณผํ ์์ฒญ ์
๐ฏ 5๋จ๊ณ: ์ค์ ์์ - ์์ ํ Web ACL ๊ตฌ์ฑ
์ค์ ํ๋ก๋์ ํ๊ฒฝ์์ ์ฌ์ฉํ ์ ์๋ ์์ ํ Web ACL ๊ตฌ์ฑ ์์์์:
{
"Name": "ProductionWebACL",
"Scope": "REGIONAL",
"DefaultAction": {
"Allow": {}
},
"Rules": [
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet",
"ExcludedRules": []
}
},
"OverrideAction": {
"None": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWSManagedRulesCommonRuleSet"
}
},
{
"Name": "AWSManagedRulesKnownBadInputsRuleSet",
"Priority": 2,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesKnownBadInputsRuleSet"
}
},
"OverrideAction": {
"None": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "AWSManagedRulesKnownBadInputsRuleSet"
}
},
{
"Name": "RateLimitPerIP",
"Priority": 3,
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP"
}
},
"Action": {
"Block": {
"CustomResponse": {
"ResponseCode": 429,
"CustomResponseBodyKey": "rate-limit-exceeded"
}
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "RateLimitPerIP"
}
},
{
"Name": "GeoBlockingRule",
"Priority": 4,
"Statement": {
"GeoMatchStatement": {
"CountryCodes": ["CN", "RU", "KP"]
}
},
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "GeoBlockingRule"
}
}
],
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "ProductionWebACL"
}
}
๐ฐ ๋น์ฉ ์ต์ ํ ํ
AWS WAF๋ ์ฌ์ฉ๋ ๊ธฐ๋ฐ ๊ณผ๊ธ์ด์์:
โข Web ACL: $5/์
โข ๊ท์น: $1/์ per rule
โข ์์ฒญ: $0.60 per 1 million requests
๋น์ฉ์ ์ ๊ฐํ๋ ค๋ฉด ๋ถํ์ํ ๊ท์น์ ์ ๊ฑฐํ๊ณ , CloudFront ์บ์ฑ์ ์ ๊ทน ํ์ฉํด์ WAF๋ก ์ ๋ฌ๋๋ ์์ฒญ ์๋ฅผ ์ค์ด์ธ์! ๐ธ
๐ WAF ๋ก๊ทธ ๋ถ์๊ณผ ํ๋
WAF๋ฅผ ์ค์นํ๋ ๊ฒ๋ง์ผ๋ก๋ ๋ถ์กฑํด์. ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง๊ณผ ํ๋์ด ํ์ํ์ฃ . ๋ก๊ทธ๋ฅผ ๋ถ์ํ๊ณ ์คํ์ ์ค์ด๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊ฒ์! ๐
๐ ๋ก๊ทธ ๋ถ์์ ์ค์์ฑ
WAF ๋ก๊ทธ๋ฅผ ๋ถ์ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ธ์ฌ์ดํธ๋ฅผ ์ป์ ์ ์์ด์:
โข ๊ณต๊ฒฉ ํจํด ํ์
: ์ด๋ค ์ข
๋ฅ์ ๊ณต๊ฒฉ์ด ์ผ๋ง๋ ์์ฃผ ๋ฐ์ํ๋์ง
โข ์คํ ๋ฐ๊ฒฌ: ์ ์ ํธ๋ํฝ์ด ์๋ชป ์ฐจ๋จ๋๋ ๊ฒฝ์ฐ ์๋ณ
โข ๊ท์น ํจ๊ณผ์ฑ: ๊ฐ ๊ท์น์ด ์ค์ ๋ก ์ผ๋ง๋ ์ ์ฉํ์ง ํ๊ฐ
โข ํธ๋ ๋ ๋ถ์: ์๊ฐ๋๋ณ, ์ง์ญ๋ณ ๊ณต๊ฒฉ ํธ๋ ๋ ํ์
โข ๋ณด์ ์ ์ฑ
๊ฐ์ : ๋ฐ์ดํฐ ๊ธฐ๋ฐ์ ๋ณด์ ์ ์ฑ
์๋ฆฝ
๐ ModSecurity ๋ก๊ทธ ๋ถ์
ModSecurity์ ๊ฐ์ฌ ๋ก๊ทธ(Audit Log)๋ JSON ํ์์ผ๋ก ์ ์ฅ๋ผ์. ์ค์ ๋ก๊ทธ ์์๋ฅผ ๋ณผ๊น์:
{
"transaction": {
"time": "15/Jan/2024:14:23:45 +0000",
"transaction_id": "YbJQ8CoAAQEAAHi-AAAAAA",
"remote_address": "192.168.1.100",
"remote_port": 54321
},
"request": {
"method": "GET",
"http_version": "HTTP/1.1",
"uri": "/login.php?id=1' OR '1'='1",
"headers": {
"Host": "example.com",
"User-Agent": "Mozilla/5.0...",
"Accept": "*/*"
}
},
"response": {
"status": 403,
"protocol": "HTTP/1.1"
},
"audit_data": {
"messages": [
{
"message": "SQL Injection Attack Detected",
"data": "Matched Data: ' OR '1'='1 found within ARGS:id",
"file": "/etc/modsecurity/crs/rules/REQUEST-942-APPLICATION-ATTACK-SQLI.conf",
"line": "1234",
"id": "942100",
"severity": "CRITICAL",
"tags": ["OWASP_CRS", "SQLI"]
}
]
}
}
์ด ๋ก๊ทธ๋ฅผ ๋ถ์ํ๊ธฐ ์ํ ์ ์ฉํ ๋ช ๋ น์ด๋ค์ด์์:
# ๊ฐ์ฅ ๋ง์ด ์ฐจ๋จ๋ IP ์ฃผ์ Top 10
cat /var/log/apache2/modsec_audit.log | \
grep -oP '"remote_address":\s*"\K[^"]+' | \
sort | uniq -c | sort -rn | head -10
# ๊ฐ์ฅ ๋ง์ด ํธ๋ฆฌ๊ฑฐ๋ ๊ท์น ID
cat /var/log/apache2/modsec_audit.log | \
grep -oP '"id":\s*"\K[^"]+' | \
sort | uniq -c | sort -rn | head -10
# ์๊ฐ๋๋ณ ๊ณต๊ฒฉ ๋น๋
cat /var/log/apache2/modsec_audit.log | \
grep -oP '"time":\s*"\K[^:]+' | \
cut -d'/' -f1 | \
sort | uniq -c
# ํน์ ๊ท์น ID๋ก ํํฐ๋ง
cat /var/log/apache2/modsec_audit.log | \
jq 'select(.audit_data.messages[].id == "942100")'
# ์ฐจ๋จ๋ ์์ฒญ์ URI ํจํด ๋ถ์
cat /var/log/apache2/modsec_audit.log | \
grep -oP '"uri":\s*"\K[^"]+' | \
sort | uniq -c | sort -rn | head -20
๐จ ์คํ(False Positive) ์ฒ๋ฆฌ ๋ฐฉ๋ฒ
์ ์์ ์ธ ํธ๋ํฝ์ด ์ฐจ๋จ๋๋ ์คํ์ ์ฌ์ฉ์ ๊ฒฝํ์ ํด์น๋ฏ๋ก ๋ฐ๋์ ํด๊ฒฐํด์ผ ํด์. ์คํ์ ์ฒ๋ฆฌํ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ด ์์ด์:
๋ฐฉ๋ฒ 1: ํน์ ๊ท์น ๋นํ์ฑํ
ํน์ ๊ท์น์ด ๊ณ์ ์คํ์ ์ผ์ผํจ๋ค๋ฉด ํด๋น ๊ท์น์ ๋นํ์ฑํํ ์ ์์ด์:
# ModSecurity ์ค์ ํ์ผ์ ์ถ๊ฐ
# ๊ท์น ID 942100์ ๋นํ์ฑํ
SecRuleRemoveById 942100
# ์ฌ๋ฌ ๊ท์น์ ํ๋ฒ์ ๋นํ์ฑํ
SecRuleRemoveById 942100 942110 942120
๋ฐฉ๋ฒ 2: ํน์ URL์ ๋ํด ๊ท์น ์์ธ ์ฒ๋ฆฌ
ํน์ ๊ฒฝ๋ก์์๋ง ๊ท์น์ ๋นํ์ฑํํ๊ณ ์ถ๋ค๋ฉด:
# /api/upload ๊ฒฝ๋ก์์๋ง ํ์ผ ์
๋ก๋ ๊ท์น ๋นํ์ฑํ
SecRule REQUEST_URI "@beginsWith /api/upload" \
"id:1100,\
phase:1,\
nolog,\
pass,\
ctl:ruleRemoveById=942100"
# /search ๊ฒฝ๋ก์์ SQL ์ธ์ ์
๊ท์น ์ํ
SecRule REQUEST_URI "@beginsWith /search" \
"id:1101,\
phase:1,\
nolog,\
pass,\
ctl:ruleRemoveTargetById=942100;ARGS:query"
๋ฐฉ๋ฒ 3: ํน์ ํ๋ผ๋ฏธํฐ ํ์ดํธ๋ฆฌ์คํธ
ํน์ ํ๋ผ๋ฏธํฐ์์๋ง ๊ท์น์ ์ ์ฉํ์ง ์์ผ๋ ค๋ฉด:
# 'content' ํ๋ผ๋ฏธํฐ๋ HTML ํ๊ทธ๋ฅผ ํฌํจํ ์ ์์ผ๋ฏ๋ก XSS ๊ท์น ์ ์ธ
SecRuleUpdateTargetById 941100 "!ARGS:content"
# ์ฌ๋ฌ ํ๋ผ๋ฏธํฐ๋ฅผ ํ๋ฒ์ ์ ์ธ
SecRuleUpdateTargetById 941100 "!ARGS:content" "!ARGS:description"
๋ฐฉ๋ฒ 4: IP ํ์ดํธ๋ฆฌ์คํธ
์ ๋ขฐํ ์ ์๋ IP ์ฃผ์๋ WAF ๊ฒ์ฌ๋ฅผ ๊ฑด๋๋ฐ๊ฒ ํ ์ ์์ด์:
# ํน์ IP ์ฃผ์ ํ์ดํธ๋ฆฌ์คํธ
SecRule REMOTE_ADDR "@ipMatch 10.0.0.0/8,172.16.0.0/12" \
"id:1200,\
phase:1,\
nolog,\
pass,\
ctl:ruleEngine=Off"
# ํน์ IP์์ ์ค๋ ์์ฒญ์ ๋ชจ๋ ๊ท์น ๋นํ์ฑํ
SecRule REMOTE_ADDR "@ipMatchFromFile /etc/modsecurity/whitelist-ips.txt" \
"id:1201,\
phase:1,\
nolog,\
pass,\
ctl:ruleEngine=Off"
๐ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง๊ณผ ์ต์ ํ
WAF๋ ๋ชจ๋ HTTP ์์ฒญ์ ๊ฒ์ฌํ๋ฏ๋ก ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ด์. ์ฑ๋ฅ์ ๋ชจ๋ํฐ๋งํ๊ณ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ด์์:
# Apache ์ํ ๋ชจ๋ ํ์ฑํ
sudo a2enmod status
# server-status ํ์ด์ง ์ค์
sudo nano /etc/apache2/mods-enabled/status.conf
status.conf์ ๋ค์ ๋ด์ฉ ์ถ๊ฐ:
<Location "/server-status">
SetHandler server-status
Require ip 127.0.0.1
</Location>
์ด์ http://localhost/server-status์์ ์ค์๊ฐ ์ฑ๋ฅ ์งํ๋ฅผ ํ์ธํ ์ ์์ด์.
์ฑ๋ฅ ์ต์ ํ ํ:
โข ์๋ต ๋ณธ๋ฌธ ๊ฒ์ฌ ๋นํ์ฑํ: SecResponseBodyAccess Off (ํ์ํ ๊ฒฝ์ฐ๋ง On)
โข ๋ก๊ทธ ๋ ๋ฒจ ์กฐ์ : ํ๋ก๋์
์์๋ SecDebugLogLevel 0
โข ๋ถํ์ํ ๊ท์น ์ ๊ฑฐ: ์ฌ์ฉํ์ง ์๋ CRS ๊ท์น ํ์ผ ์ ์ธ
โข ์ ๊ทํํ์ ์ต์ ํ: ๋ณต์กํ ์ ๊ทํํ์์ ์ฑ๋ฅ ์ ํ์ ์ฃผ๋ฒ
โข ์บ์ฑ ํ์ฉ: ์ ์ ์ฝํ
์ธ ๋ WAF ๊ฒ์ฌ ์ ์ ์บ์์์ ์๋น
๐ ๏ธ ๊ณ ๊ธ WAF ํ์ฉ ์ ๋ต
๊ธฐ๋ณธ์ ์ธ ์ค์ ์ ๋์ด์ WAF๋ฅผ ๋์ฑ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ๊ณ ๊ธ ์ ๋ต๋ค์ ์์๋ณผ๊ฒ์! ๐
๐ค ๋จธ์ ๋ฌ๋ ๊ธฐ๋ฐ ์ํ ํ์ง
์ต์ WAF ์๋ฃจ์ ๋ค์ ๋จธ์ ๋ฌ๋์ ํ์ฉํด์ ์๋ก์ด ๊ณต๊ฒฉ ํจํด์ ์๋์ผ๋ก ํ์ตํ๊ณ ํ์งํด์. AWS WAF์ ๊ฒฝ์ฐ Fraud Control์ด๋ Bot Control ๊ฐ์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฃ .
AWS WAF Bot Control ์ค์ ์์:
{
"Name": "BotControlRule",
"Priority": 10,
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesBotControlRuleSet",
"ManagedRuleGroupConfigs": [
{
"AWSManagedRulesBotControlRuleSet": {
"InspectionLevel": "COMMON"
}
}
]
}
},
"OverrideAction": {
"None": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "BotControlRule"
}
}
์ด ๊ท์น์ ๋ค์๊ณผ ๊ฐ์ ๋ด๋ค์ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์ฐจ๋จํด์:
โข ๊ฒ์ ์์ง ํฌ๋กค๋ฌ (ํ์ฉ ๊ฐ๋ฅ)
โข ์
์ฑ ์คํฌ๋ํผ
โข ์๋ํ๋ ๊ณต๊ฒฉ ๋๊ตฌ
โข ๊ณ์ ํ์ทจ ์๋ ๋ด
โข ์ฌ๊ณ ํ์ธ ๋ด (์ค๋์ปค ๋ด ๋ฑ)
๐ API ๋ณด์ ๊ฐํ
RESTful API๋ GraphQL API๋ฅผ ๋ณดํธํ๊ธฐ ์ํ ํน๋ณํ WAF ์ค์ ์ด ํ์ํด์:
API ์ ์ฉ ๋ณด์ ๊ท์น:
# JSON ํ์ด๋ก๋ ํฌ๊ธฐ ์ ํ
SecRule REQUEST_HEADERS:Content-Type "@contains application/json" \
"id:2001,\
phase:1,\
chain,\
pass,\
nolog"
SecRule REQUEST_BODY "@gt 1048576" \
"deny,\
status:413,\
msg:'JSON payload too large'"
# API ํค ๊ฒ์ฆ
SecRule REQUEST_URI "@beginsWith /api/" \
"id:2002,\
phase:1,\
chain,\
deny,\
status:401,\
msg:'Missing or invalid API key'"
SecRule &REQUEST_HEADERS:X-API-Key "@eq 0"
# Rate limiting (API๋ณ๋ก ๋ค๋ฅธ ์ ํ)
SecRule REQUEST_URI "@beginsWith /api/public" \
"id:2003,\
phase:1,\
pass,\
nolog,\
setvar:tx.rate_limit=100"
SecRule REQUEST_URI "@beginsWith /api/premium" \
"id:2004,\
phase:1,\
pass,\
nolog,\
setvar:tx.rate_limit=1000"
# GraphQL ์ฟผ๋ฆฌ ๊น์ด ์ ํ
SecRule REQUEST_BODY "@rx \"query\".*\{.*\{.*\{.*\{.*\{" \
"id:2005,\
phase:2,\
deny,\
status:400,\
msg:'GraphQL query too deep'"
# SQL ์ธ์ ์
(JSON ํ์ด๋ก๋ ๋ด๋ถ)
SecRule REQUEST_BODY "@rx (?i)(union.*select|insert.*into)" \
"id:2006,\
phase:2,\
deny,\
status:403,\
msg:'SQL injection in JSON payload'"
๐ ์ง๋ฆฌ์ ์ฐจ๋จ (Geo-blocking)
ํน์ ๊ตญ๊ฐ๋ ์ง์ญ์์ ์ค๋ ํธ๋ํฝ์ ์ฐจ๋จํ๋ ๊ฒ๋ ํจ๊ณผ์ ์ธ ๋ณด์ ์ ๋ต์ด์์:
ModSecurity์์ GeoIP ์ฌ์ฉ:
# GeoIP ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค์น
sudo apt install libmaxminddb0 libmaxminddb-dev mmdb-bin
# GeoIP ๋ชจ๋ ์ค์
SecGeoLookupDB /usr/share/GeoIP/GeoLite2-Country.mmdb
# ํน์ ๊ตญ๊ฐ ์ฐจ๋จ
SecRule REMOTE_ADDR "@geoLookup" \
"id:3001,\
phase:1,\
chain,\
deny,\
status:403,\
msg:'Access denied from blocked country'"
SecRule GEO:COUNTRY_CODE "@rx ^(CN|RU|KP)$"
# ํน์ ๊ตญ๊ฐ๋ง ํ์ฉ (ํ์ดํธ๋ฆฌ์คํธ ๋ฐฉ์)
SecRule REMOTE_ADDR "@geoLookup" \
"id:3002,\
phase:1,\
chain,\
deny,\
status:403,\
msg:'Access allowed only from specific countries'"
SecRule GEO:COUNTRY_CODE "!@rx ^(US|KR|JP)$"
# ๊ด๋ฆฌ์ ํ์ด์ง๋ ํน์ ๊ตญ๊ฐ์์๋ง ์ ๊ทผ ํ์ฉ
SecRule REQUEST_URI "@beginsWith /admin" \
"id:3003,\
phase:1,\
chain,\
deny,\
status:403,\
msg:'Admin access restricted by country'"
SecRule REMOTE_ADDR "@geoLookup" \
"chain"
SecRule GEO:COUNTRY_CODE "!@rx ^(KR)$"
๐ ๋์ IP ํํ ์์คํ
๊ณต๊ฒฉ์ ์๋ํ IP ์ฃผ์๋ฅผ ์๋์ผ๋ก ๋ธ๋๋ฆฌ์คํธ์ ์ถ๊ฐํ๋ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ด์:
# ๊ณต๊ฒฉ ์๋ ์นด์ดํฐ ์ฆ๊ฐ
SecRule REQUEST_URI "@rx (?i)(\.\.\/|etc\/passwd|union.*select)" \
"id:4001,\
phase:2,\
pass,\
log,\
msg:'Attack attempt detected',\
setvar:ip.attack_count=+1,\
expirevar:ip.attack_count=3600"
# 3ํ ์ด์ ๊ณต๊ฒฉ ์๋์ 1์๊ฐ ์ฐจ๋จ
SecRule IP:ATTACK_COUNT "@gt 2" \
"id:4002,\
phase:1,\
deny,\
status:403,\
msg:'IP temporarily blocked due to multiple attack attempts',\
setvar:ip.blocked=1,\
expirevar:ip.blocked=3600"
# ์ฐจ๋จ๋ IP ํ์ธ
SecRule IP:BLOCKED "@eq 1" \
"id:4003,\
phase:1,\
deny,\
status:403,\
msg:'IP is currently blocked'"
๐ฑ ๋ชจ๋ฐ์ผ ์ฑ API ๋ณดํธ
๋ชจ๋ฐ์ผ ์ฑ์ API๋ฅผ ๋ณดํธํ๊ธฐ ์ํ ํน๋ณํ ์ ๋ต์ด์์:
1. ์ฑ ์ธ์ฆ (App Attestation)
์ ํ ์ฑ์์๋ง API ํธ์ถ์ ํ์ฉํ๋๋ก ์ค์ :
# iOS App Attestation ๊ฒ์ฆ
SecRule REQUEST_HEADERS:X-App-Attestation "@rx ^[A-Za-z0-9+/=]+$" \
"id:5001,\
phase:1,\
pass,\
nolog,\
setvar:tx.app_verified=1"
SecRule TX:APP_VERIFIED "!@eq 1" \
"id:5002,\
phase:1,\
deny,\
status:401,\
msg:'App attestation required'"
# Android SafetyNet ๊ฒ์ฆ
SecRule REQUEST_HEADERS:X-SafetyNet-Token "@rx ^[A-Za-z0-9._-]+$" \
"id:5003,\
phase:1,\
pass,\
nolog,\
setvar:tx.safetynet_verified=1"
2. ์ธ์ฆ์ ํผ๋ (Certificate Pinning) ๊ฒ์ฆ
HTTPS ์ฐ๊ฒฐ์ ์ธ์ฆ์๋ฅผ ๊ฒ์ฆํด์ ์ค๊ฐ์ ๊ณต๊ฒฉ์ ๋ฐฉ์ง:
# ํน์ ์ธ์ฆ์ ์ง๋ฌธ๋ง ํ์ฉ
SecRule REQUEST_HEADERS:X-Certificate-Fingerprint \
"!@rx ^(abc123def456|789ghi012jkl)$" \
"id:5004,\
phase:1,\
deny,\
status:403,\
msg:'Invalid certificate fingerprint'"
3. ๋๋ฐ์ด์ค ํ๊ฑฐํ๋ฆฐํ
์์ฌ์ค๋ฌ์ด ๋๋ฐ์ด์ค๋ฅผ ์๋ณํ๊ณ ์ฐจ๋จ:
# ๋ฃจํ
/ํ์ฅ๋ ๋๋ฐ์ด์ค ์ฐจ๋จ
SecRule REQUEST_HEADERS:X-Device-Jailbroken "@eq true" \
"id:5005,\
phase:1,\
deny,\
status:403,\
msg:'Jailbroken/rooted devices not allowed'"
# ์๋ฎฌ๋ ์ดํฐ ์ฐจ๋จ
SecRule REQUEST_HEADERS:X-Device-Emulator "@eq true" \
"id:5006,\
phase:1,\
deny,\
status:403,\
msg:'Emulators not allowed'"
๐ก ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ ์ฐพ๊ธฐ ์ด๋ฐ ๊ณ ๊ธ WAF ์ค์ ์ ์ ๋ฌธ ์ง์์ด ํ์ํด์. ์ฌ๋ฅ๋ท์์๋ ๋ณด์ ์ ๋ฌธ๊ฐ, ํด๋ผ์ฐ๋ ์ํคํ ํธ, DevSecOps ์์ง๋์ด ๋ฑ ๋ค์ํ ์ ๋ฌธ๊ฐ๋ค์ ๋์์ ๋ฐ์ ์ ์์ด์. ์ค์ ๊ฒฝํ์ด ํ๋ถํ ์ ๋ฌธ๊ฐ์ ํจ๊ป๋ผ๋ฉด ์ฌ๋ฌ๋ถ์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์ฑ ์์ ํ๊ฒ ๋ณดํธํ ์ ์๋ต๋๋ค! ๐ก๏ธ
๐จ WAF ์ด์ ์ ์ฃผ์์ฌํญ๊ณผ ๋ฒ ์คํธ ํ๋ํฐ์ค
WAF๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ด์ํ๊ธฐ ์ํ ์ค์ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํ ๊ฒ์! ๐ช
โ ๋ฒ ์คํธ ํ๋ํฐ์ค
1๏ธโฃ ๋จ๊ณ์ ๋ฐฐํฌ
Detection Only โ Learning โ Prevention
์ฒ์๋ถํฐ ์ฐจ๋จ ๋ชจ๋๋ก ์ด์ํ์ง ๋ง์ธ์. ๋จผ์ ํ์ง๋ง ํ๋ฉด์ ๋ก๊ทธ๋ฅผ ๋ถ์ํ๊ณ , ์คํ์ ์ ๊ฑฐํ ํ์ ์ฐจ๋จ ๋ชจ๋๋ก ์ ํํ์ธ์.
2๏ธโฃ ์ ๊ธฐ์ ์ธ ๊ท์น ์ ๋ฐ์ดํธ
์ต์ ์ํ์ ๋์
OWASP CRS๋ ๊ด๋ฆฌํ ๊ท์น ์ธํธ๋ฅผ ์ ๊ธฐ์ ์ผ๋ก ์
๋ฐ์ดํธํ์ธ์. ์๋ก์ด ์ทจ์ฝ์ ๊ณผ ๊ณต๊ฒฉ ๊ธฐ๋ฒ์ด ๊ณ์ ๋ฑ์ฅํ๋๊น์.
3๏ธโฃ ๋ฐฑ์ ๊ณผ ๋กค๋ฐฑ ๊ณํ
์์ ํ ๋ณ๊ฒฝ ๊ด๋ฆฌ
WAF ์ค์ ์ ๋ณ๊ฒฝํ๊ธฐ ์ ์ ํญ์ ๋ฐฑ์
ํ๊ณ , ๋ฌธ์ ๋ฐ์ ์ ์ฆ์ ๋กค๋ฐฑํ ์ ์๋ ๊ณํ์ ์ธ์ฐ์ธ์.
4๏ธโฃ ๋ชจ๋ํฐ๋ง๊ณผ ์๋ฆผ
์ค์๊ฐ ์ํ ๋์
CloudWatch, Prometheus, Grafana ๋ฑ์ ํ์ฉํด์ WAF ๋ฉํธ๋ฆญ์ ์ค์๊ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ , ์ด์ ์งํ ๋ฐ๊ฒฌ ์ ์ฆ์ ์๋ฆผ์ ๋ฐ์ผ์ธ์.
5๏ธโฃ ๋ฌธ์ํ
์ง์ ๊ณต์ ์ ์ ์ง๋ณด์
๋ชจ๋ ์ปค์คํ
๊ท์น๊ณผ ์์ธ ์ฒ๋ฆฌ์ ๋ํด ๋ช
ํํ๊ฒ ๋ฌธ์ํํ์ธ์. ์ ์ด ๊ท์น์ ์ถ๊ฐํ๋์ง, ์ด๋ค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋์ง ๊ธฐ๋กํ์ธ์.
6๏ธโฃ ์ ๊ธฐ์ ์ธ ๋ณด์ ํ ์คํธ
ํจ๊ณผ์ฑ ๊ฒ์ฆ
์นจํฌ ํ
์คํธ๋ ์ทจ์ฝ์ ์ค์บ์ ์ ๊ธฐ์ ์ผ๋ก ์ํํด์ WAF๊ฐ ์ค์ ๋ก ๊ณต๊ฒฉ์ ์ ๋ง๊ณ ์๋์ง ํ์ธํ์ธ์.
โ ๏ธ ํผํด์ผ ํ ์ค์๋ค
โ ํ์ง ๋ง์์ผ ํ ๊ฒ๋ค:
1. ๊ณผ๋ํ ๊ท์น ์ค์
๋๋ฌด ๋ง์ ๊ท์น์ ํ์ฑํํ๋ฉด ์ฑ๋ฅ์ด ์ ํ๋๊ณ ์คํ์ด ์ฆ๊ฐํด์. ํ์ํ ๊ท์น๋ง ์ ํ์ ์ผ๋ก ์ฌ์ฉํ์ธ์.
2. ๋ก๊ทธ ๋ถ์ ์ํ
WAF๋ฅผ ์ค์น๋ง ํ๊ณ ๋ก๊ทธ๋ฅผ ํ์ธํ์ง ์์ผ๋ฉด ๊ณต๊ฒฉ์ ๋์น๊ฑฐ๋ ์คํ์ ๋ฐ๊ฒฌํ์ง ๋ชปํด์.
3. ํ์ดํธ๋ฆฌ์คํธ ๋จ์ฉ
ํธ์๋ฅผ ์ํด ๋๋ฌด ๋ง์ IP๋ ๊ฒฝ๋ก๋ฅผ ํ์ดํธ๋ฆฌ์คํธ์ ์ถ๊ฐํ๋ฉด ๋ณด์ ๊ตฌ๋ฉ์ด ์๊ฒจ์.
4. ์
๋ฐ์ดํธ ๋ฏธ๋ฃจ๊ธฐ
WAF ์ํํธ์จ์ด๋ ๊ท์น ์ธํธ๋ฅผ ์ค๋ ์
๋ฐ์ดํธํ์ง ์์ผ๋ฉด ์๋ก์ด ๊ณต๊ฒฉ์ ์ทจ์ฝํด์ ธ์.
5. ๋จ์ผ ๋ฐฉ์ด์ ์์กด
WAF๋ง์ผ๋ก ๋ชจ๋ ๋ณด์์ ํด๊ฒฐํ๋ ค๊ณ ํ์ง ๋ง์ธ์. ๋ค์ธต ๋ฐฉ์ด ์ ๋ต์ด ํ์ํด์.
๐ WAF ์ด์ ์ฒดํฌ๋ฆฌ์คํธ
| ์ฃผ๊ธฐ | ์์ | ๋ด๋น |
|---|---|---|
| ๋งค์ผ | โข ์ฐจ๋จ๋ ์์ฒญ ๋ก๊ทธ ํ์ธ โข ์ด์ ํธ๋ํฝ ํจํด ๋ชจ๋ํฐ๋ง โข ์๋ฆผ ํ์ธ ๋ฐ ๋์ |
๋ณด์ ์ด์ํ |
| ๋งค์ฃผ | โข ์คํ ๋ถ์ ๋ฐ ๊ท์น ํ๋ โข ์ฑ๋ฅ ๋ฉํธ๋ฆญ ๋ฆฌ๋ทฐ โข ์๋ก์ด ๊ณต๊ฒฉ ํจํด ๋ถ์ |
๋ณด์ ์์ง๋์ด |
| ๋งค์ | โข ๊ท์น ์ธํธ ์
๋ฐ์ดํธ โข ๋ณด์ ์ ์ฑ ๋ฆฌ๋ทฐ โข ํธ๋ ๋ ๋ถ์ ๋ฆฌํฌํธ ์์ฑ |
๋ณด์ ๊ด๋ฆฌ์ |
| ๋ถ๊ธฐ๋ณ | โข ์นจํฌ ํ
์คํธ ์ํ โข WAF ํจ๊ณผ์ฑ ํ๊ฐ โข ๋ณด์ ์ ์ฑ ๊ฐ์ |
๋ณด์ ํ ์ ์ฒด |
| ์ฐ๊ฐ | โข ์ ์ฒด ๋ณด์ ์ํคํ
์ฒ ๋ฆฌ๋ทฐ โข WAF ์๋ฃจ์ ์ฌํ๊ฐ โข ์์ฐ ๋ฐ ๋ฆฌ์์ค ๊ณํ |
CISO/๋ณด์ ์ฑ ์์ |
๐ ํ ๊ต์ก๊ณผ ์ญ๋ ๊ฐํ
WAF๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ด์ํ๋ ค๋ฉด ํ์๋ค์ ๋ณด์ ์ญ๋์ด ์ค์ํด์:
์ถ์ฒ ํ์ต ๋ฆฌ์์ค:
โข OWASP Top 10: ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ฃผ์ ๋ณด์ ์ํ ์ดํด
โข ModSecurity Handbook: ModSecurity ๊ณต์ ๊ฐ์ด๋
โข AWS WAF Workshop: AWS ๊ณต์ ํธ์ฆ์จ ์ํฌ์ต
โข SANS SEC542: ์น ์ ํ๋ฆฌ์ผ์ด์
์นจํฌ ํ
์คํธ ๊ณผ์
โข Certified Ethical Hacker (CEH): ์ค๋ฆฌ์ ํดํน ์๊ฒฉ์ฆ
์ค์ต ํ๊ฒฝ ๊ตฌ์ถ:
โข DVWA (Damn Vulnerable Web Application): ์ทจ์ฝํ ์น ์ฑ์ผ๋ก ๊ณต๊ฒฉ ์ค์ต
โข WebGoat: OWASP์ ๊ต์ก์ฉ ์ทจ์ฝํ ์น ์ ํ๋ฆฌ์ผ์ด์
โข Juice Shop: ํ๋์ ์ธ ์น ๊ธฐ์ ์คํ์ ์ทจ์ฝ์ ํ์ต
โข HackTheBox: ์ค์ ๊ฐ์ ํดํน ์ฑ๋ฆฐ์ง ํ๋ซํผ
๐ฎ WAF์ ๋ฏธ๋์ ํธ๋ ๋
์น ๋ณด์ ๊ธฐ์ ์ ๊ณ์ ์งํํ๊ณ ์์ด์. ์์ผ๋ก WAF๊ฐ ์ด๋ป๊ฒ ๋ฐ์ ํ ์ง ์ดํด๋ณผ๊น์? ๐
๐ค AI/ML ๊ธฐ๋ฐ ์ง๋ฅํ WAF
์ธ๊ณต์ง๋ฅ๊ณผ ๋จธ์ ๋ฌ๋์ ํ์ฉํ ์ฐจ์ธ๋ WAF๊ฐ ๋ฑ์ฅํ๊ณ ์์ด์:
โข ํ์ ๊ธฐ๋ฐ ์ด์ ํ์ง: ์ ์ ํธ๋ํฝ ํจํด์ ํ์ตํ๊ณ ์ด์ ํ์๋ฅผ ์๋์ผ๋ก ๊ฐ์ง
โข ์ ๋ก๋ฐ์ด ๊ณต๊ฒฉ ๋์: ์๋ ค์ง์ง ์์ ์๋ก์ด ๊ณต๊ฒฉ๋ ํจํด ๋ถ์์ผ๋ก ํ์ง
โข ์๋ ๊ท์น ์์ฑ: ๊ณต๊ฒฉ ํจํด์ ๋ถ์ํด์ ์๋์ผ๋ก ๋ฐฉ์ด ๊ท์น ์์ฑ
โข ์คํ ์๋ ๊ฐ์: ๋จธ์ ๋ฌ๋์ผ๋ก ์คํ์ ํ์ตํ๊ณ ์๋์ผ๋ก ๊ท์น ํ๋
โข ์์ธก์ ๋ฐฉ์ด: ๊ณต๊ฒฉ ์งํ๋ฅผ ์ฌ์ ์ ๊ฐ์งํ๊ณ ์ ์ ์ ์ผ๋ก ๋์
โ๏ธ ์๋ฒ๋ฆฌ์ค WAF
์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ์ ์ต์ ํ๋ WAF๊ฐ ๋ฐ์ ํ๊ณ ์์ด์:
โข Lambda@Edge WAF: CloudFront ์ฃ์ง์์ ์คํ๋๋ ๊ฒฝ๋ WAF
โข API Gateway ํตํฉ: ์๋ฒ๋ฆฌ์ค API๋ฅผ ์ํ ๋ค์ดํฐ๋ธ ๋ณด์
โข ์ด๋ฒคํธ ๊ธฐ๋ฐ ๋ฐฉ์ด: ๊ณต๊ฒฉ ๊ฐ์ง ์ ์๋์ผ๋ก Lambda ํจ์ ์คํ
โข ๋ง์ดํฌ๋ก์๋น์ค ๋ณดํธ: ๊ฐ ๋ง์ดํฌ๋ก์๋น์ค๋ณ ๋
๋ฆฝ์ ์ธ WAF ์ ์ฑ
๐ ์ฃ์ง ์ปดํจํ ๊ณผ WAF
5G์ ์ฃ์ง ์ปดํจํ ์ ๋ฐ์ ์ผ๋ก WAF๋ ์ฃ์ง๋ก ์ด๋ํ๊ณ ์์ด์:
โข ์ด์ ์ง์ฐ ๋ฐฉ์ด: ์ฌ์ฉ์์ ๊ฐ๊น์ด ์ฃ์ง์์ ์ฆ์ ๊ณต๊ฒฉ ์ฐจ๋จ
โข ๋ถ์ฐ ๋ฐฉ์ด: ์ ์ธ๊ณ ์ฃ์ง ๋
ธ๋์์ ๋์์ ๋ฐฉ์ด
โข IoT ๋ณด์: IoT ๋๋ฐ์ด์ค์ API๋ฅผ ์ฃ์ง์์ ๋ณดํธ
โข 5G ๋คํธ์ํฌ ์ฌ๋ผ์ด์ฑ: ๋คํธ์ํฌ ๋ ๋ฒจ์์ ๋ณด์ ์ ์ฑ
์ ์ฉ
๐ Zero Trust ์ํคํ ์ฒ์ WAF
Zero Trust ๋ณด์ ๋ชจ๋ธ์ด ํ์ฐ๋๋ฉด์ WAF์ ์ญํ ๋ ๋ณํํ๊ณ ์์ด์:
โข ์ง์์ ์ธ ๊ฒ์ฆ: ๋ชจ๋ ์์ฒญ์ ๋งค๋ฒ ๊ฒ์ฆ
โข ๋ง์ดํฌ๋ก ์ธ๊ทธ๋ฉํ
์ด์
: ์ธ๋ฐํ ์ ๊ทผ ์ ์ด
โข ์ปจํ
์คํธ ๊ธฐ๋ฐ ์ ์ฑ
: ์ฌ์ฉ์, ๋๋ฐ์ด์ค, ์์น, ์๊ฐ ๋ฑ์ ๊ณ ๋ คํ ๋์ ์ ์ฑ
โข ํตํฉ ๋ณด์ ํ๋ซํผ: IAM, SIEM, SOAR๊ณผ์ ๊ธด๋ฐํ ํตํฉ
๐ ์๋ํ์ DevSecOps
๋ณด์์ด ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ํตํฉ๋๋ฉด์ WAF๋ ์๋ํ๋๊ณ ์์ด์:
# Infrastructure as Code๋ก WAF ๊ด๋ฆฌ
# Terraform ์์
resource "aws_wafv2_web_acl" "main" {
name = "production-waf"
scope = "REGIONAL"
default_action {
allow {}
}
rule {
name = "RateLimitRule"
priority = 1
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
action {
block {}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimitRule"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "ProductionWAF"
sampled_requests_enabled = true
}
}
# CI/CD ํ์ดํ๋ผ์ธ์ WAF ํ
์คํธ ํตํฉ
# GitLab CI ์์
waf_test:
stage: security
script:
- echo "Testing WAF rules..."
- python test_waf_rules.py
- echo "Checking for false positives..."
- python check_false_positives.py
only:
- main
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.