๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

SSL๊ณผ OAuth๋ฅผ ๊ฒฐํ•ฉํ•œ ์•ˆ์ „ํ•œ API ์„ค๊ณ„: ๋ณด์•ˆ์„ฑ๊ณผ ํšจ์œจ์„ฑ์„ ๋ชจ๋‘ ์žก๋Š” ๋ฐฉ๋ฒ•

mrmount 2024. 10. 20.

 

 

 

1. ์•ˆ์ „ํ•œ API ์„ค๊ณ„์—์„œ SSL๊ณผ OAuth์˜ ์—ญํ• 

API ํ†ต์‹  ์—์„œ๋Š” ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๊ณ  ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. SSL/TLS ๋Š” ํ†ต์‹  ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๊ณ , OAuth ๋Š” ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ๋‹ด๋‹นํ•˜์—ฌ API ์ ‘๊ทผ์„ ์ œ์–ด ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ธฐ์ˆ ์„ ๊ฒฐํ•ฉํ•˜๋ฉด ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์ธ API ์„ค๊ณ„ ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 


 

2. SSL/TLS๋ฅผ ์‚ฌ์šฉํ•œ ์•ˆ์ „ํ•œ API ํ†ต์‹ 

 

SSL/TLS๋ž€?

SSL/TLS(Transport Layer Security) ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™” ํ•˜์—ฌ ๋„คํŠธ์›Œํฌ์—์„œ์˜ ๋„์ฒญ ๋ฐ ์œ„๋ณ€์กฐ๋ฅผ ๋ฐฉ์ง€ ํ•˜๋Š” ๋ณด์•ˆ ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค. API์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ๋ชจ๋“  ํ†ต์‹ ์— HTTPS๋ฅผ ์‚ฌ์šฉ ํ•ด ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค.

SSL์„ ์ ์šฉํ•œ API ์˜ˆ์ œ

์•„๋ž˜๋Š” Flask ๋กœ ๋งŒ๋“  ๊ฐ„๋‹จํ•œ HTTPS API์ž…๋‹ˆ๋‹ค.

 

์˜ˆ์‹œ ์ฝ”๋“œ: SSL์„ ์‚ฌ์šฉํ•œ API ์„œ๋ฒ„ ๊ตฌ์„ฑ

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/secure-data')
def secure_data():
    return jsonify({"message": "์ด ๋ฐ์ดํ„ฐ๋Š” ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธ๋ฉ๋‹ˆ๋‹ค."})

if __name__ == '__main__':
    # SSL ์ธ์ฆ์„œ ๋ฐ ํ‚ค๋ฅผ ์ง€์ •ํ•ด HTTPS ์„œ๋ฒ„ ์‹คํ–‰
    app.run(ssl_context=('cert.pem', 'key.pem'), port=5000)

 

 

1. ์•ˆ์ „ํ•œ API ์„ค๊ณ„์—์„œ SSL๊ณผ OAuth์˜ ์—ญํ• 

API ํ†ต์‹  ์—์„œ๋Š” ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์˜ค๊ณ  ๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. SSL/TLS ๋Š” ํ†ต์‹  ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๊ณ , OAuth ๋Š” ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ๋ฅผ ๋‹ด๋‹นํ•˜์—ฌ API ์ ‘๊ทผ์„ ์ œ์–ด ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ธฐ์ˆ ์„ ๊ฒฐํ•ฉํ•˜๋ฉด ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์ธ API ์„ค๊ณ„ ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 


 

2. SSL/TLS๋ฅผ ์‚ฌ์šฉํ•œ ์•ˆ์ „ํ•œ API ํ†ต์‹ 

 

SSL/TLS๋ž€?

SSL/TLS(Transport Layer Security) ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™” ํ•˜์—ฌ ๋„คํŠธ์›Œํฌ์—์„œ์˜ ๋„์ฒญ ๋ฐ ์œ„๋ณ€์กฐ๋ฅผ ๋ฐฉ์ง€ ํ•˜๋Š” ๋ณด์•ˆ ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค. API์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ๋ชจ๋“  ํ†ต์‹ ์— HTTPS๋ฅผ ์‚ฌ์šฉ ํ•ด ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•ฉ๋‹ˆ๋‹ค.

SSL์„ ์ ์šฉํ•œ API ์˜ˆ์ œ

์•„๋ž˜๋Š” Flask ๋กœ ๋งŒ๋“  ๊ฐ„๋‹จํ•œ HTTPS API์ž…๋‹ˆ๋‹ค.

 

์˜ˆ์‹œ ์ฝ”๋“œ: SSL์„ ์‚ฌ์šฉํ•œ API ์„œ๋ฒ„ ๊ตฌ์„ฑ

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/secure-data')
def secure_data():
    return jsonify({"message": "์ด ๋ฐ์ดํ„ฐ๋Š” ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธ๋ฉ๋‹ˆ๋‹ค."})

if __name__ == '__main__':
    # SSL ์ธ์ฆ์„œ ๋ฐ ํ‚ค๋ฅผ ์ง€์ •ํ•ด HTTPS ์„œ๋ฒ„ ์‹คํ–‰
    app.run(ssl_context=('cert.pem', 'key.pem'), port=5000)

์„ค๋ช…:
- ์ด ์˜ˆ์ œ์—์„œ๋Š” cert.pem ๊ณผ key.pem ์„ ์‚ฌ์šฉํ•ด HTTPS ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
- HTTPS ํ†ต์‹ ์„ ํ†ตํ•ด API ๋ฐ์ดํ„ฐ๊ฐ€ ์•”ํ˜ธํ™” ๋ฉ๋‹ˆ๋‹ค.

 


 

3. OAuth๋ฅผ ํ†ตํ•œ API ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ

 

OAuth์˜ ์—ญํ• 

OAuth 2.0 ์€ API ํด๋ผ์ด์–ธํŠธ๊ฐ€ Access Token ์„ ํ†ตํ•ด ์ธ์ฆ๊ณผ ๊ถŒํ•œ์„ ๋ถ€์—ฌ ๋ฐ›๋„๋ก ํ•˜๋Š” ํ‘œ์ค€์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ์ž์‹ ์˜ ์ž๊ฒฉ ์ฆ๋ช…์„ ์ง์ ‘ ๋…ธ์ถœํ•˜์ง€ ์•Š๊ณ , ํ† ํฐ ๊ธฐ๋ฐ˜ ์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ API์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ์‹œ ์ฝ”๋“œ: OAuth๋กœ ๋ณดํ˜ธ๋œ API ํ˜ธ์ถœ

import requests

access_token = "your_access_token"

headers = {
    "Authorization": f"Bearer {access_token}"
}

response = requests.get("https://api.example.com/protected-resource", headers=headers)

if response.status_code == 200:
    print("API ํ˜ธ์ถœ ์„ฑ๊ณต:", response.json())
else:
    print("API ํ˜ธ์ถœ ์‹คํŒจ:", response.status_code)

์„ค๋ช…:
- Authorization ํ—ค๋”์— Access Token ์„ ํฌํ•จํ•˜์—ฌ ์ธ์ฆ๋œ API ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
- ๋งŒ๋ฃŒ๋œ ํ† ํฐ์€ 401 Unauthorized ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 


 

4. API Rate Limiting๊ณผ ๋ชจ๋‹ˆํ„ฐ๋ง

 

API Rate Limiting์˜ ํ•„์š”์„ฑ

Rate Limiting(์†๋„ ์ œํ•œ) ์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง€์ •๋œ ์‹œ๊ฐ„ ๋™์•ˆ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋Š” API ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ์ œํ•œ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด API ๋‚จ์šฉ๊ณผ DDoS ๊ณต๊ฒฉ ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์˜ˆ์‹œ ์ฝ”๋“œ: Flask์™€ Redis๋ฅผ ์‚ฌ์šฉํ•œ Rate Limiting ๊ตฌํ˜„

import time
import redis
from flask import Flask, jsonify, request

app = Flask(__name__)
r = redis.Redis()

RATE_LIMIT = 5  # 5ํšŒ ์š”์ฒญ ์ œํ•œ
WINDOW = 60  # 1๋ถ„ ์‹œ๊ฐ„ ์ฐฝ

@app.route('/api')
def api():
    client_ip = request.remote_addr
    key = f"rate_limit:{client_ip}"
    request_count = r.get(key)

    if request_count and int(request_count) >= RATE_LIMIT:
        return jsonify({"error": "Rate limit exceeded"}), 429

    r.incr(key)
    r.expire(key, WINDOW)
    return jsonify({"message": "API ํ˜ธ์ถœ ์„ฑ๊ณต"})

if __name__ == '__main__':
    app.run()

์„ค๋ช…:
- ์‚ฌ์šฉ์ž๋Š” 1๋ถ„ ๋™์•ˆ 5ํšŒ ์š”์ฒญ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ดˆ๊ณผ ์‹œ 429 Too Many Requests ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
- Redis๋ฅผ ์‚ฌ์šฉํ•ด ์š”์ฒญ ์ˆ˜๋ฅผ ์ถ”์ ํ•˜๊ณ  ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

API ๋ชจ๋‹ˆํ„ฐ๋ง

API ์„œ๋ฒ„์˜ ์„ฑ๋Šฅ๊ณผ ๋ณด์•ˆ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด API ํ˜ธ์ถœ ๋กœ๊ทธ์™€ ๋ชจ๋‹ˆํ„ฐ๋ง ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
- Prometheus์™€ Grafana ๊ฐ™์€ ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•ด API ์ƒํƒœ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.
- ๊ฒฝ๊ณ  ์‹œ์Šคํ…œ ์„ ํ†ตํ•ด ๋น„์ •์ƒ์ ์ธ API ์‚ฌ์šฉ์„ ์ฆ‰์‹œ ํƒ์ง€ํ•ฉ๋‹ˆ๋‹ค.

 


 

5. SSL๊ณผ OAuth๋ฅผ ๊ฒฐํ•ฉํ•œ ์•ˆ์ „ํ•œ API ์„ค๊ณ„

 

์„ค๊ณ„ ์‹œ ๊ณ ๋ คํ•  ์‚ฌํ•ญ

  1. HTTPS๋ฅผ ์‚ฌ์šฉํ•ด ๋ชจ๋“  API ํ†ต์‹  ์•”ํ˜ธํ™”
  2. OAuth 2.0 ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ธ์ฆ ๊ฐ•ํ™”
  3. Rate Limiting ์„ ํ†ตํ•ด API ๋‚จ์šฉ ๋ฐฉ์ง€
  4. ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ ๋กœ API ์‚ฌ์šฉ ์ƒํƒœ ์‹ค์‹œ๊ฐ„ ์ถ”์ 

์˜ˆ์‹œ: SSL๊ณผ OAuth๋ฅผ ๊ฒฐํ•ฉํ•œ API ํ˜ธ์ถœ ํ๋ฆ„

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ HTTPS ๋ฅผ ํ†ตํ•ด API์— ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.
  2. Access Token ์„ ์‚ฌ์šฉํ•ด OAuth ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  3. Rate Limiting ์œผ๋กœ ์š”์ฒญ ์†๋„๋ฅผ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.
  4. ๋ชจ๋“  API ํ˜ธ์ถœ ๋กœ๊ทธ๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ ๋กœ ์ˆ˜์ง‘๋ฉ๋‹ˆ๋‹ค.

 


 

FAQ

Q1. SSL ์—†์ด OAuth๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ์ „ํ•œ๊ฐ€์š”?
A1. ์•„๋‹™๋‹ˆ๋‹ค. SSL์€ ๋ชจ๋“  ํ†ต์‹ ์„ ์•”ํ˜ธํ™” ํ•ด ์ค‘๊ฐ„์ž ๊ณต๊ฒฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.

Q2. Access Token์ด ๋งŒ๋ฃŒ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•˜๋‚˜์š”?
A2. Refresh Token ์„ ์‚ฌ์šฉํ•ด ์ƒˆ๋กœ์šด Access Token์„ ๋ฐœ๊ธ‰๋ฐ›์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Q3. Rate Limiting์€ ์™œ ํ•„์š”ํ•œ๊ฐ€์š”?
A3. DDoS ๊ณต๊ฒฉ๊ณผ API ๋‚จ์šฉ ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

Q4. PKCE๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?
A4. ๋ชจ๋ฐ”์ผ ์•ฑ ๊ณผ ๊ฐ™์€ ๊ณต๊ฐœ ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” PKCE ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Q5. API ํ˜ธ์ถœ ๋กœ๊ทธ๋Š” ์–ด๋–ป๊ฒŒ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋‚˜์š”?
A5. Prometheus์™€ Grafana ๋ฅผ ์‚ฌ์šฉํ•ด API ํ˜ธ์ถœ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 


๋Œ“๊ธ€