diff --git a/app.js b/app.js index f4ca5cfaccd0535d196eac2aca6b126b1155d917..5c204821ec7ecc5d1fa68bdb59b3257d1f1a9aee 100644 --- a/app.js +++ b/app.js @@ -3,7 +3,7 @@ const app = express(); const mongoose = require('mongoose'); const cors = require('cors'); -app.use(express.urlencoded({ extended: false })); +//app.use(express.urlencoded({ extended: false })); const passport = require('./config/passport'); //const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser'); @@ -15,11 +15,40 @@ require('dotenv').config(); const secretKey = process.env.JWT_SECRET; // 실제 환경에서는 환경 변수로 관리하세요. const refreshTokenSecretKey = process.env.JWT_REFRESH_SECRET; +const https = require('https'); +const fs = require('fs'); +const expressSanitizer = require('express-sanitizer'); + +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); +app.use(expressSanitizer()); +app.use('/', express.static('public')); + +// SSL 인증서와 개인 키 파일 경로 설정 +// SSL 옵션 설정 +const sslOptions = { + key: fs.readFileSync('./cert/server.key'), + cert: fs.readFileSync('./cert/server.cert'), + }; + +// // HTTP 서버 설정 (포트 8001) +// const HTTP_PORT = 8001; +// app.listen(HTTP_PORT, () => { +// console.log(`HTTP server started on port ${HTTP_PORT}`); +// }); + +// // HTTPS 서버 설정 (포트 8080) +// const HTTPS_PORT = 8080; +// https.createServer(options, app).listen(HTTPS_PORT, () => { +// console.log(`HTTPS server started on port ${HTTPS_PORT}`); +// }); //middleware app.use(cors({ - origin: "http://localhost:3000", + origin: "https://localhost:3000", credentials: true, //쿠키전송 허용 + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] })); //비밀번호 변경 라우트 등록 const passwordRoutes = require('./route/conf_password'); @@ -143,6 +172,10 @@ app.get('/googlelogin/redirect', { expiresIn: '7d' } // 리프레시 토큰 유효 기간: 7일 ); + // 토큰 로그 출력 + console.log('생성된 액세스 토큰:', accessToken); + console.log('생성된 리프레시 토큰:', refreshToken); + // 사용자 데이터베이스에 리프레시 토큰 저장 req.user.refreshToken = refreshToken; await req.user.save(); @@ -150,18 +183,19 @@ app.get('/googlelogin/redirect', // 쿠키에 토큰 저장 res.cookie('accessToken', accessToken, { httpOnly: true, - secure: process.env.NODE_ENV === 'production', + secure: true, sameSite: 'Strict', maxAge: 15 * 60 * 1000 // 15분 }); res.cookie('refreshToken', refreshToken, { httpOnly: true, - secure: process.env.NODE_ENV === 'production', + secure: true, sameSite: 'Strict', maxAge: 7 * 24 * 60 * 60 * 1000 // 7일 }); - res.redirect(`http://localhost:3000/login#token=${token}`); + //res.redirect(`http://localhost:3000/login#token=${token}`); + res.redirect('https://localhost:3000/'); console.log(`구글 로그인 성공: ${req.user.email}`); } ); @@ -218,7 +252,7 @@ app.post('/token', async (req, res) => { res.cookie('accessToken', newAccessToken, { httpOnly: true, - secure: process.env.NODE_ENV === 'production', + secure: true, sameSite: 'Strict', maxAge: 15 * 60 * 1000 // 15분 }); @@ -331,7 +365,7 @@ app.post('/login', async (req, res) => { //https 환경에서만 res.cookie('accessToken', accessToken, { httpOnly: true, - secure: process.env.NODE_ENV === 'production', // 프로덕션 환경에서만 secure 플래그 활성화 + secure: true, // 프로덕션 환경에서만 secure 플래그 활성화 sameSite: 'Strict', // CSRF 방지를 위해 sameSite 옵션 설정 maxAge: 3600000 // 1시간 (토큰 만료 시간과 동일하게 설정) }); @@ -398,6 +432,24 @@ app.get('/auth/status', authenticateToken, (req, res) => { }); -app.listen(process.env.PORT, () => { - console.log(`Server is running on http://localhost:${process.env.PORT}`); -}); +// app.listen(process.env.PORT, () => { +// console.log(`Server is running on http://localhost:${process.env.PORT}`); +// }); + +// HTTPS 강제 적용 미들웨어 (선택 사항) +app.use((req, res, next) => { + if (req.secure || req.headers['x-forwarded-proto'] === 'https') { + next(); + } else { + res.redirect(`https://${req.headers.host}${req.url}`); + } + }); + +https.createServer(sslOptions, app).listen(process.env.PORT || 8000, () => { + console.log(`HTTPS 서버가 실행 중입니다: https://localhost:${process.env.PORT || 8000}`); + }); + +// HTTP 서버 실행 (선택 사항) +// http.createServer(app).listen(8080, () => { +// console.log('HTTP 서버가 실행 중입니다: http://localhost:8080'); +// }); \ No newline at end of file diff --git a/cert/server.cert b/cert/server.cert new file mode 100644 index 0000000000000000000000000000000000000000..73953a168cdca87a54b90769e08052dc1e2a02a3 --- /dev/null +++ b/cert/server.cert @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDazCCAlOgAwIBAgIUKmvSyaI7ZwBUWv+Aip2q+ozENK8wDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEyMDQxNDI2MTBaFw0yNTAx +MDMxNDI2MTBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQCoB4lkQ8gtZALn6xl1h/s9Ub1MuAQBJEetY5UV1gJW +2aGtICzVvWgzVGbLgBJOf2jw3EBfuAGPhYcOxP2+aOHxxf3+gp5ZWWjHMa202/F0 +thvlnEZTCg0modLKOw4CNMLE6OD3mhjb7KxeCZbEWMDlnYiTBsoANQrrLeAHqUOz +c2OmCuvLHxdTpLa9KmEGqQOQRNyrrhx1lKfewTRtFHpcdY2msCooa0gBYFKpEuaY +MEqrZEG2/bqUs8gSl6woeXXIN7c18ADToyQIL6Wsy57G7e3zvAehOckAWzN2/YXU +cA2FxregTiaYdmuI89BKJ3+tRUnTt2erlsGerMSCPlp1AgMBAAGjUzBRMB0GA1Ud +DgQWBBS6ssmy7CXbAnwsL68eESy337YE3jAfBgNVHSMEGDAWgBS6ssmy7CXbAnws +L68eESy337YE3jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAx +0b9exkxjIo/wm1Rqo+DEGdB1uIvLFWTximfxY0PYCERyw+RajBPlvGlqWZw0h1rH +BjIMkLW3axPdblVgAzC1J4F2ia2qH2JTF/waM2n5RkCmDXnjhpXRCeOcrv8dEvTe +0pqM3UC9QlElQ7zmTmUIdwJjWAar/rv6niGBmmG5j2NF66J0P8Bat0lndjFfXwWI +xth/u9GROzNEc3FSkHXK0VkGj76z8zsZginLccGqmysbsWWbN3ArVSv8iJoOOYq+ +5/XPNRT4POZod574hqr+2QBCgyJGjfZecWR7f7Jg3NMyAVS3i0Q9gEWdKDvTmJSx +sdd32Gq+4+jIsMm37c05 +-----END CERTIFICATE----- diff --git a/cert/server.key b/cert/server.key new file mode 100644 index 0000000000000000000000000000000000000000..88bbd6490585792f4fe36f666a133cd0c0c37c50 --- /dev/null +++ b/cert/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCoB4lkQ8gtZALn +6xl1h/s9Ub1MuAQBJEetY5UV1gJW2aGtICzVvWgzVGbLgBJOf2jw3EBfuAGPhYcO +xP2+aOHxxf3+gp5ZWWjHMa202/F0thvlnEZTCg0modLKOw4CNMLE6OD3mhjb7Kxe +CZbEWMDlnYiTBsoANQrrLeAHqUOzc2OmCuvLHxdTpLa9KmEGqQOQRNyrrhx1lKfe +wTRtFHpcdY2msCooa0gBYFKpEuaYMEqrZEG2/bqUs8gSl6woeXXIN7c18ADToyQI +L6Wsy57G7e3zvAehOckAWzN2/YXUcA2FxregTiaYdmuI89BKJ3+tRUnTt2erlsGe +rMSCPlp1AgMBAAECggEACW845eYPZosLxblT2d9LekctZZIceXLvylrBy3LTeUxp +cUbR9aNXpzApQGpdvMYXHpUDUUyL2+LfsTLa23bYnuJiz0hGu1YTlcGikvnZfhfe +i58hbLavA9kItJ2pvPJ48CTyQrzGggyxJeuMaVRhalMU0MqMC4Ru60MNZei5Wik8 +SZLwZJRp163QXedw5f6XJ2GLlOAnKx/prmx1DFkz8I6pruearqCtJDNLlxTqoYjR +oTfmlVSMvsObDt+SsKimQ+0t01jVNDB4LTZO1myUbHslrVFeedvrzrhvjlEirMGr +tpGFdyj/tBcPkSLl3MOPOBcLkGBrF1H0+Awi+b138QKBgQDlbVh2p0JwRe27nYWb +VaK+36ZK9yXeaRdkrWIaERFfOTLbun5amV2Sj6K1oXXDTe1WrOfmGE4cx1mSX3Qb +jLBWNKq/4Uui27f5onST54t0MUZlFOfAbRJuN6IH2sEY615apmb+0x8wVhMH4dhL +k6/94lEss7h/zadqASWyzOdYpQKBgQC7fbZNujdOvtiqwVH2hEY+tXm3kvuwzW+W +jIz4CkjmPxlIvt39h0WFGg1a6X1UYAXk4J7pxR039vcwd1Ep31TyYqoL1aYEDDiS +TgsSRrD3mlzkeqUxkamzIMgtoKzZ3U4fUMGw/z3TGlmIwS5oICqZPq6jMRONh/pZ +Vj7w4UKBkQKBgBOo+xuv2ZGlbGnXZcuZ2whgQe/KngQhHVATS4TQUZzHWgRaRtmc +qtgUVu0ZmO3Tj7MNvhGJo6fzrUlNxLVXqQS6HqeytriN+4X41eSWwuyCDHY9BF8I ++btYKRpjNIjeIofCGrFbhiCuP5M9VzuivEIVUr9x5y2MgfwjfQeFZ43BAoGAXolb +o8OSYaU/MJI7lrZJiRMOJW76c8KSUnHaHrNo4JfOUuzSmCRd/GgPddindiTYs/hC +iJL4UaC4MProtNlERtdS8Jawl/flinfJg1SbpK1zy0zAAMd2rriH1uHeZhf9bTLW +Bz4b2Va+8IKfuKcHc6+0dNqpBkMbC3K+V8ztMNECgYBo02wYaNgTbvKUBEPh/NwU +U3LhCpGcvZdVvKMiQSe2vwHs+udJ+pvIl6BPQmE8gyR9BchWnG6yGNNvzZUOvBry +Z/j+gXRq/xjtjU+SxCIS086hDUGW2vEaLGB1/V8pXuCnIY+Y41NiCVXeoe5Ve4ro +dDTrCCWZACy95J0BvmhQLQ== +-----END PRIVATE KEY----- diff --git a/config/passport.js b/config/passport.js index 69eb5322d5d1e20419d8c987712036286ed09c4c..1ba16b7f740f6b7418c2a2cfe9282b572b934315 100644 --- a/config/passport.js +++ b/config/passport.js @@ -8,7 +8,7 @@ const User = require('../models/user'); passport.use(new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, - callbackURL: `http://localhost:${process.env.PORT}/googlelogin/redirect` + callbackURL: `https://localhost:${process.env.PORT}/googlelogin/redirect` }, async (accessToken, refreshToken, profile, done) => { const { id, displayName, emails} = profile; try { diff --git a/middleware/authMiddleware.js b/middleware/authMiddleware.js index 00d246af06a7090b67bcee1f00d4cc17f995122a..060661133d9bc91f2f045176928fb44e2fefa5b8 100644 --- a/middleware/authMiddleware.js +++ b/middleware/authMiddleware.js @@ -4,14 +4,21 @@ require('dotenv').config(); const secretKey = process.env.JWT_SECRET; function authenticateToken(req, res, next) { - const token = req.cookies.token; // 쿠키에서 토큰 추출 + const token = req.cookies.accessToken; // 쿠키에서 토큰 추출 //const authHeader = req.headers['authorization']; //const token = authHeader && authHeader.split(' ')[1]; + console.log("토큰: ", token); - if (!token) return res.sendStatus(401); + if (!token) { + req.user = null; // 토큰이 없을 경우 null로 설정 + return next(); + } jwt.verify(token, secretKey, (err, decoded) => { - if (err) return res.sendStatus(403); + if (err) { + req.user = null; // 토큰이 유효하지 않을 경우도 null로 설정 + return next(); + } req.user = decoded; next(); diff --git a/models/user.js b/models/user.js index 0e0c68dc22a7b5f5356a3176ad9c56fc361f3f2e..6cabe20983ef66ce842673898096876847fbeed6 100644 --- a/models/user.js +++ b/models/user.js @@ -7,6 +7,7 @@ const userSchema = new mongoose.Schema({ name: String, password: String, //profilePicture: String, + // 리프레시 토큰 필드 추가 }); module.exports = mongoose.model('User', userSchema); diff --git a/package-lock.json b/package-lock.json index 089601cbade11e8f108aa5d7435f2349346f4e23..37f9a02c71cb8fc2ec2a05249491061c97c3f6ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "dotenv": "^16.4.5", "expres": "^0.0.5", "express": "^4.21.1", + "express-sanitizer": "^1.0.6", "express-session": "^1.18.1", "jsonwebtoken": "^9.0.2", "jwt-decode": "^4.0.0", @@ -589,6 +590,18 @@ "node": ">= 0.10.0" } }, + "node_modules/express-sanitizer": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/express-sanitizer/-/express-sanitizer-1.0.6.tgz", + "integrity": "sha512-77Ruhr/NTVGE2Ecc8pH3XedpreQiHRtwA+ONON0/nJam8Re/AvkGngd8EqKb2YKCqaL4Iw+W33IJXgHgMe7xaQ==", + "license": "MIT", + "dependencies": { + "sanitizer": "0.1.3" + }, + "engines": { + "node": "*" + } + }, "node_modules/express-session": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz", @@ -1756,6 +1769,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sanitizer": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/sanitizer/-/sanitizer-0.1.3.tgz", + "integrity": "sha512-j05vL56tR90rsYqm9ZD05v6K4HI7t4yMDEvvU0x4f+IADXM9Jx1x9mzatxOs5drJq6dGhugxDW99mcPvXVLl+Q==", + "license": "Apache-2.0" + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", diff --git a/package.json b/package.json index 53a9fc95e5a57fec3119f5322e19d8a23d897310..06665b6817a399db4b322ae148faa9d899c920c0 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dotenv": "^16.4.5", "expres": "^0.0.5", "express": "^4.21.1", + "express-sanitizer": "^1.0.6", "express-session": "^1.18.1", "jsonwebtoken": "^9.0.2", "jwt-decode": "^4.0.0",