SQL Injection
이름은 SQL Injection이지만 No SQL도 해당되는 이야기다. SQL Injection이란 사용자 input으로 데이터베이스 쿼리를 만들때 input에 SQL 구문을 작성하여 작성된 SQL 구문이 실제로 동작하게 되는 것을 말한다. express와 mongo 환경에서 이것을 막아보자.
npm i express-mongo-sanitize
위 패키지를 설치하고 아래 코드 처럼 미들웨어를 추가하면 된다.
const mongoSanitize = require('express-mongo-sanitize');
app.use(mongoSanitize());
Cross Site Scripting (XSS)
XSS는 클라이언트 측 스크립트가 웹 페이지에 삽입되는 것을 말한다. 아래의 예시를 보자.
캠핑장의 title은 h1 태그가 적용되지 않은 것을 볼 수 있다. title을 표시할 때 <%= %>를 사용하기 때문에 html escape가 발생하기 때문이다. 하지만 지도에 뜨는 팝업은 <%- %>으로 캠핑장 객체를 전달하기 때문에 html escape가 되지 않는다. 이제 input에 스크립트가 있으면 에러 메시지를 표시하게 해보자.
Joi 유효성 검사가 정의되어있는 schema.js를 아래 처럼 수정한다.
const BaseJoi = require('joi');
const sanitizeHtml = require('sanitize-html');
const extension = (joi) => ({
type: 'string',
base: joi.string(),
messages: {
'string.escapeHTML': '{{#label}} must not include HTML!'
},
rules: {
escapeHTML: {
validate(value, helpers) {
const clean = sanitizeHtml(value, {
allowedTags: [],
allowedAttributes: {},
});
if (clean !== value) return helpers.error('string.escapeHTML', { value })
return clean;
}
}
}
});
const Joi = BaseJoi.extend(extension);
module.exports.campgroundSchema = Joi.object({
campground: Joi.object({
title: Joi.string().required().escapeHTML(),
price: Joi.number().required().min(0),
//image: Joi.string(),
location: Joi.string().required().escapeHTML(),
description: Joi.string().escapeHTML()
}).required(),
deleteImages: Joi.array()
});
module.exports.reviewSchema = Joi.object({
review: Joi.object({
rating: Joi.number().required().min(0).max(5),
body: Joi.string().required().escapeHTML()
}).required()
})
스택 오류 숨기기
error.ejs를 다음과 같이 수정하면 개발 모드가 아닌 상태에서는 스택 추적 오류가 나타나지 않는다.
<div class="row mt-3">
<div class="col-6 offset-3">
<div class="alert alert-danger" role="alert">
<h4 class="alert-heading">
<%= err.message %>
</h4>
<% if (process.env.NODE_ENV !== "production") { %>
<br>
<p>
<%= err.stack %>
</p>
<% } %>
</div>
</div>
</div>
Helmet 사용하기
helmet은 정보보안을 위해 http header를 자동으로 설정해주는 패키지다. express 기반 앱에서 http reponse header을 설정하는 12개의 미들웨어가 모여져있다. 컨텐츠 보안, Adobe 제품의 크로스도메인 요청 처리, 브라우저 DNS prefetching 제어, 인증서 투명성 처리, 사이트 특징 제한, 클릭재킹 예방, 잠재적으로 위험한 정보 숨김, https만 허용, IE를 신뢰할 수 없는 html 열지 못하게 하기, referer 헤더 숨기기, xss 공격 보호가 있다.
먼저 설치를 한다.
npm i helmet
app.js 코드에 아래 코드를 추가한다. 명시된 url을 제외하고는 동작하지 않도록 한다.
const helmet = require('helmet');
app.use(helmet());
const scriptSrcUrls = [
"https://stackpath.bootstrapcdn.com/",
"https://api.tiles.mapbox.com/",
"https://api.mapbox.com/",
"https://kit.fontawesome.com/",
"https://cdnjs.cloudflare.com/",
"https://cdn.jsdelivr.net",
];
const styleSrcUrls = [
"https://kit-free.fontawesome.com/",
"https://stackpath.bootstrapcdn.com/",
"https://api.mapbox.com/",
"https://api.tiles.mapbox.com/",
"https://fonts.googleapis.com/",
"https://use.fontawesome.com/",
"https://cdn.jsdelivr.net"
];
const connectSrcUrls = [
"https://api.mapbox.com/",
"https://a.tiles.mapbox.com/",
"https://b.tiles.mapbox.com/",
"https://events.mapbox.com/",
];
const fontSrcUrls = [];
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: [],
connectSrc: ["'self'", ...connectSrcUrls],
scriptSrc: ["'unsafe-inline'", "'self'", ...scriptSrcUrls],
styleSrc: ["'self'", "'unsafe-inline'", ...styleSrcUrls],
workerSrc: ["'self'", "blob:"],
objectSrc: [],
imgSrc: [
"'self'",
"blob:",
"data:",
"https://res.cloudinary.com/cloudinary 이름/",
"https://images.unsplash.com/",
],
fontSrc: ["'self'", ...fontSrcUrls],
},
})
);
'웹 프로그래밍' 카테고리의 다른 글
[React] 프로젝트 관리 앱 (1) | 2024.01.26 |
---|---|
[React] Investment Calculator (0) | 2024.01.08 |
[Yelpcamp 프로젝트] 디자인 수정 (0) | 2023.12.10 |
[Yelpcamp 프로젝트] 클러스터 맵 (0) | 2023.12.09 |
[YelpCamp 프로젝트] 지도 추가 (1) | 2023.12.08 |