๐ [ ๋ ํ๊ฐ ] Web Development with Node & Express 2ํ์ ์ฝ๊ณ ...
โ๏ธ ์๋ก
์ด ์ฑ
์ ๋ณด๊ฒ ๋ ๊ณ๊ธฐ๋ ์๋ฆฌ์ค ํ ํ๋ก์ ํธ์์ ํ๋ก ํธ์๋๋ฅผ ์ค๋นํ๊ณ ์๋ ๋์๊ฒ ๋ฌด์งํ๋ ๋ฐฑ์๋ ํํธ๋ฅผ ๋ด๋นํ๊ฒ ๋์๊ณ , ๋งจ๋
์ ํค๋ฉํ๋ ๊ฒฉ์ผ๋ก ๋ฐฑ์๋์ ๊ดํ ์ ๋ณด๋ฅผ ์ด๋ฆฌ์ ๋ฆฌ ์ฐพ์๋ณด๋ ์ค ๋น๊ต์ ์ต๊ทผ(2021.5.21.
)์ ์ถํํ๊ณ Spring
์ ๋ค๋ฃจ๋ ์ฑ
์ด ์๋๋ผ Express.js
๋ฅผ ๋ค๋ฃจ๋ ์์ ์ด์ด์ ๊ตฌ๋งคํ๋ค. ์ฑ
์ ์๋ผ๋์์ ์ฃผ๋ฌธํ๊ณ , ์ฑ
์ ์ฝ 450ํ์ด์ง๋ก ๊ตฌ์ฑ๋์ด์์ผ๋ฉฐ ๋
์๊ธฐ๊ฐ์ 2022.01.25 ~ 2022.02.19
์ด๋ค.
โ๏ธ ๋ณธ๋ก
ํํ์ด ์ฑ
์ ์ฝ์ผ๋ฉฐ ๋น์ฅ์ ๋ฐฑ์๋๋ฅผ ๊ตฌํํด์ผํ๋ํฐ๋ผ ๋ด๊ฐ ํ์ํ ์ฃผ์ ๋ง ๋จผ์ ์ดํด๋ดค๋ค. ์ต์คํ๋ ์ค ์๊ฐ, ํ์ง๋ณด์ฆ, ์ฟ ํค์ ์ธ์
, ๋ฏธ๋ค์จ์ด, ์ง์์ฑ, ๋ผ์ฐํ
, REST API์ JSON, SPA, ๋ณด์ ํํธ์๋ค. ์ด ์ค์์ ๊ฐ์ฅ ๊ธฐ์ต์ ๋จ๋ ๋ถ๋ถ์ ๋ฐ๋ก ๋ฏธ๋ค์จ์ด, ์ฟ ํค์ ์ธ์
์ธ๋ฐ, ๋๋ JWT
๋ฅผ ์ด์ฉํ์ฌ ์ธ์ฆ์ ๊ตฌํํ์ง๋ง ์๋ฒ์์ ์ฟ ํค๋ฅผ ์ ํ ์ธ์ํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ์์๋๋ฐ ๊ฒฐ๊ตญ cookie-parser
๋ฏธ๋ค์จ์ด๋ฅผ ์์ฑํ์ง ์์์ ์๊ธฐ๋ ๋ฌธ์ ์๋ค.. (์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฝ 3์๊ฐ์ ์ฝ์งํ๋ค.) ๋๋ถ์ ๋ฏธ๋ค์จ์ด์ ์ค์์ฑ์ ๊นจ๋ฌ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ฟ ํค์ ๋ํด ๊ธฐ์กด์ ์๊ณ ์๋ ์ง์๊ณผ ๋๋ถ์ด ๋ช ๊ฐ์ง ์๋ก์ด ์ฌ์ค์ ์๊ฒ ๋์๋๋ฐ, ์ฟ ํค์ ๊ดํด ์์๋ฌ์ผ ํ ์ค์ํ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ๋ค.
1. ์ฌ์ฉ์๊ฐ ์ฟ ํค ๋ด์ฉ์ ๋ณผ ์ ์๋ค.
- ์๋ฒ์์ ํด๋ผ์ด์ธํธ์ ๋ณด๋ด๋ ์ฟ ํค๋ ๋ชจ๋ ํด๋ผ์ด์ธํธ์์ ๋ณผ ์ ์๋ค. ์ฟ ํค๋ฅผ ์ํธํํด์ ์ฝํ
์ธ ๋ฅผ ๋ณดํธํ ์ ์๊ธด ํ์ง๋ง, ๋ณ๋ณํ ๋ชฉ์ ์ผ๋ก๋ง ์ฌ์ฉํ๋ค๋ฉด ๊ตณ์ด ์ํธํํ ์ด์ ๊ฐ ์๋ค. ์๋ช
๋ (Signed)์ฟ ํค๋ ์ฝํ
์ธ ๋ฅผ ์ฝ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค๊ธด ํ๊ฒ ์ง๋ง, ์ํธํ๋ผ๊ณ ํ ์ ์๋ ์์ค์ด ์๋๋ค.
2. ์ฌ์ฉ์๊ฐ ์ฟ ํค๋ฅผ ์ญ์ ํ๊ฑฐ๋ ๊ธ์งํ ์ ์๋ค.
- ์ฌ์ฉ์๋ ์ฟ ํค ์ ์ฒด์ ๋ํ ๊ถํ์ด ์๊ณ , ๋ธ๋ผ์ฐ์ ์๋ ์ฟ ํค๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก, ๋๋ ํ๊บผ๋ฒ์ ์ญ์ ํ๋ ๊ธฐ๋ฅ์ด ์๋ค. ๋ํ, ์ฌ์ฉ์๊ฐ ์ฟ ํค๋ฅผ ๊ธ์งํ ์๋ ์๋๋ฐ ์ด๋ด ๋ ์ฟ ํค ์์ด๋ ์ ๋๋ก ๋์ํ ์ ์๋ ์น ์ ํ๋ฆฌ์ผ์ด์
์ ์ ๋ง ๋จ์ํ ๊ธฐ๋ฅ ๋ง๊ณ ๋ ์ํํ๊ธฐ ์ด๋ ต๋ค.
3. ์ฟ ํค๋ ๊ณต๊ฒฉ์ ์ฌ์ฉ๋ ์ ์๋ค.
- XSS(cross-site-scripting attack) ๊ณต๊ฒฉ ์ค ์
์์ ์ธ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ก ์ฟ ํค ์ฝํ
์ธ ๋ฅผ ๋ฐ๊พธ๋ ๋ฐฉ๋ฒ๋ ์๋ค. ์๋ฒ์ ์ ์๋๋ ์ฟ ํค๋ฅผ ๋งน์ ํด์๋ ์ ๋๋ ์ด์ ์ค ํ๋๋ค. `์๋ช
๋ ์ฟ ํค(Signed cookie)`๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ก ์ฟ ํค๋ฅผ ๋ณ์กฐํ์ ๊ฒฝ์ฐ ๊ทธ ํ์ ์ด ๋ช
๋ฐฑํ ๋๋ฌ๋๋ฏ๋ก ๊ณต๊ฒฉ์ ๋ง๋๋ฐ ๋์์ด ๋๋ค. (์๋ช
๋ ์ฟ ํค๋ ์ผ๋ฐ์ ์ธ ์ฟ ํค๋ณด๋ค ์ฐ์ ์์๊ฐ ๋๋ค. ์๋ช
๋ ์ฟ ํค์์ ์ฌ์ฉ๋ ์ด๋ฆ์ ์ผ๋ฐ ์ฟ ํค์์๋ ์ฌ์ฉํ ์ ์๋ค.) ๋๋ `httpOnly` ์ต์
์ ์ฌ์ฉํ์ฌ ํด๋ผ์ด์ธํธ์์ ์ฟ ํค๋ฅผ ์์ ํ์ง ๋ชปํ๊ณ ์๋ฒ์์๋ง ๊ฐ๋ฅํ๊ฒ๋ ์ค์ ํ ์๋ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ํ์ฉ๋๊ฐ ์กฐ๊ธ ๋จ์ด์ง์ง๋ง ํจ์ฌ ์์ ํ๋ค.
4. ์ฟ ํค๋ฅผ ๋จ์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ ๋์น์ฑ๋ค.
- ์ฌ์ฉ์์ ์ปดํจํฐ์ ์ฟ ํค๋ ๋ฐ์ดํฐ๋ฅผ ๋๋ฌด ๋ง์ด ์ ์ฅํ๋ฉด ์ฌ์ฉ์๋ฅผ ์ง์ฆ๋๊ฒ ํ ์ ์์ผ๋ฏ๋ก ํผํด์ผ ํ๋ค. ์ฟ ํค๋ ์ต์ํ์ผ๋ก ์ ์งํด๋ผ.
5. ์ฟ ํค์์ ์ฌ์ฉ ํ ์ ์๋ option
- domain: ์ฟ ํค์ ๋๋ฉ์ธ์ ์ฐ๊ฒฐํ๋ค. ํ์ง๋ง ํ์ฌ ์๋ฒ๊ฐ ์คํ ์ค์ธ ๋๋ฉ์ธ์ด ์๋ ๋ค๋ฅธ ๋๋ฉ์ธ๊ณผ ์ฐ๊ฒฐํ ์๋ ์๋ค.
- path: ์ฟ ํค๊ฐ ์ ์ฉ๋ ๊ฒฝ๋ก๋ฅผ ์ง์ ํ๋ค. ๊ธฐ๋ณธ๊ฐ์ธ `/`๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ดํธ์ ๋ชจ๋ ํ์ด์ง์ ์ฟ ํค๊ฐ ์ ์ฉ๋๋ค. ๊ฒฝ๋ก๋ฅผ `/foo`๋ก ์ค์ ํ๋ฉด `/foo`, `/foo/bar` ๋ฑ์ ์ ์ฉ๋๋ค.
- maxAge: ํด๋ผ์ด์ธํธ๊ฐ ์ฟ ํค๋ฅผ ์ผ๋ง๋ ์ค๋ ๋ณด๊ดํ๊ณ ์์ด์ผ ํ๋์ง ๋ฐ๋ฆฌ์ด ๋จ์๋ก ์ง์ ํ๋ค. ์ด ์ต์
์ ์ค์ ํ์ง ์์ผ๋ฉด ์ฟ ํค๋ ๋ธ๋ผ์ฐ์ ๋ฅผ ๋ซ์ ๋ ์ญ์ ๋๋ค. `expired` ์ต์
์์ ๋ง๋ฃ ๋ ์ง๋ฅผ ์ค์ ํ ์๋ ์์ง๋ง ๋ฌธ๋ฒ์ด ๋ณต์กํ๊ธฐ ๋๋ฌธ์ `maxAge`๋ฅผ ๊ถํ๋ค.
- secure: `HTTPS` ์ฐ๊ฒฐ์ ํตํด์๋ง ์ฟ ํค๋ฅผ ์ ์กํ๋ค.
- httpOnly: ์๋ฒ์์๋ง ์ฟ ํค๋ฅผ ์์ ํ๋ค. ์ฆ, client์์๋ ์ฟ ๋ฆฌ๋ฅผ ์์ ํ ์ ์๋ค. XSS๊ณต๊ฒฉ์ ๋ง๋๋ฐ ๋์์ด ๋๋ค.
- signed: ์ฟ ํค์ ์๋ช
์ ํด์ `res.cookie`๊ฐ ์๋๋ผ `res.signedCookies`์์ ์ ๊ทผํ ์ ์๊ฒ ํ๋ค. ์๋ช
๋ ์ฟ ํค๊ฐ ๋ณ์กฐ๋๋ฉด ์๋ฒ๋ ๊ทธ ์ฟ ํค๋ฅผ ๊ฑฐ๋ถํ๊ณ ์๋ ๊ฐ์ผ๋ก ์ด๊ธฐํ ํ๋ค.
๋ํ, passport
๋ฅผ ์ด์ฉํด ์ธ์ฆํํธ๋ฅผ ๊ตฌํํ๋๋ฐ, GitHub Strategy
๋ฅผ ์ฌ์ฉํด์ ๋ค์๊ณผ ๊ฐ์ด ์ธ์ฆ์ ๊ตฌํํ๋ค. ์ฒ์์๋ passport
ํํ์ด์ง์ docs์ ๋น์ทํ๊ฒ ์์ฑํ์ง๋ง, ๋ค์ ์ฝ๋๋ ๋ด๊ฐ GitFarm
ํ๋ก์ ํธ์์ ์์ฑํ ๋ฐฑ์๋ ์ฝ๋์ด๋ค. ์ฝ๋๋ ์งง์ ๋ณด์ด์ง๋ง ๋์ ์๋น์ค์ ํ์ํ ์ ๋ณด์ ๋ง๊ฒ ์์ ํ๋๋ฐ ๊ทธ ์์
์ด ์๊ฐ๋ณด๋ค ์ค๋ ๊ฑธ๋ ธ๋ค.
// passport/strategy/GitHub.js
import GitHub from "passport-github2";
import keys from "../../config/keys.js";
import { User } from "../../model/index.js";
const GitHubStrategy = GitHub.Strategy;
const { clientID, clientSecret, callbackURL } = keys.GitHub;
const config = {
clientID,
clientSecret,
callbackURL,
};
export default new GitHubStrategy(
config,
async (accessToken, refreshToken, profile, done) => {
const { username } = profile;
const { id, avatar_url: avatarUrl } = profile._json;
const findUser = await User.findOne({ id });
if (!findUser) {
const newUser = new User({
id,
username,
avatarUrl,
accessToken,
});
newUser.save();
return done(null, newUser);
}
return done(null, findUser);
},
);
// routes/api/auth.js
router.get(
"/github",
passport.authenticate("github", {
scope: ["repo", "profile", "user"],
session: false,
}),
);
router.get(
"/github/callback",
passport.authenticate("github", {
session: false,
failureRedirect: "/api/auth/login/failed",
}),
async (req, res) => {
const { id, username } = req.user;
const payload = { id, username };
const token = await createToken(payload);
res.cookie("token", token, cookieConfig);
res.redirect("/loading");
},
);
โ๏ธ ๊ฒฐ๋ก
์ด ์ฑ
์ ์ฝ์ผ๋ฉฐ ์ต์ํ์ ๋ฐฑ์๋์์ ํ์ํ ์ฝ๋๋ฅผ ์์ฑํ๋๋ฐ ๋์์ ๋ง์ด ๋ฐ์๋ค. ์์ง๊น์ง ์ฐ๋ฆฌ๋๋ผ์์๋ Express.js
๋ณด๋ค Spring
์ ๋ ๋ง์ด ์ฌ์ฉํ์ง๋ง, ๋ฐฑ์๋์ ํฐ ํ์ ๋ฒ์ด๋์ง ์์ ๊ฒ์ด๋ค. JAVA
๋ณด๋ค JS
๋ฅผ ๋ ์ ์๋ฉด์ ๋ฐฑ์๋๋ฅผ ๋ง๋ณด๊ณ ์ถ์ ๋ถ๋ค์๊ฒ ์ถ์ฒํด์ฃผ๊ณ ์ถ์ ์ฑ
์ด๋ค.
reference
'๋ ์' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[ ๋ ํ๊ฐ ] TCP/IP ์ฝ๊ฒ, ๋ ์ฝ๊ฒ๋ฅผ ์ฝ๊ณ ... (0) | 2022.04.21 |
---|---|
[ ๋ ํ๊ฐ ] ๊ทธ๋ฆผ์ผ๋ก ๋ฐฐ์ฐ๋ Http & Network Basic์ ์ฝ๊ณ ... (0) | 2022.04.05 |
[ ๋ ํ๊ฐ ] ๋ฐ์ํ ๋์์ธ ํจํด๊ณผ ์๋ฆฌ๋ฅผ ์ฝ๊ณ ... (0) | 2021.11.09 |
[ ๋ ํ๊ฐ ] ๊ทธ๋ฆผ์ผ๋ก ์ดํดํ๋ AWS ๊ตฌ์กฐ์ ๊ธฐ์ ์ ์ฝ๊ณ ... (0) | 2021.11.02 |
[ ๋ ํ๊ฐ ] HTML5 & CSS3๋ฅผ ์ฝ๊ณ .. (0) | 2021.10.12 |
๋๊ธ