\n\n

การสร้าง AI API ที่ปลอดภัยเป็นสิ่งสำคัญมากในยุคปัจจุบัน ในบทความนี้เราจะมาดูวิธีการใช้ OAuth2 และ JWT (JSON Web Token) เพื่อปกป้อง AI API endpoints ของคุณอย่างมีประสิทธิภาพ

\n\n

JWT คืออะไร?

\n\n

JWT หรือ JSON Web Token เป็นมาตรฐานเปิด (RFC 7519) ที่ใช้ในการส่งข้อมูลระหว่าง parties อย่างปลอดภัยในรูปแบบ JSON ซึ่งสามารถตรวจสอบความถูกต้องและเชื่อถือได้

\n\n

โครงสร้างของ JWT

\n\n

JWT ประกอบด้วย 3 ส่วนหลักที่คั่นด้วยจุด (.):

\n\n
xxxxx.yyyyy.zzzzz
\n\n\n\n

OAuth2 คืออะไร?

\n\n

OAuth2 เป็น authorization framework ที่ช่วยให้แอปพลิเคชันสามารถขอเข้าถึงทรัพยากรในนามของผู้ใช้ได้อย่างปลอดภัย โดยไม่ต้องแชร์ password

\n\n

การผสาน OAuth2 กับ JWT

\n\n

ในการใช้งานจริง เราจะใช้ OAuth2 ในการขอ authorization และ JWT เป็น token ที่ใช้ในการยืนยันตัวตน

\n\n

ตัวอย่างการสร้าง JWT Middleware

\n\n

นี่คือตัวอย่างการสร้าง JWT middleware สำหรับ Express.js:

\n\n
const jwt = require('jsonwebtoken');\nconst secretKey = process.env.JWT_SECRET;\n\n// Middleware สำหรับตรวจสอบ JWT\nfunction authMiddleware(req, res, next) {\n    const authHeader = req.headers.authorization;\n    \n    if (!authHeader || !authHeader.startsWith('Bearer ')) {\n        return res.status(401).json({ \n            error: 'Authorization header missing or invalid' \n        });\n    }\n    \n    const token = authHeader.substring(7);\n    \n    try {\n        const decoded = jwt.verify(token, secretKey, {\n            algorithms: ['HS256'],\n            issuer: 'your-api-name'\n        });\n        \n        req.user = decoded;\n        next();\n    } catch (error) {\n        if (error.name === 'TokenExpiredError') {\n            return res.status(401).json({ \n                error: 'Token has expired' \n            });\n        }\n        return res.status(401).json({ \n            error: 'Invalid token' \n        });\n    }\n}\n\nmodule.exports = authMiddleware;
\n\n

การสร้าง Token และ Protected Endpoint

\n\n
const express = require('express');\nconst jwt = require('jsonwebtoken');\nconst authMiddleware = require('./authMiddleware');\n\nconst app = express();\napp.use(express.json());\n\nconst JWT_SECRET = process.env.JWT_SECRET;\nconst TOKEN_EXPIRY = '1h';\n\n// Endpoint สำหรับ login และสร้าง token\napp.post('/api/auth/login', async (req, res) => {\n    const { username, password } = req.body;\n    \n    // ตรวจสอบ credentials (ควรใช้ database จริง)\n    const user = await validateCredentials(username, password);\n    \n    if (!user) {\n        return res.status(401).json({ \n            error: 'Invalid credentials' \n        });\n    }\n    \n    // สร้าง JWT token\n    const token = jwt.sign(\n        {\n            userId: user.id,\n            username: user.username,\n            role: user.role\n        },\n        JWT_SECRET,\n        {\n            expiresIn: TOKEN_EXPIRY,\n            issuer: 'ai-api-service',\n            subject: String(user.id)\n        }\n    );\n    \n    res.json({\n        access_token: token,\n        token_type: 'Bearer',\n        expires_in: 3600\n    });\n});\n\n// Protected AI API endpoint\napp.post('/api/ai/completions', authMiddleware, async (req, res) => {\n    const { prompt, model } = req.body;\n    \n    // ตรวจสอบ rate limit ต่อ user\n    const rateLimit = await checkRateLimit(req.user.userId);\n    if (!rateLimit.allowed) {\n        return res.status(429).json({\n            error: 'Rate limit exceeded',\n            retry_after: rateLimit.retryAfter\n        });\n    }\n    \n    // เรียกใช้ AI model\n    const response = await callAIModel(prompt, model, req.user);\n    \n    res.json(response);\n});\n\napp.listen(3000, () => {\n    console.log('AI API Server running on port 3000');\n});
\n\n

การใช้งานกับ AI API

\n\n

นี่คือตัวอย่างการเรียกใช้ AI API อย่างปลอดภัย:

\n\n
const axios = require('axios');\n\nclass AIServiceClient {\n    constructor(apiUrl, apiKey) {\n        this.apiUrl = apiUrl;\n        this.apiKey = apiKey;\n    }\n    \n    async generateWithAuth(prompt, model, userToken) {\n        try {\n            const response = await axios.post(\n                ${this.apiUrl}/ai/completions,\n                {\n                    prompt: prompt,\n                    model: model,\n                    max_tokens: 1000,\n                    temperature: 0.7\n                },\n                {\n                    headers: {\n                        'Authorization': Bearer ${userToken},\n                        'Content-Type': 'application/json'\n                    },\n                    timeout: 30000 // 30 วินาที timeout\n                }\n            );\n            \n            return response.data;\n        } catch (error) {\n            if (error.response) {\n                console.error('API Error:', error.response.status);\n                console.error('Details:', error.response.data);\n            }\n            throw error;\n        }\n    }\n}\n\n// การใช้งาน\nconst client = new AIServiceClient(\n    'https://api.example.com',\n    process.env.API_KEY\n);\n\nasync function main() {\n    const result = await client.generateWithAuth(\n        'อธิบายเกี่ยวกับ JWT',\n        'gpt-4',\n        'user-jwt-token-here'\n    );\n    console.log('Result:', result);\n}\n\nmain();
\n\n

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

\n\n

1. Token หมดอายุเร็วเกินไป

\n\n

ปัญหา: Token หมดอายุทันทีหลังจากสร้าง ทำให้ผู้ใช้ต้อง login ใหม่บ่อย

\n\n
// ผิดพลาด - ใช้เวลาผิด format\nconst token = jwt.sign(payload, secret, {\n    expiresIn: '60' // อาจถูกตีความเป็น milliseconds\n});\n\n// ถูกต้อง - ใช้ string format ที่ชัดเจน\nconst token = jwt.sign(payload, secret, {\n    expiresIn: '1h', // หรือ '2h', '30m', '7d'\n    algorithm: 'HS256'\n});
\n\n

2. ไม่ตรวจสอบ Algorithm ใน Token

\n\n

ปัญหา: เปิดช่องโหว่ให้ผู้โจมตีสามารถเปลี่ยน algorithm เป็น 'none' ได้

\n\n
// ผิดพลาด - ไม่ระบุ algorithm\nconst decoded = jwt.verify(token, secret);\n\n// ถูกต้อง - ระบุ algorithm ที่อนุญาตเท่านั้น\nconst decoded = jwt.verify(token, secret, {\n    algorithms: ['HS256'],\n    issuer: 'your-app-name',\n    audience: 'api-users'\n});\n\n// หรือใช้ jose library สำหรับความปลอดภัยสูงสุด\nconst { jwtVerify } = require('jose');\nconst secret = new TextEncoder().encode(process.env.JWT_SECRET);\nconst { payload } = await jwtVerify(token, secret, {\n    algorithms: ['HS256']\n});
\n\n

3. ใช้ Secret Key ที่อ่อนแอ

\n\n

ปัญหา: Secret key ที่เดาได้ง่ายทำให้ถูก brute force attack

\n\n
// ผิดพลาด - Secret สั้นและเดาได้ง่าย\nconst secret = '123456';\n\n// ผิดพลาด - Secret ตายตัวในโค้ด\nconst secret = 'my-secret-key';\n\n// ถูกต้อง - ใช้ Environment variable และสร้าง key ที่แข็งแกร่ง\nconst secret = crypto.createHash('sha256')\n    .update(process.env.JWT_SECRET || require('crypto').randomBytes(64).toString('hex'))\n    .digest();\n\n// หรือใช้ RSA/ECDA สำหรับความปลอดภัยที่ดีกว่า\nconst { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {\n    modulusLength: 2048,\n    publicKeyEncoding: { type: 'spki', format: 'pem' },\n    privateKeyEncoding: { type: 'pkcs8', format: 'pem' }\n});\n\n// สร้าง token ด้วย private key\nconst token = jwt.sign(payload, privateKey, { algorithm: 'RS256' });\n\n// ตรวจสอบ token ด้วย public key\nconst decoded = jwt.verify(token, publicKey, { algorithm: 'RS256' });
\n\n

4. เก็บ Token ใน Local Storage

\n\n

ปัญหา: Local Storage ถูกโจมตีด้วย XSS ได้ง่าย

\n\n
// ผิดพลาด - เก็บใน Local Storage\nlocalStorage.setItem('token', response.data.access_token);\n\n// ถูกต้อง - ใช้ HttpOnly Cookie\n// Server side: ตั้งค่า cookie พร้อม flag ที่ปลอดภัย\nres.cookie('access_token', token, {\n    httpOnly: true,    // ป้องกัน JavaScript เข้าถึง\n    secure: true,      // ส่งผ่าน HTTPS เท่านั้น\n    sameSite: 'strict', // ป้องกัน CSRF\n    maxAge: 3600000,   // 1 ชั่วโมง\n    path: '/'\n});\n\n// ถูกต้อง - สำหรับ SPA ใช้ memory และ secure storage\nclass TokenManager {\n    #token = null;\n    \n    setToken(token) {\n        this.#token = token;\n    }\n    \n    getToken() {\n        return this.#token;\n    }\n    \n    clearToken() {\n        this.#token = null;\n    }\n}\n\n// ใช้ httpOnly cookie สำหรับ automatic refresh\nasync function refreshToken() {\n    const response = await fetch('/api/auth/refresh', {\n        method: 'POST',\n        credentials: 'include' // ส่ง cookie ทุก request\n    });\n    return response.json();\n}
\n\n

Best Practices สำหรับ AI API Security

\n\n
    \n
  1. Rate Limiting - จำกัดจำนวน request ต่อผู้ใช้/เวลา
  2. \n
  3. Input Validation - ตรวจสอบ prompt ก่อนส่งให้ AI model
  4. \n
  5. Output Sanitization - กรองผลลัพธ์จาก AI เพื่อป้องกัน XSS
  6. \n
  7. Logging และ Monitoring - บันทึกการใช้งานเพื่อตรวจจับความผิดปกติ
  8. \n
  9. Token Rotation - สร้าง token ใหม่เป็นระยะ
  10. \n
\n\n

สรุป

\n\n

การปกป้อง AI API ด้วย OAuth2 และ JWT เป็นแนวทางที่ได้รับการยอมรับอย่างกว้างขวาง สิ่งสำคัญคือต้องใช้ algorithm ที่ถูกต้อง เก็บ secret อย่างปลอดภัย และตรวจสอบ token อย่างเข้มงวด นอกจากนี้ควรใช้ additional security measures เช่น rate limiting และ HTTPS เสมอ

" } ```