Search

๋ณด์•ˆ ์„ค์ •

Nginx ๋ณด์•ˆ ์„ค์ •

๊ฐœ์š”

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

Nginx ๋ณด์•ˆ ๊ณ„์ธต

graph TD
    A["๐ŸŒ ์ธํ„ฐ๋„ท<br/>(๊ณต๊ฒฉ์ž ํฌํ•จ)"] --> B["๐Ÿ”ฅ ๋ฐฉํ™”๋ฒฝ<br/>UFW/iptables"]
    B --> C["๐Ÿ›ก๏ธ Nginx ๋ณด์•ˆ ๊ณ„์ธต"]
    C --> D["๐Ÿ–ฅ๏ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜<br/>Spring Boot ๋“ฑ"]

    C --> C1["์„œ๋ฒ„ ์ •๋ณด ์ˆจ๊ธฐ๊ธฐ"]
    C --> C2["์š”์ฒญ ์ œํ•œ (Rate Limit)"]
    C --> C3["๋ณด์•ˆ ํ—ค๋”"]
    C --> C4["์ ‘๊ทผ ์ œ์–ด (IP/Auth)"]
    C --> C5["SSL/TLS ๊ฐ•ํ™”"]
    C --> C6["์š”์ฒญ ํฌ๊ธฐ ์ œํ•œ"]

    style C fill:#FFD700
Mermaid
๋ณต์‚ฌ

1. ์„œ๋ฒ„ ์ •๋ณด ์ˆจ๊ธฐ๊ธฐ

ํ•ด์ปค๊ฐ€ ๊ฐ€์žฅ ๋จผ์ € ํ•˜๋Š” ๊ฑด ์„œ๋ฒ„ ์ •๋ณด๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๊ฑฐ์˜ˆ์š”. Nginx ๋ฒ„์ „์ด ์•Œ๋ ค์ง€๋ฉด ํ•ด๋‹น ๋ฒ„์ „์˜ ์•Œ๋ ค์ง„ ์ทจ์•ฝ์ ์„ ๊ณต๊ฒฉํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”!
http { # Nginx ๋ฒ„์ „ ์ •๋ณด ์ˆจ๊ธฐ๊ธฐ (์‘๋‹ต ํ—ค๋”์—์„œ ์ œ๊ฑฐ) server_tokens off; }
Plain Text
๋ณต์‚ฌ
์„ค์ •
์ ์šฉ ์ „
์ ์šฉ ํ›„
์‘๋‹ต ํ—ค๋”
Server: nginx/1.24.0
Server: nginx
์—๋Ÿฌ ํŽ˜์ด์ง€
nginx/1.24.0 ํ‘œ์‹œ
nginx ๋งŒ ํ‘œ์‹œ

2. Rate Limiting (์š”์ฒญ ์ œํ•œ)

DDoS ๊ณต๊ฒฉ์ด๋‚˜ ๋ธŒ๋ฃจํŠธํฌ์Šค ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋Š” ๊ฐ€์žฅ ํšจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ•์ด์—์š”!
graph LR
    A["๐Ÿ‘ค ์ •์ƒ ์‚ฌ์šฉ์ž<br/>์ดˆ๋‹น 5ํšŒ ์š”์ฒญ"] -->|โœ… ํ—ˆ์šฉ| C["๐Ÿ–ฅ๏ธ Nginx"]
    B["๐Ÿค– ๊ณต๊ฒฉ์ž<br/>์ดˆ๋‹น 100ํšŒ ์š”์ฒญ"] -->|โŒ 429 ์ฐจ๋‹จ| C

    style A fill:#90EE90
    style B fill:#FFB3B3
Mermaid
๋ณต์‚ฌ
http { # Rate Limit ์˜์—ญ ์ •์˜ # $binary_remote_addr = ํด๋ผ์ด์–ธํŠธ IP ๊ธฐ์ค€ # zone=limit_req:10m = 10MB ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ # rate=10r/s = ์ดˆ๋‹น 10๊ฐœ ์š”์ฒญ ํ—ˆ์šฉ limit_req_zone $binary_remote_addr zone=limit_req:10m rate=10r/s; # ๋กœ๊ทธ์ธ ์‹œ๋„ ์ œํ•œ (๋” ์—„๊ฒฉ) limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s; server { # ์ผ๋ฐ˜ ์š”์ฒญ์— Rate Limit ์ ์šฉ location / { limit_req zone=limit_req burst=20 nodelay; } # ๋กœ๊ทธ์ธ ๊ฒฝ๋กœ๋Š” ๋” ์—„๊ฒฉํ•˜๊ฒŒ location /api/auth/login { limit_req zone=login_limit burst=5 nodelay; proxy_pass <http://localhost:8080>; } } }
Plain Text
๋ณต์‚ฌ
์„ค์ •
์˜๋ฏธ
rate=10r/s
์ดˆ๋‹น 10๊ฐœ ์š”์ฒญ ํ—ˆ์šฉ
burst=20
์ˆœ๊ฐ„์ ์œผ๋กœ 20๊ฐœ๊นŒ์ง€ ์ดˆ๊ณผ ํ—ˆ์šฉ (ํ์— ๋Œ€๊ธฐ)
nodelay
ํ ๋Œ€๊ธฐ ์—†์ด ์ฆ‰์‹œ ์ฒ˜๋ฆฌํ•˜๊ณ , ์ดˆ๊ณผ ์‹œ ์ฆ‰์‹œ ๊ฑฐ๋ถ€
์ƒํ™ฉ
๊ฒฐ๊ณผ
์ดˆ๋‹น 10๊ฐœ ์ดํ•˜
์ •์ƒ ์ฒ˜๋ฆฌ
์ดˆ๋‹น 11~30๊ฐœ
burst ๋ฒ”์œ„ ๋‚ด ํ—ˆ์šฉ
์ดˆ๋‹น 31๊ฐœ ์ด์ƒ
429 Too Many Requests

3. ๋ณด์•ˆ ํ—ค๋” (Security Headers)

server { # XSS ๊ณต๊ฒฉ ๋ฐฉ์ง€ add_header X-Content-Type-Options "nosniff" always; # ํด๋ฆญ์žฌํ‚น ๋ฐฉ์ง€ (iframe ์‚ฝ์ž… ์ฐจ๋‹จ) add_header X-Frame-Options "SAMEORIGIN" always; # XSS ํ•„ํ„ฐ ํ™œ์„ฑํ™” add_header X-XSS-Protection "1; mode=block" always; # HTTPS ๊ฐ•์ œ (HSTS) add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # Referrer ์ •๋ณด ์ œํ•œ add_header Referrer-Policy "strict-origin-when-cross-origin" always; # Content Security Policy (๊ณ ๊ธ‰) add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always; }
Plain Text
๋ณต์‚ฌ
ํ—ค๋”
๋ฐฉ์–ด ๋Œ€์ƒ
์„ค๋ช…
X-Content-Type-Options
MIME ์Šค๋‹ˆํ•‘
๋ธŒ๋ผ์šฐ์ €๊ฐ€ Content-Type์„ ์ž„์˜๋กœ ๋ฐ”๊พธ์ง€ ๋ชปํ•˜๊ฒŒ
X-Frame-Options
ํด๋ฆญ์žฌํ‚น
๋‹ค๋ฅธ ์‚ฌ์ดํŠธ๊ฐ€ iframe์œผ๋กœ ๋‚ด ์‚ฌ์ดํŠธ๋ฅผ ์‚ฝ์ž… ๋ชปํ•˜๊ฒŒ
X-XSS-Protection
XSS ๊ณต๊ฒฉ
๋ธŒ๋ผ์šฐ์ €์˜ XSS ํ•„ํ„ฐ ํ™œ์„ฑํ™”
Strict-Transport-Security
๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ ๊ณต๊ฒฉ
HTTPS ์ ‘์† ๊ฐ•์ œ (1๋…„๊ฐ„ ๊ธฐ์–ต)
Referrer-Policy
์ •๋ณด ์œ ์ถœ
์™ธ๋ถ€ ์ด๋™ ์‹œ Referer ์ •๋ณด ์ œํ•œ
Content-Security-Policy
XSS, ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
ํ—ˆ์šฉ๋œ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋งŒ ๋กœ๋“œ

4. ์ ‘๊ทผ ์ œ์–ด

IP ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด

# ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ โ€” ํŠน์ • IP๋งŒ ํ—ˆ์šฉ location /admin/ { allow 203.0.113.0/24; # ํšŒ์‚ฌ IP ๋Œ€์—ญ allow 10.0.0.0/8; # ๋‚ด๋ถ€ ๋„คํŠธ์›Œํฌ deny all; # ๋‚˜๋จธ์ง€ ์ „๋ถ€ ์ฐจ๋‹จ proxy_pass <http://localhost:8080>; } # ํŠน์ • IP ์ฐจ๋‹จ location / { deny 192.168.1.100; # ํŠน์ • IP ์ฐจ๋‹จ deny 10.0.0.0/8; # IP ๋Œ€์—ญ ์ฐจ๋‹จ allow all; # ๋‚˜๋จธ์ง€ ํ—ˆ์šฉ }
Plain Text
๋ณต์‚ฌ

Basic ์ธ์ฆ (ID/๋น„๋ฐ€๋ฒˆํ˜ธ)

# htpasswd ์„ค์น˜ sudo apt install apache2-utils # ๋น„๋ฐ€๋ฒˆํ˜ธ ํŒŒ์ผ ์ƒ์„ฑ sudo htpasswd -c /etc/nginx/.htpasswd admin # ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ ํ”„๋กฌํ”„ํŠธ
Bash
๋ณต์‚ฌ
# ์Šคํ…Œ์ด์ง• ์„œ๋ฒ„ ๋ณดํ˜ธ location / { auth_basic "Restricted Access"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass <http://localhost:8080>; }
Plain Text
๋ณต์‚ฌ

5. SSL/TLS ๊ฐ•ํ™”

server { listen 443 ssl http2; # ์ตœ์‹  TLS๋งŒ ํ—ˆ์šฉ (1.2, 1.3) ssl_protocols TLSv1.2 TLSv1.3; # ๊ฐ•๋ ฅํ•œ ์•”ํ˜ธํ™” ์Šค์œ„ํŠธ ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; # SSL ์„ธ์…˜ ์บ์‹œ ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # DH ํŒŒ๋ผ๋ฏธํ„ฐ (์ถ”๊ฐ€ ๋ณด์•ˆ) ssl_dhparam /etc/nginx/dhparam.pem; }
Plain Text
๋ณต์‚ฌ
# DH ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ฑ (์‹œ๊ฐ„์ด ์ข€ ๊ฑธ๋ฆผ) sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
Bash
๋ณต์‚ฌ

6. ์š”์ฒญ ํฌ๊ธฐ ๋ฐ ๋ฒ„ํผ ์ œํ•œ

http { # ์š”์ฒญ ๋ฐ”๋”” ํฌ๊ธฐ ์ œํ•œ (ํŒŒ์ผ ์—…๋กœ๋“œ ๋“ฑ) client_max_body_size 10M; # ๋ฒ„ํผ ํฌ๊ธฐ ์ œํ•œ (๋ฒ„ํผ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๋ฐฉ์ง€) client_body_buffer_size 1K; client_header_buffer_size 1K; large_client_header_buffers 2 1K; }
Plain Text
๋ณต์‚ฌ

7. ๋ด‡ ๋ฐ ์Šค์บ๋„ˆ ์ฐจ๋‹จ

# ์•…์„ฑ ๋ด‡ User-Agent ์ฐจ๋‹จ if ($http_user_agent ~* (SemrushBot|AhrefsBot|MJ12bot|DotBot|BLEXBot)) { return 403; } # ๋น„์–ด์žˆ๋Š” User-Agent ์ฐจ๋‹จ if ($http_user_agent = "") { return 403; } # ํŠน์ • HTTP ๋ฉ”์„œ๋“œ๋งŒ ํ—ˆ์šฉ if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE|PATCH)$) { return 405; } # ์ˆจ๊ฒจ์ง„ ํŒŒ์ผ ์ ‘๊ทผ ์ฐจ๋‹จ (.env, .git ๋“ฑ) location ~ /\\. { deny all; access_log off; log_not_found off; }
Plain Text
๋ณต์‚ฌ

๋ณด์•ˆ ์„ค์ • ์ข…ํ•ฉ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

์ˆœ์„œ
์„ค์ •
์ค‘์š”๋„
๋ช…๋ น์–ด/์„ค์ •
1
์„œ๋ฒ„ ๋ฒ„์ „ ์ˆจ๊ธฐ๊ธฐ
server_tokens off
2
HTTPS ์ ์šฉ
Let's Encrypt + HTTPโ†’HTTPS ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
3
๋ณด์•ˆ ํ—ค๋” ์ถ”๊ฐ€
X-Frame-Options, HSTS ๋“ฑ
4
Rate Limiting
limit_req_zone
5
๋ฐฉํ™”๋ฒฝ ์„ค์ •
ufw allow 'Nginx Full'
6
SSL/TLS ๊ฐ•ํ™”
TLSv1.2/1.3๋งŒ, ๊ฐ•๋ ฅํ•œ cipher
7
์ˆจ๊น€ ํŒŒ์ผ ์ฐจ๋‹จ
location ~ /\\.
8
๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ IP ์ œํ•œ
allow/deny
9
ํŒŒ์ผ ์—…๋กœ๋“œ ํฌ๊ธฐ ์ œํ•œ
client_max_body_size
10
์•…์„ฑ ๋ด‡ ์ฐจ๋‹จ
User-Agent ํ•„ํ„ฐ๋ง

๋ณด์•ˆ ์ ๊ฒ€ ๋„๊ตฌ

๋„๊ตฌ
์šฉ๋„
URL/๋ช…๋ น์–ด
SSL Labs
SSL/TLS ์„ค์ • ์ ๊ฒ€
ssllabs.com/ssltest/
Security Headers
๋ณด์•ˆ ํ—ค๋” ์ ๊ฒ€
securityheaders.com
Nmap
ํฌํŠธ ์Šค์บ”
nmap -sV ์„œ๋ฒ„IP
curl
ํ—ค๋” ํ™•์ธ
curl -I <https://example.com>
# ๋ณด์•ˆ ํ—ค๋” ํ™•์ธ curl -I <https://example.com> # ์—ด๋ฆฐ ํฌํŠธ ํ™•์ธ sudo ss -tlnp # ์ ‘์† ์‹œ๋„ ๋กœ๊ทธ ํ™•์ธ (๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ๊ณต๊ฒฉ ๊ฐ์ง€) grep "error" /var/log/nginx/error.log | tail -20
Bash
๋ณต์‚ฌ

ํ•ต์‹ฌ ์ •๋ฆฌ

server_tokens off: Nginx ๋ฒ„์ „ ์ •๋ณด ์ˆจ๊ธฐ๊ธฐ (๊ธฐ๋ณธ ์ค‘์˜ ๊ธฐ๋ณธ!)
Rate Limiting: limit_req_zone์œผ๋กœ DDoS/๋ธŒ๋ฃจํŠธํฌ์Šค ๋ฐฉ์–ด
๋ณด์•ˆ ํ—ค๋”: X-Frame-Options, HSTS, CSP ๋“ฑ์œผ๋กœ ์›น ๊ณต๊ฒฉ ๋ฐฉ์–ด
์ ‘๊ทผ ์ œ์–ด: IP ์ œํ•œ(allow/deny), Basic ์ธ์ฆ์œผ๋กœ ๊ด€๋ฆฌ์ž ๋ณดํ˜ธ
SSL ๊ฐ•ํ™”: TLS 1.2/1.3๋งŒ ํ—ˆ์šฉ, ๊ฐ•๋ ฅํ•œ ์•”ํ˜ธํ™” ์Šค์œ„ํŠธ ์‚ฌ์šฉ
์ˆจ๊น€ ํŒŒ์ผ(.env, .git) ์ ‘๊ทผ ์ฐจ๋‹จ ํ•„์ˆ˜!