출력정보에 대한 보안
페이지에서 사용자가 업데이트나 수정을 하였을때 폼 값 자체를 <script></script> 태그와 같은 것으로 버그를 유발하며 출력 정보를 조작할 수 있다.
아래의 예처럼 <script>태그로 alert 경고창을 뜨게 하도록 할 수도 있다.
- 이러한 버그는 아주 기본적인 예시일 뿐이며 더 나아간다면 정보 탈취 등등 많은 심각한 보안 문제로 사건이 커질 수 있다.
- 이를 해결하기 위해서는 필터링 처리를 하는 일명 '소독'이 필요하다.
아래 사이트는 npm이라는 모듈의 정보를 서비스 제공하는 사이트이다. 여기서 HTML의 <sciprt>와 같은 태그들을 필터링하기 위한 모듈 서비스 중 하나인 "sanitize-html"의 모듈을 찾을 수 있다.
유의할 점은 npm 모듈을 모두 신뢰하면 안된다. 사이트에 들어가 다른 개발자 사용자들의 후기와 다운로드 비율을 확인하고 검증되었는지 확인하는 것이 중요하다.
https://www.npmjs.com/package/sanitize-html
사이트에 들어가면 아래와 같이 사용방법이 나와있다.
npm 모듈 실행 방법과 활용
명령 프롬프트에서 "npm init"을 입력하고 엔터를 여러 번 치면 적용하고자 하는 웹 정보들의 절차를 시작하게 된다.
엔터를 Is thos OK? (yes)가 나올때까지 치면 다시 명령어를 칠 수 있는데 이는 npm 모듈을 적용할 수 있는 절차가 끝났다는 것이다.
그 다음으로 명령어 칸에 "npm install -S sanitize-html"을 적어주고 다시 엔터를 눌러 실행 해주면 sanitize-html이라는 모듈을 다운 받아 적용받고자 하는 웹의 정보 파일 폴더인 nodejs에 모듈의 내용 파일들이 저장된다.
아래와 같이 모듈 파일들이 적용된 것을 확인 할 수 있다. 저 수 많은 모듈 파일들은 sanitize-html을 실행시키기 위한 여러가지의 복잡한 의존파일들이다. 이 많은 것들을 npm 모듈이 해주는 것이다.
자세히 찾아보면 모듈 파일 폴더 목록에 sanitize-html이 들어있고 package.json 파일에서 "sanitize-html"버전을 의존하여 사용하고 있다는 것을 확인할 수있다.
이제 아래와 같이 코드를 수정하면 된다.
var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');
var template = require('./data/muse.js');
var path = require('path');
var sanitizeHtml = require('sanitize-html');
//npm 모듈인 'sanitize-html'을 불러와 변수 sanitizeHtml로 선언해준다.
var app = http.createServer(function(request,response){
var _url = request.url;
var queryData = url.parse(_url, true).query;
var pathname = url.parse(_url, true).pathname;
if(pathname === '/'){
if(queryData.id === undefined){
fs.readdir('./data', function(error, filelist){
var title = 'Welcome';
var description = 'Hello, Node.js';
var list = template.list(filelist);
var html = template.HTML(title, list,
`<h2>${title}</h2>${description}`,
`<a href="/create">create</a>`
);
response.writeHead(200);
response.end(html);
});
} else {
fs.readdir('./data', function(error, filelist){
var filteredId = path.parse(queryData.id).base;
fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
var title = queryData.id;
var sanitizedTitle = sanitizeHtml(title);
var sanitizedDescription = sanitizeHtml(description, {
allowedTags:['h1']
//sanitizeHtml 변수 메소드의 두 번째 인자는 태그 중에 허용할 수 있는 태그를 설정할 수 있다.
});
//위와 같이 npm 모듈이 들어가 있는 변수 sanitizeHtml을 이용하여 title과 description
//내용을 <sciprt>와 같은 태그로 제어하는 버그를 막아주고 필터링하여 소독한다고 말할 수 있다.
var list = template.list(filelist);
var html = template.HTML(title, list,
`<h2>${sanitizedTitle}</h2>${sanitizedDescription}`,
//(title, description부분들 모두 sanitizedTitle, sanitizedDescription로 각각 수정.
` <a href="/create">create</a>
<a href="/update?id=${sanitizedTitle}">update</a>
<form action="delete_process" method="post">
<input type="hidden" name="id" value="${sanitizedTitle}">
<input type="submit" value="delete">
</form>`
);
response.writeHead(200);
response.end(html);
});
});
}
} else if(pathname === '/create'){
fs.readdir('./data', function(error, filelist){
var title = 'WEB - create';
var list = template.list(filelist);
var html = template.HTML(title, list, `
<form action="/create_process" method="post">
<p><input type="text" name="title" placeholder="title"></p>
<p>
<textarea name="description" placeholder="description"></textarea>
</p>
<p>
<input type="submit">
</p>
</form>
`, '');
response.writeHead(200);
response.end(html);
});
} else if(pathname === '/create_process'){
var body = '';
request.on('data', function(data){
body = body + data;
});
request.on('end', function(){
var post = qs.parse(body);
var title = post.title;
var description = post.description;
fs.writeFile(`data/${title}`, description, 'utf8', function(err){
response.writeHead(302, {Location: `/?id=${title}`});
response.end();
})
});
} else if(pathname === '/update'){
fs.readdir('./data', function(error, filelist){
var filteredId = path.parse(queryData.id).base;
fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
var title = queryData.id;
var list = template.list(filelist);
var html = template.HTML(title, list,
`
<form action="/update_process" method="post">
<input type="hidden" name="id" value="${title}">
<p><input type="text" name="title" placeholder="title" value="${title}"></p>
<p>
<textarea name="description" placeholder="description">${description}</textarea>
</p>
<p>
<input type="submit">
</p>
</form>
`,
`<a href="/create">create</a> <a href="/update?id=${title}">update</a>`
);
response.writeHead(200);
response.end(html);
});
});
} else if(pathname === '/update_process'){
var body = '';
request.on('data', function(data){
body = body + data;
});
request.on('end', function(){
var post = qs.parse(body);
var id = post.id;
var filteredId = path.parse(id).base;
var title = post.title;
var description = post.description;
fs.rename(`data/${filteredId}`, `data/${title}`, function(error){
fs.writeFile(`data/${title}`, description, 'utf8', function(err){
response.writeHead(302, {Location: `/?id=${title}`});
response.end();
})
});
});
} else if(pathname === '/delete_process'){
var body = '';
request.on('data', function(data){
body = body + data;
});
request.on('end', function(){
var post = qs.parse(body);
var id = post.id;
var filteredId = path.parse(id).base;
fs.unlink(`data/${filteredId}`, function(error){
response.writeHead(302, {Location: `/`});
response.end();
})
});
} else {
response.writeHead(404);
response.end('Not found');
}
});
app.listen(3000);
'프로그래밍 개발 > NodeJs' 카테고리의 다른 글
Node.js and Mysql - My SQL join을 이용해서 구현하기 (0) | 2021.01.11 |
---|---|
Node.js and Mysql - Node.js에 My SQL 구현하기 (0) | 2021.01.11 |
Node.js - 입력정보에 대한 보안 (0) | 2020.12.26 |
Node.js - 기본적인 CRUD APP 기능들 구현하기 (0) | 2020.12.19 |
Node.js - Node.js에서 동기와 비동기 (0) | 2020.12.12 |
댓글