반응형

배경

계절학기에 들어가면서 1학점 짜리 웹 프로젝트 연구를 진행하게 되었다. 주제는 웹 보안을 위한 시큐어 코딩 학습 사이트다.

3주 동안 진행되는 계절학기 특성상 미리 준비하는게 정신건강에 좋기 때문에 미리 웹사이트를 구축해보기로 했다.

 

새로운 기술

우선, 평소에는 react, nodejs 로 웹을 구축했었는데 이번에는 nextjs 를 이용해 구축해보려고 한다. 새로운 기술에 대해 배우는고 공부하는데 도움이 될 것 같아 이렇게 진행하려고 한다.

 

취약점 조사

프로젝트에는 웹보안 하면 가장 기초가되는 4가지 공격을 제외한 공격을 다루라고 명시되어 있다. (sql injection, XSS, path traversal, desdrialization)

사실 내가 생각해도 위의 공격은 너무 소스도 많고 기본적인 문제들이라 날로 먹는 느낌이 들 것 같긴했다.

그렇기에 새로운 취약점을 찾아보았고, OWASP 에서 발표한 TOP10 취약점을 알게 되었다.

 

 

여기서 나는 1번 injection, 8번 CSRF 에 대해 진행해보려고 한다. injection 에도 file upload, os command 를 이용한 취약점에 집중하려고 한다.

 

웹 구현

 

next 프로젝트를 구축한 후 app 폴더의 트리 모습이다. layout.js 를 이용해 헤더와 네비게이션을 고정해놓고 page를 바꾸어가며 출력할 예정이다.

 

app
│ favicon.ico
│ globals.css
│ layout.js
│ page.js

├─components
│ Header.js
│ Nav.js

├─csrf
│ page.js

├─file
│ page.js

├─list
│ page.js

└─os

 

헤더와 네비게이션을 고정하기 위해 다음과 같은 코드를 작성했다.

 

layout.js

import Link from "next/link";
import "./globals.css";
import { Inter } from "next/font/google";
import Nav from "./components/Nav";
import Header from "./components/Header";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Header/>
        <Nav />
        {children}
      </body>
    </html>
  );
}

Header.js

'use client';
const { default: Link } = require("next/link");

const Header = () =>{
  const toggleDropdown = () => {
    setDropdownVisible(!isDropdownVisible);
  };
    return(
        <div className="header">
            <h3>Secure Coding Lecture</h3>
        </div>
    )
}

export default Header;

Nav.js

'use client';
import { useState } from "react";
const { default: Link } = require("next/link");

const Nav = () =>{
    const [isDropdownVisible, setDropdownVisible] = useState(false);

  const toggleDropdown = () => {
    setDropdownVisible(!isDropdownVisible);
  };
    return(
        <nav className="navbar">
          <ul className="navList">
            <li className="navItem">
              <Link href="/">홈</Link>
            </li>
            <li className="navItem">
              <div onClick={toggleDropdown}>강의
              {isDropdownVisible && (
                <ul className="subNavList">
                  <li className="navItem">
                    <Link href="/file">File Upload Attack</Link>
                  </li>
                  <li className="navItem">
                    <Link href="/os">OS Command Injection</Link>
                  </li>
                  <li className="navItem">
                    <Link href="/csrf">CSRF</Link>
                  </li>
                </ul>
              )}
              </div>
            </li>
            <li className="navItem">
              <Link href="/">설정</Link>
            </li>
          </ul>
        </nav>
    )
}

export default Nav;

위의 코드를 이용하면 다음과 같은 웹이 출력된다.

 

 

 

어려웠던점

  1. Layout.js 내에서 useState 사용불가
    • 이건 내가 next 에 대해 제대로 몰라 생겼던 문제다. next 는 기본적으로 서버 컴포넌트로 작동하는데 useState 는 클라이언트에서만 사용되기에 오류가 발생한다.
    • 따라서, use client 를 최상단에 적어 클라이언트 임을 선언하면 정상작동 된다.
반응형
반응형

NodeJS 로 채팅 서비스 만들기

시스템 소프트 웨어 강의를 배우면서 리눅스를 이용한 c 코드 C - S 를 만들어보니 재미가 있어 NodeJS 로 구현해 보기로 했다.

위의 링크를 통해 배우고 구현해 보기로 했다.

필요 모듈

const fs = require('fs');
// express module
const express = require('express');
// socket module
const socket = require('socket.io');
// html module
const http = require('http');

NodeJS 기본 모듈을 제외하면 express, socket.io 모듈이 추가로 필요하다.

Socket.io module

Socket.io 에 대한 함수를 알아보자

  • socket.on(’event’, Callback func) : 해당 이벤트를 받고 콜백함수를 실행
  • socket.emit(’event’, Data) : 이벤트 명을 지정하고 데이터 보냄
    • event 종류
      • connection : client 와 연결시 발생
      • disconnection : client 와 연결해제되었을 때 발생

Socket 은 객체 io 를 생성한다.

const io = socket(server)

생성된 io 를 이용해 데이터를 주고 받는 함수를 만들 수 있다.

main.js 에 만든 이벤트 함수들은 총

  • newUser
  • message
  • disconnect

이며 이를 코드로 표현하면

io.sockets.on('connection', function(socket){

    socket.on('newUser', function(name){
        socket.name = name
        // newUser 이벤트로 가져온 name 을 update 이벤트로 데이터 전송
        io.sockets.emit('update', {type : 'connect', name:'SERVER', message: name + 'was connected'})
    })

    socket.on('message', function(data){
        data.name = socket.name
       // message 이벤트로 가져온 data 를 다른 client 에게 update 할 데이터 전송
        socket.broadcast.emit('update', data)
    })

    socket.on('disconnect', function(){
        socket.broadcast.emit('update', {type : 'disconnect', name:"SERVER", message : socket.name + 'Disconnected'})
    })
})

라고 표현할 수 있다.

홈페이지에 접속하면 사용자의 이름을 받는다.

socket.on('connect', function(){
    var name = prompt('Welcome', '')

    if(!name){
        name = 'Annonymous'
    }
    socket.emit('newUser', name)
})

prompt 를 이용해 이름을 입력받아 emit 하여 newUser를 실행한다.

이어 input 박스에 적은 메시지를 채팅창에 표현해보려고 한다.

반응형

'Web > NodeJS' 카테고리의 다른 글

[NodeJS] 1.DB연동  (0) 2022.01.29
반응형

HTTP module

var http  = require('http');
//http module 불러오기

var url = require('url');
// url module 불러오기

http.createServer(function(request,response){
    // http module 을 이용하여 서버 생성

    var pathname = url.parse(request.url).pathname;
    //url 뒤에 있는 디렉토리 / 파일 이름 파싱

    if(pathname=="/"{// pathname 이 비어있다면 index를 디폴트로
        pathname="/index.html";    
    }
}

 

콜백함수를 사용해 response 이벤트가 감지되면 데이터를 데이터에 받아온다.

 

var callback = function(response){
    var body='';
    response.on('data',function(data){
        body += data;    
    };
}

Mysql module

NodeJS 에서 DB 연동을 해보려고 한다.

 

const express = require('express')
const app = express();

 

express 를 불러와 app 에 할당한다.

 

var mysql = require('mysql');
var pool = mysql.createPool({
    connectionLimit : 10,
    host :"localhost",
    user : "root",
    password : "0000",
    database : "moviestar"
})

 

require(’mysql’) 은 mysql 모듈을 사용하겠다라는 뜻.

mysql 을 실행하기 위한 pool 을 생성한다.

 

app.get('/db',function(req,res){
    pool.getConnection(function(err, connection){

        if(err) throw err;

        connection.query('select * from user', function(error,results, fields){
            res.send(JSON.stringify(results));
            console.log('results', results);
            connection.release();

            if(error) throw error;
        })
    })
})

 

생성된 pool 을 mysql 과 연결한다.

query 함수를 이용하여 mysql 에 명령을 전달한다.

sql에서 데이터 request 가 온다면 아래와 같이 불러올 수 있다.

 

request.on('end', function(){
          var post = qs.parse(body);
          var title = post.title;
          var description = post.description;

          db.query(`insert into topic (title, description, created, author_id) 
          values (?, ?, NOW(), ?)`,
          [post.title, post.description, 1],
          function(error, result){
            if(error){
              throw error;
            }
            response.writeHead(302, {Location: `/?id=${result.insertId}`});
            response.end();
          });
      });
반응형

'Web > NodeJS' 카테고리의 다른 글

[NodeJS] Chatting Service -1-  (0) 2022.02.06

+ Recent posts