Node.js

App - 출력정보에 대한 보안

수업소개

출력정보에서 발생할 수 있는 보안적인 이슈를 살펴보겠습니다. 

 

 

 

강의 1

 

 

 

강의2

 

 

강의3

 

 

 

소스코드

main.js (변경사항)

var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');
var template = require('./lib/template.js');
var path = require('path');
var sanitizeHtml = require('sanitize-html');

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']
            });
            var list = template.list(filelist);
            var html = template.HTML(sanitizedTitle, list,
              `<h2>${sanitizedTitle}</h2>${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 title = post.title;
          var description = post.description;
          fs.rename(`data/${id}`, `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);

 

댓글

댓글 본문
  1. DotGaBi95
    npm으로 sanitize-html 설치하기 전에 pm2에서 main.js 실행시킨 상태면 pm2에서 main.js 재실행 하심 될겁니다.
    pm2 stop main.js
    pm2 start main.js
    아니면 pm2 restart main.js
    이거로도 안되시면
    pm2 save
    pm2 kill
    pm2 resurrect 해보세요!
    저는 그렇게 했더니 되더라구요. sanitize-html 문제가 아니라 pm2 문제인 것 같아요.
    대화보기
    • 화려하게간다
      아닌 나는 왜 안되는거냐고~~~~~~~~~~~~~
    • security for input and output
    • 케굴
      2020-12-26
    • 야옹스
      20211010 Sanitized
    • 졸작완성하자
      211009 완료
    • labis98
      20210730 GOOD!!!
    • 2021.07.18
    • Jeong Il Haan
      20210423
    • byoonn
      완료
    • chimhyangmoo
      21.02.27
    • jeisyoon
      2021.02.12 App - 출력 정보에 대한 보안 완료
    • 마아앙
      2021.02.10
    • 박소연
      alert태그는 지워지는데 h1이 지워지지 않고 태그가 먹히길래 찾아보니까 지금은 모듈의 디폴트 옵션이 allowedTags에 h1~h6이 전부 들어있기 때문이었어요. 혹시 저처럼 이게 왜 먹히지 하시는분 있을까봐 적어둬요.
    • 손민철
      21/1/1 완료
    • 생활둘기
      2020 12 27
    • kkn1125
      20.12.23 완료~!
    • Yong Hyun Lee
      섬뜩하고 재밌네요!
      완료 201002
    • 박병진
      완료
    • minimal
      update시에는 왜 sanitize를 안해도 되는지 궁금합니다.
    • Jenny Song
      10th.AUG.2020 완료
    • Amousk
      좋은 강의 감사합니다.
    • Katherine Roh
      완료 :)
    • 준바이
      감사합니다
    • 03.12 완료
    • eddylee123456
      복습
    • eddylee123456
      완료
    • 스티븐잡숴
      완료
    • 스티븐잡숴
      완료
    • import.위드
      감사합니다.
      데이터 생성,수정,삭제 + 보안의 내용을 정리해보았습니다.
      공부하시는분들 참고가 되셨으면 좋겠습니다 ^^
      https://blog.naver.com......285
    • 임은정
      완료
    • codinginpain
      완료쓰
    • 강다리
      재밌네요
    • 쑤우
      수강완료. 감사합니다~
    • 굼벵이
      완료
    • CronEB
      완료
    • youngjin.lee
      completed
    • 허공
      190510 감사합니다.
    • 위준우
      완료
    • devs
      저도 이런 오류 났었는데 form action = "/create_process" 부분이나 pathname === '/create'에 '/' 를 빼먹어서 생긴 오류였어요!
      대화보기
      • 홈에서 create 누르면 작성 화면으로 가지 않고 사이트 연결 할 수없다는 오류만 뜹니다.
        not found, undefind 도 안뜨고 구글 오류 메세지로 떠서 어디서 오류가 나는지도 찾을 수가 없습니다.
        어디서 오류가 나는지 아는 방법 없을까요? pm2 에서는 이렇게 출력 됩니다.

        16:53:03 0|main | TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be one of type string or Buffer. Received type object
        16:53:03 0|main | at ServerResponse.end (_http_outgoing.js:690:13)
        16:53:03 0|main | at C:\Users\kim\Desktop\project\main.js:71:15
        16:53:03 0|main | at FSReqWrap.oncomplete (fs.js:141:20)
      • ㄹㅈㅈ
        감사합니다
      • supernet
        감사합니다.
      • 권문수
        감사합니다.. 저도 똑같이 따라했는데 혼자 안되길래 뭔가했는데.. 치미님 말씀대로 하니까 잘되네요..;; 감사합니다 ㅎㅎ
        대화보기
        • 치미
          저도 같은 에러가 발생했어요
          cmd를 관리자 권한으로 실행해도 같은 오류가 발생하네요

          --
          작업관리자창에서 node관련 프로세스를 모두 종료 후 package.json을 삭제하고
          다시 설치 했더니 잘됩니다
          대화보기
          • Bong Song
            관리자 권한으로 설치하면 되지 않나요?
            대화보기
            • leesj020925@naver.com
              npm install -S sanitize-html
              인스톨 과정에서 에러가 발생하는게 경로중에 띄어쓰기가 포함된 디렉토리가 있으면 안되나요? 이고잉님과 마찬가지로 바탕화면에 nodejs 폴더를 생성하고 지금까지 강좌를 따라왔습니다.


              C:\Users\Stephen Lee\Desktop\nodejs>npm install -S sanitize-html
              npm WARN nodejs@1.0.0 No description
              npm WARN nodejs@1.0.0 No repository field.

              npm ERR! path C:\Users\Stephen Lee\Desktop\nodejs\node_modules\domutils
              npm ERR! code ENOENT
              npm ERR! errno -4058
              npm ERR! syscall rename
              npm ERR! enoent ENOENT: no such file or directory, rename 'C:\Users\Stephen Lee\Desktop\nodejs\node_modules\domutils' -> 'C:\Users\Stephen Lee\Desktop\nodejs\node_modules\.domutils.DELETE'
              npm ERR! enoent This is related to npm not being able to find a file.
              npm ERR! enoent

              npm ERR! A complete log of this run can be found in:
              npm ERR! C:\Users\Stephen Lee\AppData\Roaming\npm-cache\_logs\2018-11-28T10_13_00_967Z-debug.log

              보시기 번거롭겠지만 발생된 에러 부분입니다.
              아톰에서도 일부분만 설치됐습니다.
            • 일단시작하고본다
              크으으 감사합니다 이고잉님!!
            • jo_onc
              어쩌다보니 삽질 2시간만에 성공했습니다 하핳...
              강의 감사합니다^^
            • fed-gren
              말씀하신게 맞다고 생각되는게,

              출력정보에 대한 보안은
              사용자가 입력한 정보를 출력할 때 발생하는 문제에 대한 보안이라는 주제라고 이해했습니다.

              문제를 발생시키는 코드를 보면 html로 들어가는 부분에 사용자가 script 태그를 써서 자바스크립트로 동작시키면서
              그 정보를 입력한건 문제가 없으나 출력할 때 문제를 일으키죠.

              그래서 nomadlife님이 말씀하신대로, 표시할 때 sanitizing을 하는게 맞습니다. 저장된 정보에도 script태그는 남아있으니까요.:)
              대화보기
              graphittie 자세히 보기