2025. 1. 15. 17:56ㆍTIL
Server
현재 로그인을 할때 AccessToken은 헤더에 담아서 클라이언트에게 보내고 RefreshToken은 secure=ture 설정을 해주었기때문에 쿠키가 HTTPS 연결에서만 전달이 되는 상황이다.
@PostMapping("/login")
fun login(@RequestBody request: LoginRequest, response: HttpServletResponse): ResponseEntity<
Map<String, String>> {
val tokenResponse = oAuthService.login(request)
// ACCESS TOKEN을 헤더에 담아서 반환
val headers = HttpHeaders()
headers.add("Authorization", "Bearer ${tokenResponse.accessToken}")
// REFRESH TOKEN을 쿠키에 저장
val refreshTokenCookie = Cookie("refreshToken", tokenResponse.refreshToken).apply {
isHttpOnly = true
secure = true
path = "/"
}
response.addCookie(refreshTokenCookie)
val messageJson = mapOf(
"message" to "토큰 발급 성공"
)
return ResponseEntity.ok()
.headers(headers)
.body(messageJson)
}
지금 테스트 단계에서는 HTTP를 이용하고 있기 때문에 secure = true 부분을 삭제해도 되지만 어차피 추후에 배포를 할때 HTTPS로 배포를 할것이기 때문에 SSL/HTTPS를 적용을 할것이다.
자체 성명 (Self-Signed) 인증서 생성
keytool -genkeypair -alias my-ssl-key -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650
생성된 keystore 파일은 main/resources 하위에 위치하고 gitingore에 명시하여 git에 공유하지 않도록 설정한다.
application.yml
server:
port: 443
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-type: PKCS12
key-alias: my-ssl-key
key-store-password: ******
포트번호 443으로 접속하면 https 연결이 된것을 확인할 수 있다.
https://localhost/swagger-ui/index.html#/
주의 요함이라고 표시가 된 이유는 인증기관(CA)에서 인증받은 인증서가 아닌 자체 서명 인증서이기 때문에 경고 표시가 나오는것이다. 나중에 실서비스를 할때는 CA에서 인증받은 인증서를 사용하거나 AWS에서 관리하는 SSL 인증서를 사용할 예정이다.
Client
서버 뿐만 아니라 클라이언트에서도 https 연결이 되어야하기 때문에 클라이언트도 마찬가지로 임시로 자체 성명을 이용한다.
클라이언트 ssl 생성
https://slproweb.com/products/Win32OpenSSL.html
Win64 OpenSSL v3.4.0 exe 파일 설치 및 실행
(light버전으로 설치하면 openssl.cfg 파일이 생성되지 않기때문에 light버전을 설치하면 안된다!!)
환경변수 설정
openssl version
제대로 설정되었는지 확인
cert 파일 생성
mkdir cert
private key 설정
openssl genrsa -out client-key.pem 2048
CSR 설정
openssl req -new -key client-key.pem -out client-csr.pem
인증서 발급
openssl x509 -req -in client-csr.pem -signkey client-key.pem -out client-cert.pem -days 365
cert 폴더 내 파일이 생성된것을 확인
서버 인증서 발급
openssl req -nodes -new -x509 -keyout server-key.pem -out server-cert.pem -days 365
기존 server.js
// server.js
const express = require('express');
const path = require('path');
const app = express();
const port = 3000;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
app.listen(port, () => {
console.log(`Frontend server is running on http://localhost:${port}`);
});
HTTPS 적용된 server.js
// server.js
const express = require('express');
const path = require('path');
const fs = require('fs');
const https = require('https');
const http = require('http');
const app = express();
const httpsPort = 3000;
const httpPort = 3001; // HTTP 포트 (리디렉션용)
// SSL 인증서 경로 (key.pem, cert.pem)
const sslOptions = {
key: fs.readFileSync(path.join(__dirname, 'cert', 'server-key.pem')),
cert: fs.readFileSync(path.join(__dirname, 'cert', 'server-cert.pem'))
};
// 정적 파일 제공
app.use(express.static(path.join(__dirname, 'public')));
// 라우트 설정
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
// HTTPS 서버 실행
https.createServer(sslOptions, app).listen(httpsPort, () => {
console.log(`Frontend server is running on https://localhost:${httpsPort}`);
});
// HTTP 요청을 HTTPS로 리디렉션
http.createServer((req, res) => {
res.writeHead(301, { "Location": `https://localhost:${httpsPort}${req.url}` });
res.end();
}).listen(httpPort, () => {
console.log(`HTTP server is running on http://localhost:${httpPort} (Redirecting to HTTPS)`);
});
node server.js
HTTPS로 연결이 된것을 확인할 수 있다.
클라이언트 접속
https://localhost:3000
클라이언트도 https로 접속이 잘 된것을 확인할 수 있다.
'TIL' 카테고리의 다른 글
Redis를 이용한 로그아웃 (0) | 2025.01.14 |
---|---|
Swagger failed to load api definition 오류 (0) | 2025.01.13 |
신규 회원가입시 𝐷𝑒𝑓𝑎𝑢𝑙𝑡-𝐼𝑚𝑎𝑔𝑒 설정 및 접근 가능한 채팅방만 조회 (0) | 2025.01.07 |
𝒫𝓇ℯ𝓈𝒾ℊ𝓃ℯ𝒹 𝒰ℛℒ과 프로필 사진 (0) | 2025.01.06 |
S3을 이용한 프로필 사진 업로드 구현 (1) | 2025.01.03 |