Altsis ์์คํ ์ ๋ณด์ ์ ์ฑ , ์ํธํ ์ฒด๊ณ, ์ ๊ทผ ์ ์ด ๋ฐ ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ์ค๋ช ํฉ๋๋ค.
Altsis๋ ํ์ ๊ฐ์ธ์ ๋ณด์ ๊ต์ก ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ์์คํ ์ผ๋ก, ๋ค์ธต ๋ณด์ ์ ๋ต์ ์ ์ฉํฉ๋๋ค.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Altsis ๋ณด์ ์ฒด๊ณ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ โโ ํต์ ๋ณด์ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ HTTPS (ACM + CloudFront/ALB) โ โ
โ โ CORS ๋๋ฉ์ธ ์ ํ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโ ์ธ์ฆ ๋ณด์ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Passport.js (๋ก์ปฌ + Google OAuth 2.0) โ โ
โ โ Redis ๊ธฐ๋ฐ ์ธ์
๊ด๋ฆฌ (TTL 24์๊ฐ) โ โ
โ โ ๋ฏธ๋ค์จ์ด ๊ธฐ๋ฐ ๊ถํ ์ฒดํฌ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโ ๋ฐ์ดํฐ ๋ณด์ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ bcrypt ๋น๋ฐ๋ฒํธ ํด์ฑ โ โ
โ โ mongoose-encryption ํ๋ ์ํธํ โ โ
โ โ S3 Pre-signed URL (5๋ถ ๋ง๋ฃ) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโ ์ธํ๋ผ ๋ณด์ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ ๋ณด์ ๊ทธ๋ฃน, IAM ์ต์ ๊ถํ โ โ
โ โ ํ๊ฒฝ ๋ณ์ ์ํธํ ๊ด๋ฆฌ โ โ
โ โ S3 ๋ฒํท ์ ๊ทผ ์ ์ด โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ๋ bcrypt ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ํด์ฑ๋์ด ์ ์ฅ๋ฉ๋๋ค. ์๋ฌธ ๋น๋ฐ๋ฒํธ๋ ์ด๋์๋ ์ ์ฅ๋์ง ์์ต๋๋ค.
| ํญ๋ชฉ | ์ค๋ช |
|---|---|
| ์๊ณ ๋ฆฌ์ฆ | bcrypt |
| Salt Rounds | ํ๊ฒฝ ๋ณ์ saltRounts๋ก ์ค์ (๊ถ์ฅ: 10 ์ด์) |
| ์ ์ฉ ์์ | ์ฌ์ฉ์ ์์ฑ ๋ฐ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ์ ์๋ ์ ์ฉ |
| ๋ชจ๋ธ | User |
๋น๋ฐ๋ฒํธ ์
๋ ฅ
โ
โผ
bcrypt.genSalt(saltRounds) โ ๋๋ค Salt ์์ฑ
โ
โผ
bcrypt.hash(password, salt) โ Salt + ๋น๋ฐ๋ฒํธ ํด์ฑ
โ
โผ
ํด์ฑ๋ ๊ฐ DB์ ์ ์ฅ
๋ก๊ทธ์ธ ์ ๋น๋ฐ๋ฒํธ ์
๋ ฅ
โ
โผ
bcrypt.compare(plainPassword, hashedPassword)
โ
โโ true โ ์ธ์ฆ ์ฑ๊ณต
โโ false โ ์ธ์ฆ ์คํจ
Note
bcrypt๋ ๋ด๋ถ์ ์ผ๋ก Salt๋ฅผ ํด์๊ฐ์ ํฌํจ์ํค๋ฏ๋ก ๋ณ๋์ Salt ์ ์ฅ์ด ํ์ํ์ง ์์ต๋๋ค. Salt Rounds ๊ฐ์ด ๋์์๋ก ๋ณด์์ด ๊ฐํ๋์ง๋ง ์ฐ์ฐ ์๊ฐ์ด ์ฆ๊ฐํฉ๋๋ค.
์๊ฐ ๋ฑ๋ก(Enrollment) ๋ชจ๋ธ์ ํ๊ฐ(evaluation) ํ๋๋ mongoose-encryption์ผ๋ก ์ํธํ๋ฉ๋๋ค.
| ํญ๋ชฉ | ์ค๋ช |
|---|---|
| ๋ชจ๋ธ | Enrollment |
| ์ํธํ ํ๋ | evaluation |
| ์ํธํ ํค | ENCKEY_E (32๋ฐ์ดํธ Base64) |
| ์๋ช ํค | SIGKEY_E (64๋ฐ์ดํธ Base64) |
| ์๊ณ ๋ฆฌ์ฆ | AES-256-CBC (์ํธํ) + HMAC-SHA-512 (์๋ช ) |
// backend/src/models/Enrollment.js
enrollmentSchema.plugin(encrypt, {
encryptionKey: process.env["ENCKEY_E"],
signingKey: process.env["SIGKEY_E"],
encryptedFields: ["evaluation"],
});ํ์ ๊ธฐ๋ก(Archive) ๋ชจ๋ธ์ ๋ฐ์ดํฐ(data) ํ๋๋ ๋ณ๋์ ํค ์์ผ๋ก ์ํธํ๋ฉ๋๋ค.
| ํญ๋ชฉ | ์ค๋ช |
|---|---|
| ๋ชจ๋ธ | Archive |
| ์ํธํ ํ๋ | data |
| ์ํธํ ํค | ENCKEY_A (32๋ฐ์ดํธ Base64) |
| ์๋ช ํค | SIGKEY_A (64๋ฐ์ดํธ Base64) |
| ์๊ณ ๋ฆฌ์ฆ | AES-256-CBC (์ํธํ) + HMAC-SHA-512 (์๋ช ) |
// backend/src/models/Archive.js
archiveSchema.plugin(encrypt, {
encryptionKey: process.env["ENCKEY_A"],
signingKey: process.env["SIGKEY_A"],
encryptedFields: ["data"],
});Caution
์ํธํ ํค ๊ด๋ฆฌ ์ฃผ์์ฌํญ
- ์ํธํ ํค๋ฅผ ๋ถ์คํ๋ฉด ์ํธํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ณต๊ตฌํ ์ ์์ต๋๋ค
- ํค๋ ๋ฐ๋์ ์์ ํ ๊ณณ์ ๋ณ๋๋ก ๋ฐฑ์ ํด์ผ ํฉ๋๋ค
- ํ๊ฐ ์ ๋ณด์ ํ์ ๊ธฐ๋ก์ ์๋ก ๋ค๋ฅธ ํค ์์ ์ฌ์ฉํ์ฌ ๊ฒฉ๋ฆฌํฉ๋๋ค
- ํค ๊ต์ฒด ์์๋ ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ๋จผ์ ๋ณตํธํํ ํ ์ ํค๋ก ์ฌ์ํธํํด์ผ ํฉ๋๋ค
# ์ํธํ ํค ์์ฑ (32๋ฐ์ดํธ Base64)
openssl rand -base64 32
# ์๋ช
ํค ์์ฑ (64๋ฐ์ดํธ Base64)
openssl rand -base64 64์ฌ์ฉ์ ์ธ์ ์ Redis์ ์ ์ฅ๋๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ๋ณด์ ์ค์ ์ด ์ ์ฉ๋ฉ๋๋ค.
| ํญ๋ชฉ | ์ค์ | ์ค๋ช |
|---|---|---|
| ์ ์ฅ์ | Redis Cloud (connect-redis) |
๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ ๋น ๋ฅธ ์ธ์ ์ ๊ทผ |
| TTL | 24์๊ฐ (86400์ด) |
์ธ์ ๋ง๋ฃ ์๊ฐ |
| ์ธ์ ํค | session_key ํ๊ฒฝ ๋ณ์ |
์ธ์ ์ฟ ํค ์๋ช ์ ์ฌ์ฉ |
| httpOnly | true |
JavaScript์์ ์ฟ ํค ์ ๊ทผ ์ฐจ๋จ |
| resave | false |
๋ณ๊ฒฝ๋์ง ์์ ์ธ์ ์ฌ์ ์ฅ ๋ฐฉ์ง |
| saveUninitialized | false |
์ด๊ธฐํ๋์ง ์์ ์ธ์ ์ ์ฅ ๋ฐฉ์ง |
| rolling | true |
์์ฒญ๋ง๋ค ์ธ์ ๋ง๋ฃ ์๊ฐ ๊ฐฑ์ |
// backend/src/app.js
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env["session_key"].trim(),
cookie: {
httpOnly: true,
secure: false, // ALB์์ HTTPS ์ข
๋ฃ ํ HTTP๋ก ์ ๋ฌ๋๋ฏ๋ก
},
rolling: true,
store: new RedisStore({
client: redisClient,
ttl: 24 * 60 * 60, // 24์๊ฐ
}),
})
);๋ก๊ทธ์ธ ์ฑ๊ณต
โ
โผ
์ธ์
์์ฑ โ Redis์ ์ ์ฅ (TTL: 24์๊ฐ)
โ
โผ
์ธ์
์ฟ ํค ํด๋ผ์ด์ธํธ์ ์ ๋ฌ (httpOnly)
โ
โผ
์ดํ ์์ฒญ๋ง๋ค ์ธ์
ํ์ธ + TTL ๊ฐฑ์ (rolling)
โ
โโ 24์๊ฐ ๋ฏธํ๋ โ ์ธ์
์๋ ๋ง๋ฃ
โโ ๋ก๊ทธ์์ โ ์ธ์
๋ช
์์ ์ญ์
ํ์ฉ๋ ๋๋ฉ์ธ์์๋ง API์ ์ ๊ทผํ ์ ์๋๋ก CORS๋ฅผ ์ ํํฉ๋๋ค.
// backend/src/app.js
app.use(
cors({
origin: process.env["URL"].trim(), // ํ์ฉํ ํด๋ผ์ด์ธํธ URL
credentials: true, // ์ฟ ํค ์ ์ก ํ์ฉ
})
);| ํญ๋ชฉ | ์ค๋ช |
|---|---|
origin |
ํ๊ฒฝ ๋ณ์ URL์ ์ค์ ๋ ํด๋ผ์ด์ธํธ ๋๋ฉ์ธ๋ง ํ์ฉ |
credentials |
true - ์ธ์
์ฟ ํค๋ฅผ ํฌํจํ ์์ฒญ ํ์ฉ |
Important
CORS origin์๋ ์ ํํ ํด๋ผ์ด์ธํธ URL์ ์ค์ ํด์ผ ํฉ๋๋ค. ์์ผ๋์นด๋(*)๋ฅผ ์ฌ์ฉํ๋ฉด credentials: true์ ํจ๊ป ์๋ํ์ง ์์ผ๋ฉฐ, ๋ณด์์์ผ๋ก๋ ์ํํฉ๋๋ค.
๋ชจ๋ ํด๋ผ์ด์ธํธ-์๋ฒ ํต์ ์ HTTPS๋ก ์ํธํ๋ฉ๋๋ค.
| ๊ตฌ๊ฐ | HTTPS ์ฒ๋ฆฌ | ์ธ์ฆ์ |
|---|---|---|
| ํด๋ผ์ด์ธํธ โ CloudFront | CloudFront์์ HTTPS ์ข ๋ฃ | ACM (us-east-1) |
| ํด๋ผ์ด์ธํธ โ ALB | ALB์์ HTTPS ์ข ๋ฃ | ACM (์๋น์ค ๋ฆฌ์ ) |
| ALB โ EC2 | HTTP (๋ด๋ถ ๋คํธ์ํฌ) | - |
[ํด๋ผ์ด์ธํธ] โโโ HTTPS โโโโ [CloudFront/ALB] โโโ HTTP โโโโ [EC2]
โ
ACM ์ธ์ฆ์๋ก
TLS ์ข
๋ฃ
S3์ ์ ์ฅ๋ ํ์ผ์ ์ง์ ์ ๊ทผํ ์ ์์ผ๋ฉฐ, Pre-signed URL์ ํตํด์๋ง ์ ๊ทผํฉ๋๋ค.
| ํญ๋ชฉ | ์ค์ |
|---|---|
| ๋ง๋ฃ ์๊ฐ | 5๋ถ (300์ด) |
| ์๋ช ๋ฐฉ์ | AWS Signature V4 |
| ์ฉ๋ | ํ์ผ ๋ค์ด๋ก๋ URL ์์ฑ |
// backend/src/_s3/fileBucket.js
const signedUrlExpireSeconds = 60 * 5; // 5๋ถ
export const signUrl = (key, filename, seconds = signedUrlExpireSeconds) => {
const preSignedUrl = fileS3.getSignedUrl("getObject", {
Bucket: fileBucket,
Key: key,
Expires: seconds,
ResponseContentDisposition: `attachment; filename="${encodeURI(filename)}"`,
});
// ...
};Pre-signed URL์ ๋์ ๋ฐฉ์:
1. ์ฌ์ฉ์๊ฐ ํ์ผ ๋ค์ด๋ก๋ ์์ฒญ
2. ์๋ฒ์์ S3 Pre-signed URL ์์ฑ (5๋ถ ์ ํจ)
3. ํด๋ผ์ด์ธํธ์ URL ์ ๋ฌ
4. ํด๋ผ์ด์ธํธ๊ฐ URL๋ก S3์ ์ง์ ๋ค์ด๋ก๋
5. 5๋ถ ํ URL ์๋ ๋ง๋ฃ
Altsis๋ Passport.js๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๊ฐ์ง ์ธ์ฆ ์ ๋ต์ ์ง์ํฉ๋๋ค.
| ์ ๋ต | ํ์ผ | ์ค๋ช |
|---|---|---|
| Local Strategy | _passport/localStrategy2.js |
์์ด๋/๋น๋ฐ๋ฒํธ ๋ก๊ทธ์ธ |
| Google Strategy | _passport/googleStrategy2.js |
Google OAuth 2.0 ๋ก๊ทธ์ธ |
์ฌ์ฉ์ โ ์์ด๋ + ๋น๋ฐ๋ฒํธ ์
๋ ฅ
โ
โผ
Passport Local Strategy
โ
โโ User ๋ชจ๋ธ์์ ์ฌ์ฉ์ ์กฐํ
โโ bcrypt.compare()๋ก ๋น๋ฐ๋ฒํธ ๊ฒ์ฆ
โ
โโ ์ฑ๊ณต โ serializeUser โ ์ธ์
์์ฑ
โโ ์คํจ โ ์๋ฌ ์๋ต
์ฌ์ฉ์ โ Google ๋ก๊ทธ์ธ ๋ฒํผ ํด๋ฆญ
โ
โผ
Google OAuth ์ธ์ฆ ํ์ด์ง ๋ฆฌ๋ค์ด๋ ํธ
โ
โผ
์ฌ์ฉ์ โ Google ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ
โ
โผ
Google โ ์ฝ๋ฐฑ URL๋ก ๋ฆฌ๋ค์ด๋ ํธ (์ธ์ฆ ์ฝ๋ ํฌํจ)
โ
โผ
Passport Google Strategy
โ
โโ ์ธ์ฆ ์ฝ๋๋ก ์ฌ์ฉ์ ์ ๋ณด ์กฐํ
โโ ๊ธฐ์กด ์ฌ์ฉ์์ ๋งค์นญ
โ
โโ ์ฑ๊ณต โ serializeUser โ ์ธ์
์์ฑ
โโ ์คํจ โ ์๋ฌ ์๋ต
// ์ง๋ ฌํ: ์ธ์
์ ์ต์ ์ ๋ณด๋ง ์ ์ฅ
passport.serializeUser(({ user, academyId }, done) => {
done(null, { _id: user._id, academyId });
});
// ์ญ์ง๋ ฌํ: ๋งค ์์ฒญ๋ง๋ค ์ธ์
์์ ์ฌ์ฉ์ ์ ๋ณด ๋ณต์
passport.deserializeUser(({ _id, academyId }, done) => {
User(academyId).findOne({ _id }, (err, user) => {
user["academyId"] = academyId;
done(null, user);
});
});API ์์ฒญ์ ์ฌ์ฉ์ ์ญํ ์ ๋ฐ๋ผ ์ ๊ทผ์ด ์ ํ๋ฉ๋๋ค.
| ์ญํ | ์ฝ๋ | ๊ถํ ๋ฒ์ |
|---|---|---|
| Owner | owner |
์์คํ ์ ์ฒด ๊ด๋ฆฌ |
| Admin | admin |
์์นด๋ฐ๋ฏธ ๊ด๋ฆฌ |
| Manager | manager |
ํ๊ต ๊ด๋ฆฌ |
| Member | member |
์ผ๋ฐ ์ฌ์ฉ์ ๊ธฐ๋ฅ |
| Guest | (๋ฏธ์ธ์ฆ) | ๊ณต๊ฐ API๋ง ์ ๊ทผ ๊ฐ๋ฅ |
HTTP ์์ฒญ
โ
โผ
์ธ์
ํ์ธ (req.isAuthenticated())
โ
โโ ๋ฏธ์ธ์ฆ โ Guest ์ฒ๋ฆฌ ๋๋ 403 ์๋ต
โ
โโ ์ธ์ฆ๋จ โ ์ญํ ํ์ธ (req.user.auth)
โ
โโ ๊ถํ ์ถฉ๋ถ โ ์์ฒญ ์ฒ๋ฆฌ
โโ ๊ถํ ๋ถ์กฑ โ 403 Forbidden
| ๋ฒํท | ์ ๊ทผ ๋ฐฉ์ | ์ค๋ช |
|---|---|---|
| ํด๋ผ์ด์ธํธ ๋ฒํท | Public Read | ์ ์ ํ์ผ ์๋น (CloudFront ๊ฒฝ์ ) |
| ํ์ผ ๋ฒํท | Private | Pre-signed URL์ ํตํ ์ธ์ฆ๋ ์ ๊ทผ๋ง ํ์ฉ |
| ๋ก๊ทธ ๋ฒํท | Private | ์๋ฒ์์๋ง ์ฐ๊ธฐ, ๊ด๋ฆฌ์๋ง ์ฝ๊ธฐ |
๊ฐ ์๋น์ค์ ํ์ํ ์ต์ํ์ ๊ถํ๋ง ๋ถ์ฌํฉ๋๋ค.
| ์๋น์ค | ํ์ฉ ์์ | ๋์ ๋ฆฌ์์ค |
|---|---|---|
| S3 | s3:PutObject, s3:DeleteObject, s3:ListBucket |
ํด๋ผ์ด์ธํธ ๋ฒํท |
| ์๋น์ค | ํ์ฉ ์์ | ๋์ ๋ฆฌ์์ค |
|---|---|---|
| S3 | s3:GetObject, s3:PutObject, s3:DeleteObject, s3:ListBucket |
ํ์ผ ๋ฒํท |
| S3 | s3:PutObject |
๋ก๊ทธ ๋ฒํท |
| ํญ๋ชฉ | ์ค์ |
|---|---|
| ํ์ผ ํฌ๊ธฐ ์ ํ | Multer ์ค์ ์ ๋ฐ๋ฆ |
| ํ์ผ ํ์ ๊ฒ์ฆ | MIME ํ์ ์ฒดํฌ |
| ์ ์ฅ ๊ฒฝ๋ก | ์์นด๋ฐ๋ฏธ ID๋ก ๊ฒฉ๋ฆฌ ({academyId}/archive/...) |
| ๊ท์น | ์ค๋ช |
|---|---|
.gitignore ํฌํจ |
.env ํ์ผ์ด Git์ ์ปค๋ฐ๋์ง ์๋๋ก ๋ณด์ฅ |
| ๋ก์ปฌ ๊ด๋ฆฌ | ๊ฐ๋ฐ์๊ฐ ๋ก์ปฌ์์ ์ง์ ์์ฑ ๋ฐ ๊ด๋ฆฌ |
| ๊ณต์ ๊ธ์ง | ์ฌ๋, ์ด๋ฉ์ผ ๋ฑ์ผ๋ก ํ๊ฒฝ ๋ณ์ ๊ณต์ ๊ธ์ง |
| ํน์ฑ | ์ค๋ช |
|---|---|
| ์ํธํ ์ ์ฅ | GitHub์ด Secrets์ ์ํธํํ์ฌ ์ ์ฅ |
| ์ํฌํ๋ก์ฐ์์๋ง ์ ๊ทผ | GitHub Actions ์คํ ์์๋ง ๋ณตํธํ |
| ๋ก๊ทธ ๋ง์คํน | ์ํฌํ๋ก์ฐ ๋ก๊ทธ์์ ์๋์ผ๋ก ๋ง์คํน ์ฒ๋ฆฌ |
| ์ ๊ทผ ์ ํ | ๋ฆฌํฌ์งํ ๋ฆฌ ๊ด๋ฆฌ์๋ง ์ค์ ๊ฐ๋ฅ |
| ๋ฑ๊ธ | ํ๊ฒฝ ๋ณ์ | ์ ์ถ ์ ์ํฅ |
|---|---|---|
| ์ต๊ณ | ENCKEY_*, SIGKEY_* |
์ํธํ๋ ํ์ ๋ฐ์ดํฐ ๋ณตํธํ ๊ฐ๋ฅ |
| ๋์ | DB_URL, REDIS_URL |
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ง์ ์ ๊ทผ ๊ฐ๋ฅ |
| ๋์ | s3_secretAccessKey* |
S3 ๋ฒํท ์ ๊ทผ ๊ฐ๋ฅ |
| ์ค๊ฐ | session_key |
์ธ์ ์์กฐ ๊ฐ๋ฅ์ฑ |
| ์ค๊ฐ | GOOGLE_CLIENT_ID |
OAuth ์ธ์ฆ ์ ์ฉ ๊ฐ๋ฅ์ฑ |
| ๋ฎ์ | SERVER_PORT, S3_REGION |
์์คํ ๊ตฌ์ฑ ์ ๋ณด ๋ ธ์ถ |
- ๋ชจ๋ ํ๊ฒฝ ๋ณ์๊ฐ GitHub Secrets์ ๋ฑ๋ก๋์ด ์๋๊ฐ
-
.envํ์ผ์ด.gitignore์ ํฌํจ๋์ด ์๋๊ฐ - HTTPS๊ฐ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๋ชจ๋์ ์ ์ฉ๋์ด ์๋๊ฐ
- CORS origin์ด ์ ํํ ํด๋ผ์ด์ธํธ URL๋ก ์ค์ ๋์ด ์๋๊ฐ
- MongoDB Atlas ๋คํธ์ํฌ ์ ๊ทผ์ด EC2 IP๋ก ์ ํ๋์ด ์๋๊ฐ
- S3 ๋ฒํท ์ ์ฑ ์ด ์ต์ ๊ถํ์ผ๋ก ์ค์ ๋์ด ์๋๊ฐ
- IAM ์ฌ์ฉ์์ ์ต์ ๊ถํ๋ง ๋ถ์ฌ๋์ด ์๋๊ฐ
- bcrypt salt rounds๊ฐ 10 ์ด์์ผ๋ก ์ค์ ๋์ด ์๋๊ฐ
- ์ํธํ ํค๊ฐ ์์ ํ๊ฒ ๋ฐฑ์ ๋์ด ์๋๊ฐ
- GitHub Personal Access Token ๋ง๋ฃ ์ฌ๋ถ ํ์ธ
- AWS IAM ์ ๊ทผ ํค ๊ต์ฒด (90์ผ ์ฃผ๊ธฐ ๊ถ์ฅ)
- S3 ๋ฒํท ํผ๋ธ๋ฆญ ์ ๊ทผ ์ค์ ํ์ธ
- MongoDB Atlas ๋คํธ์ํฌ ์ ๊ทผ ๋ชฉ๋ก ๊ฒํ
- ์ฌ์ฉํ์ง ์๋ ์ฌ์ฉ์ ๊ณ์ ๋นํ์ฑํ
- ์๋ฒ ๋ก๊ทธ์์ ๋น์ ์ ์ ๊ทผ ํจํด ํ์ธ
- Node.js ์์กด์ฑ ๋ณด์ ์ทจ์ฝ์ ์ค์บ (
npm audit) - Docker ์ด๋ฏธ์ง ๋ณด์ ์ค์บ
ํ๊ฒฝ ๋ณ์๋ ํค๊ฐ ์ ์ถ๋ ๊ฒฝ์ฐ:
-
- ์ ์ถ๋ ํค/ํ ํฐ ์ฆ์ ๋ฌดํจํ
-
- ์ ํค/ํ ํฐ ์์ฑ ๋ฐ ๊ต์ฒด
-
- GitHub Secrets ์ ๋ฐ์ดํธ
-
- ์๋ฒ ์ฌ๋ฐฐํฌ
-
- ์ ๊ทผ ๋ก๊ทธ ๋ถ์ (์ ์ถ ๊ธฐ๊ฐ ๋์์ ๋น์ ์ ์ ๊ทผ ํ์ธ)
-
- ์ํฅ๋ฐ์ ๋ฐ์ดํฐ ๋ฒ์ ํ์
-
- ํ์ ์ ์ฌ์ฉ์ ๋น๋ฐ๋ฒํธ ๊ฐ์ ๋ณ๊ฒฝ
-
- ์ธ์๋ํธ ๋ณด๊ณ ์ ์์ฑ
Altsis์ ๋ณด์ ์ทจ์ฝ์ ์ ๋ฐ๊ฒฌํ ๊ฒฝ์ฐ, ๋ค์ ์ฑ๋๋ก ๋ณด๊ณ ํด ์ฃผ์ธ์.
| ํญ๋ชฉ | ์ฐ๋ฝ์ฒ |
|---|---|
| GitHub | @devgoodway |
| ๋ณด๊ณ ๋ฐฉ์ | GitHub Issue (Private) ๋๋ ์ง์ ์ฐ๋ฝ |
- ์ทจ์ฝ์ ์ ํ (์: XSS, CSRF, ์ธ์ฆ ์ฐํ ๋ฑ)
- ์ฌํ ์ ์ฐจ (๋จ๊ณ๋ณ)
- ์ํฅ ๋ฒ์
- ๊ฐ๋ฅํ ๊ฒฝ์ฐ, ๊ฐ์ ๋ฐฉ์ ์ ์
Warning
๋ณด์ ์ทจ์ฝ์ ์ ๊ณต๊ฐ Issue๋ก ๋ฑ๋กํ์ง ๋ง์ธ์. ๋ฐ๋์ ๋น๊ณต๊ฐ ์ฑ๋์ ํตํด ๋ณด๊ณ ํด ์ฃผ์ธ์. ์ทจ์ฝ์ ์ด ์์ ๋ ๋๊น์ง ๊ณต๊ฐ๋ฅผ ์์ ํด ์ฃผ์๋ฉด ๊ฐ์ฌํ๊ฒ ์ต๋๋ค.