๐บ ๋ชฉ์ฐจ ๐บ(๋ณด์๋ ค๋ฉด ์๋ ๋๋ณด๊ธฐ ๋ฅผ ๋๋ฌ์ฃผ์ธ์.)
1. Nginx + ModSecurity + Fail2ban + Docker => 1. ์ทจ์ฝํ ์น์ฌ์ดํธ
2. Nginx + ModSecurity + Fail2ban + Docker => 2. ModSecurity + Fail2ban ์ค์น
3. Nginx + ModSecurity + Fail2ban + Docker => 3. Fail2ban ์ค์ ๋ฐฉ๋ฒ
4. Nginx + ModSecurity + Fail2ban + Docker => 4. Nginx Limit req ์ค์
5. Nginx + ModSecurity + Fail2ban + Docker => 5. Dockerhub ์ด๋ฏธ์ง ์ฌ์ฉ
1. ์ํ์ด ์ฝ๋ฉ์ ์๊ธฐ ์
์๋ ์ ์น์๋น์ค ํ๋๋ฅผ ๋ง๋ค์ด์ ์ด์์ ํ์๋ต๋๋ค. ์ฒ์์๋ cafe24 ํธ์คํ ์๋น์ค๋ฅผ ์ด์ฉํ์์ผ๋ฉฐ, ๊ฑฐ๊ธฐ์ ๋ฌด๋ฃ ๋ณด์ ์๋น์ค๋ค์ ๋ชจ๋ ์ด์ฉํ๊ณ ์์์ง์. ๊ทธ ํ AWS EC2 ํ๋ฆฌํฐ์ด๋ฅผ ์๊ฒ ๋์๊ณ , ์๋ฒ๋ฅผ ์ฎ๊ธฐ๊ฒ ๋์์ต๋๋ค. ๋ฆฌ๋ ์ค์ ๊ตฌ์ถํ๋ฉด์, ์ฐ์ฐํ ์๊ฒ๋ modsecurity๋ฅผ ์ค์นํ๊ฒ ๋์์ต๋๋ค. ๊ทธ๋๊น์ง๋ modsecurity๊ฐ ์ด๋ค ์ญํ ์ ํ๋์ง ์๋ฌด๊ฒ๋ ์์ง ๋ชปํ ์ฑ๋ก ๊ทธ๋ฅ ์ฌ์ฉ์ ํ์๋ต๋๋ค.
๊ทธ๋ฆฌ๊ณ , ์ฌํด ์ฌ๋ฆ ๋ฐฉํ ๋ ํดํน๊ณผ ๋ณด์ ๊ด๋ จ ์ฐ์๋ฅผ ๋ฐ๊ฒ ๋์์ต๋๋ค. ๊ฑฐ๊ธฐ์ ๋ฐฐ์ฐ๊ฒ ๋ ์นํดํน ๋ฐฉ๋ฒ์ผ๋ก ์ ๊ฐ ๋ง๋ ์น์๋น์ค๋ฅผ ํ ์คํธ ํด๋ณด์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ ๋๋ฌด ๋ถ๋๋ฌ์ ์ต๋๋ค. ์ํ์ด ์ฝ๋ฉ์ ์ ํ ์์ง ๋ชปํ๋ ๋ถ์กฑํ ์ทจ๋ฏธ ์ค๋ ฅ์ผ๋ก ์์ฑํ ๊ฒ์ด๋ผ ๋๋ฌด๋ ๋ง์ ๋ณด์ ๋ฌธ์ ๊ฐ ์์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๊ทธ๋๋ง ์ ๋ง ๋คํ์ด์๋ ๊ฒ์ ์ฐ์ฐํ ์ค์นํ๊ฒ ๋ modsecurity ๊ฐ ๊ทธ ๋ชจ๋ ๊ฒ์ ์กฐ์ฉํ ๋ง์์ฃผ๊ณ ์์๋ค๋ ๊ฒ์ด์์ต๋๋ค.
๊ทธ๋์์ผ ์ํ์ด ์ฝ๋ฉ์ ์ค์์ฑ์ ์๊ฒ ๋์์ผ๋ฉฐ, ์น์๋น์ค์ ์์ค๋ฅผ ์ ๋ฉด ์์ ํ๊ฒ ๋์์ง์. ๊ทธ๋ฆฌ๊ณ , ์น๋ฐฉํ๋ฒฝ์ธ modsecurity์ ๊ธฐ๋ฅ๋ ์ ์๊ฒ ๋์์ต๋๋ค.
์ต๊ทผ์ docker ๋ฅผ ์๊ฒ ๋์๊ณ , ์ ๊ฐ ๋ง๋ ๋ชจ๋ ์๋น์ค๋ค์ docker๋ฅผ ์ด์ฉํ์ฌ ์๋น์ค๋๋๋ก ๋ชจ๋ ๋ฐ๊พธ๋ ์์ ์ ํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋ฉด์, modsecurity๋ ๋์ปค๋ฅผ ์ด์ฉํ์ฌ ์ค์นํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๊ฒ ๋์์ต๋๋ค.
์ฒ์ ํด๋ณด๋ ์์ ์ด๋ผ ์์ฒญ ์ฝ์ง์ ํ๊ฒ ๋์๊ณ , ๊ฒฐ๊ตญ ๋ชจ๋ ์์ ์ ๋ง๋ฌด๋ฆฌํ์์ต๋๋ค. ์ด์ ์์ง ์๊ธฐ ์ํด, ๊ทธ๋ฆฌ๊ณ ํน์ ๋ชจ๋ฅผ ์ ์ ๋น์ทํ ์ค๋ ฅ ๋ถ์กฑํ ์ทจ๋ฏธ ๊ฐ๋ฐ์๋ค์ ์ํด ๊ณต๋ถํ๋ ๋ด์ฉ์ ๊ธฐ๋กํด๋ก๋๋ค.
์๋ ๋ด์ฉ ์์๋ ์ฐ์ ๋ณด์์ด ์ทจ์ฝํ ์น์ฌ์ดํธ๋ฅผ ๋ง๋ ํ, ๊ฑฐ๊ธฐ์ ์น๋ฐฉํ๋ฒฝ์ธ modsecurity๋ฅผ ์ค์น ํ ์ด๋ป๊ฒ ๋ฌ๋ผ์ง๋์ง ํ์ธ์ ํ ๊ฒ์ ๋๋ค.
๋ํ, ์ด๋ฒ์ ๊ณต๋ถํ๋ฉด์ ์๋กญ๊ฒ ์๊ฒ ๋ fail2ban(๋ฌด์ฐจ๋ณ ๋์ ๊ณต๊ฒฉ ๋ณดํธ)๋ ์ค์น ๋ฐ ์ฌ์ฉ๋ฒ๋ ๊ฐ์ด ์์๋ณผ ๊ฒ์ ๋๋ค.
2. ๋ณด์์ด ์ทจ์ฝํ ์น์์ค
๊ฐ. ์น์์ค ๋ค์ด๋ก๋
PHP๋ก ์์ฃผ ๋จ์ํ ๋ก๊ทธ์ธ ์นํ์ด์ง๋ฅผ ๋ง๋ค์์ต๋๋ค. ์ด ์นํ์ด์ง๋ ๋ณด์์ ์ ํ ๊ณ ๋ คํ์ง ์์, ๊ทธ๋์ ์ค์ ๋ก ์ฌ์ฉ์ ํด์๋ ์ ๋๋ก ์๋๋ ์์ค์์ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
PHP ์์ค์ ๋ํ ๊ตฌ์ฒด์ ์ธ ์ค๋ช ์ ๋ฐ๋ก ํ์ง ์์ต๋๋ค. ์์ค๋ ์๋ ๋งํฌ์์ ์ด๊ธฐ ํ์ผ์ ๋ค์ด๋ฐ์ผ์ค ์ ์์ต๋๋ค. ๋ค์ด๋ฐ์ผ์ ํ ๊ทธ ์์ ์๋ docker-compose.yml์ ์ด์ฉํ์ฌ ๋์ปค ์ปจํ ์ด๋๋ฅผ ์์ฑํ์๋ฉด ๋ฉ๋๋ค. ๋์ปค ์ฌ์ฉ๋ฒ์ ๋ํ ๋ด์ฉ๋ ์ฌ๊ธฐ์๋ ๋ค๋ฃจ์ง ์๊ฒ ์ต๋๋ค.
https://github.com/mmssem/ModSecurityFail2ban/releases/tag/%EC%B4%88%EA%B8%B0%ED%8C%8C%EC%9D%BC
๋. docker-compose.yml ๋ด์ฉ
๋ณธ ์๋น์ค๋ ์์ ๊ฐ์ด ๊ตฌ์ฑ๋์ด ์์ต๋๋ค. ๋จผ์ ์๋จ์ proxy ๊ธฐ๋ฅ์ ํ๋ nginx๋ฅผ ๋๊ณ ์์ผ๋ฉฐ, ๊ทธ ๋ท๋จ์ ์ค์ ์น์๋ฒ ๋ฐ mysql ์๋ฒ๋ฅผ ๋๊ณ ์์ต๋๋ค. ์ด๋ ๊ฒ ํ๋ ๊ฒ๋ ๋ณด์ ์ธก๋ฉด์์ ์ข๋ค๊ณ ํฉ๋๋ค.
version: '3.9'
networks:
mung_net:
driver: bridge
services:
front_nginx:
container_name: front_nginx_cname
image: nginx:1.23.2-alpine
restart: always
ports:
- "80:80" #web
- "81:81" #web2
- "82:82" #phpmyadmin
volumes:
- ./docker/front/default.conf:/etc/nginx/conf.d/default.conf
- ./docker/front/nginx.conf:/etc/nginx/nginx.conf
depends_on:
- web
- web2
networks:
- mung_net
web:
image: nginx:1.23.2
container_name: nginx_cname
restart: unless-stopped
volumes:
- ./www/data:/var/www
- ./docker/conf/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php_serv
expose:
- "80"
networks:
- mung_net
web2:
image: nginx:1.23.2
container_name: nginx_cname2
restart: unless-stopped
volumes:
- ./www/data2:/var/www
- ./docker/conf/default2.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php2_serv
expose:
- "80"
networks:
- mung_net
php_serv:
container_name: php_cname
build:
context: ./docker/php
dockerfile: Dockerfile
restart: unless-stopped
working_dir: /var/www
volumes:
- ./www/data:/var/www
expose:
- "9000"
networks:
- mung_net
php2_serv:
container_name: php2_cname
build:
context: ./docker/php
dockerfile: Dockerfile
restart: unless-stopped
working_dir: /var/www
volumes:
- ./www/data2:/var/www
expose:
- "9000"
networks:
- mung_net
mysql_serv:
image: mysql:latest
container_name: mysql_cname
restart: unless-stopped
expose:
- "3306"
volumes:
- ./docker/mysql/conf.d:/etc/mysql/conf.d
- ./docker/mysql:/docker-entrypoint-initdb.d
- ./../mysql_data/mysql:/var/lib/mysql
environment:
MYSQL_DATABASE: testdb
MYSQL_ROOT_PASSWORD: password
MYSQL_PASSWORD: password
MYSQL_USER: admin
SERVICE_TAGS: mysqlservicetags
SERVICE_NAME: mysqlservicename
TZ: Asia/Seoul
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
networks:
- mung_net
phpmyadmin_serv:
image: phpmyadmin:latest
container_name: phpmyadmin_cname
environment:
PMA_HOST: mysql
PMA_PORT: 3306
PMA_ARBITRARY: 1
restart: always
expose:
- "80"
depends_on:
- mysql_serv
networks:
- mung_net
๋ค. ์ทจ์ฝํ ๋ณด์ ์์
1) http://127.0.0.1 ๋ก ์ ์ํ ํ ์์ด๋๋ admin, ํจ์ค์๋๋ pass1234๋ฅผ ์ ๋ ฅํ๋ฉด ๋ก๊ทธ์ธ์ด ๋ฉ๋๋ค.
2) ์์ ๊ฐ์ ๊ณผ์ ์ด ์ ์์ ์ด์ง๋ง, ์ด์ SQL ์ธ์ ์ ๊ณต๊ฒฉ ๋ฐฉ๋ฒ์ผ๋ก ๋ก๊ทธ์ธ์ ์๋ํด ๋ณด๊ฒ ์ต๋๋ค. ์์ด๋์ ์๋์ ๊ฐ์ด ์ ๋ ฅํ๊ณ , ํจ์ค์๋๋ ๋์ถฉ ์๋ฌด๊ฑฐ๋ ์ ๋ ฅํด ์ค๋๋ค.
1' or 1 = 1 #
์์ฒ๋ผ SQL ์ธ์ ์ ๊ณต๊ฒฉ์ ํ๋ฌดํ๊ฒ ๋ซ๋ฆฌ๊ฒ ๋ฉ๋๋ค.
2) ์ฃผ์์ฐฝ์ ์๋์ ๊ฐ์ด ์ ๋ ฅํด ๋ด ๋๋ค. get๋ฐฉ์์ผ๋ก value ๊ฐ 1234๋ฅผ ์ ๋ฌํ๋ฉด, ํ๋ฉด ์ค๊ฐ์ ์ถ๋ ฅ๋๋๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
http://localhost/index.php?value=1234
์ด์ value ๊ฐ์ผ๋ก ์๋์ ๊ฐ์ด ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ ๋ ฅํด ๋ด ๋๋ค. ๊ทธ๋ผ alert์ฐฝ์ด ๋จ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. (Reflexed XSS ๊ณต๊ฒฉ)
http://localhost/index.php?value=<script>alert("ํดํน์ค");</script>
์ด์ ๋ค์ ์๋์ ๊ฐ์ด ์ ๋ ฅํด ๋ด ๋๋ค. ๊ทธ๋ผ ํ์ฌ ๋ก๊ทธ์ธ ๋์ด ์๋ ์ฌ๋์ ์ธ์ ์ฟ ํค ๊ฐ์ด ๊ทธ๋๋ก ๋ ธ์ถ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ์ด๋ฐ ํํ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ด์ฉํ์ฌ ๊ด๋ฆฌ์์ ์ธ์ ์ฟ ํค ๊ฐ์ ์กฐ์ฉํ ํด์ปค ์๋ฒ๋ก ์ ์กํ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ์ด์ฉํด์ ๊ด๋ฆฌ์๋ก ๋ก๊ทธ์ธ๊น์ง ํ ์ ์๊ฒ ๋ฉ๋๋ค.
http://localhost/index.php?value=<script>alert(document.cookie);</script>
์ด์ฒ๋ผ ํ์ฌ์ ์น์ฌ์ดํธ๋ ์ฌ๋ฌ ํดํน ๊ณต๊ฒฉ์ ๋ซ๋ฆด ์ ์๋ ์ทจ์ฝ์ ๋ค์ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.