2023. 1. 30. 15:33ㆍWeb 개발
실습 환경
Node.js란?
Node.js는 확장성 있는 네트워크 애플리케이션(특히 서버 사이드) 개발에 사용되는 소프트웨어 플랫폼
( Chrome V8 Javascript 엔진으로 빌드된 Javascript 런타임)
< 장점 >
- 고성능 네트워크 서버
- 단일 쓰레드(Single Thread) 이벤트 루프(Event Loop) 기반 // 높은 처리 성능
- 비동기 I/O 처리(Non-Blocking I/O) // 서버 무리 적음
- 자바스크립트 // 서버단 로직 처리 가능
- 개발 생산성 향상
- 방대한 모듈 제공(NPM)
< 단점 >
- 이벤트 기반 비동기방식이라 서버단 로직이 복잡한 경우 콜백함수의 늪에 빠질 수 있음
- 순차적 코드 실행이 아닌 비동기 방식으로 이벤트를 보내고, 응답이 오면 처리하는 방식 따라서, java 개발을 했던 방식으로 설계, 프로그래밍하면 큰 문제가 발생
- 단일 쓰레드이기 때문에 하나의 작업 자체가 많이 걸리는 웹서비스에는 어울리지 않음
게시판형태와 같이 가벼운 I/O가 많은 웹서비스에 어울림
- 코드가 수행시 코드 에러를 알 수 있으며, 에러 있을 경우 프로세스가 내려가기 때문에 테스트가 엄청 중요 반드시 모든 케이스에 대해 소스코드를 검증해야 한다.
Node.js 가 어울리는 웹서비스
- 간단한 로직.
- 대용량(동시에 여러 request를 처리)
- 빠른 응답시간 요구
- 빠른 개발 요구
- 비동기방식에 어울리는 서비스(네트워크 스트리밍 서비스, 채팅 서비스 등)
Node.js 가 어울리지 않는 웹서비스
- 단일 처리가 오래 걸리는 경우 : 싱글 쓰레드이기 때문
- 서버 체크로직이 많은 경우 : 비동기방식이기 때문에 CallBack Hell에 빠지지 않기 위해
- 업무 복잡도/난이도가 높은 경우 : 에러가 나면 서버가 죽기 때문에 코드 품질 중요
MySQL 설치
VSCode / Node.js / MySQL / Express 모듈 설치
에디터 프로그램인 VSCode에서 코드를 작성하기에 앞서, 웹 서버 제작에 필요한 모듈을 설치해야한다
init 를 설치하기 위해 express-mysql-example이름으로 폴더를 만들고
폴더 안으로 들어가 npm init 로 설치를 진행하였다
mkdir express-mysql-example
cd express-mysql-example
npm init --yes
이때, npm은 Node Package Manager의 약자로 node.js에서 사용하는 모듈들을 패키지로 만들어 관리하고 배포하는 역할을 합니다 (npm을 통해서 모듈도 설치)
※ npm init를 하는 이유는?
package.json을 생성하여 Node 패키지에 관한 정보와 의존중인 버전에 관한 정보로
node.js에서 사용하는 모듈들을 패키지로 만들어 관리하고 배포하기 위해서
npm install express mysql
- > express, mysql 모듈을 npm으로 설치
- Express
: Node.js에서 웹 어플리케이션 혹은 API 서버를구축하는데 가장 많이 사용되는 대표적인 프레임워크이며
서버를 만들고, 데이터베이스와 연결하고 어플리케이션을 구동하는 등의 작업을 진행하도록 돕는 모듈
- Mysql
: 전세계적으로 가장 널리 사용되고 있는 오픈 소스 데이터베이스
Web 서버 작동
웹 서버를 작동하기 위해 express 모듈이 필요하다
Node.js에서는 require 매서드를 통해 외부 모듈을 가져 올 수 있기에 이를 이용하였다
const express = require('express'); //express 모듈 가져옴
const app = express();
app.set('port', process.env.PORT || 3000); // 웹 서버 포트 지정
app.get('/', (req, res) => { // 웹 서버의 메인 페이지에 html파일 연동
res.sendFile(__dirname + '/web.html');
});
app.listen(app.get('port'), () => {
console.log('Express server listening on port ' + app.get('port'));
});
// 웹 서버 실행
터미널에 node index.js 입력 후
http://localhost:3000 주소로 접속하면 Node.js 서버가 실행됨을 확인 가능
'/'가 localhost를 의미
Web 서버 HTML 작성
<body>
<div class="login_box">
<div class="Login">
<h1>Login</h1>
</div>
<div class="id">
<h3>
<form action="/" id="idpw" method="POST">
아이디 : <input type="text" name="id" ><br>
패스워드 : <input type="text" name="pw" ><br>
<button type="submit" id="send">ok</button>
</form>
</h3>
</div>
</div>
</body>
위와 같이 웹서버를 열었을 때 작성한대로 잘 보이는것을 확인하였다
Test DB 생성
웹 서버와 연결할 Test DB 생성을위해 MySQL에 접속하고
web_db라는 이름의 데이터베이스를 만들어준다
show databases; 로 db가 만들어진것을 확인하고,
방금 만든 web_db를 사용한다고 명령한 다음
web_db안에 web이라는 테이블을 생성해준다
칼럼은 id와 pwd로 각각 최대 20 byte크기의 문자를 받을 수 있게 설정해주었다
테이블에 값이 잘 들어가는지 확인을 위해, web테이블의 id, pwd칼럼에 각각 test문자를 insert 해주었고

테이블을 조회 하였을 때 다음과 같이 잘 저장된 것을 확인하였다
Node.js 와 MySQL 연동
const mysql = require('mysql'); // mysql 모듈 가져옴
const connection = mysql.createConnection({ // DB정보 connection함수로 선언
host : 'localhost', // 호스트 이름
port : '3306', // mysql 사용 포트
user : 'root', // mysql user 이름
password : 'root', // mysql user의 패스워드
database : 'web_db' // 연동 할 DB 이름
});
require 매서드로 mysql 모듈을 가져왔으며
DB 연동 확인
이제 DB와 잘 연동 되었는지 확인해야한다
로그인 폼(body의 input 부분)에서 값을 입력하면 js에서 그 값을 받아와야한다
http모듈로만 body값을 가져오려면
req.on('data', function(chunk) { body += chunk; });와 같은 이벤트를 등록해야한다
이는 번거롭기때문에
body-parser모듈을 사용하여 간단하게 값을 가져올 것이다
const bodyParser = require('body-parser'); // bodyParser 모듈 가져옴
app.use("/", express.static(__dirname + "/css")); // css 파일 연동
app.use(bodyParser.urlencoded({ extends: true }))
app.get('/', (req, res) => { // html 파일 연동
res.sendFile(__dirname + '/web.html');
});
extends : true 는 중첩된 객체표현을 허용
false 는 허용 x
다음으로는,
connection.query를 통해 db에 접속하여 해당 쿼리문을 실행시켜
테이블에 값을 넣고 db를 출력하는 명령을 보내는 코드를 작성하였다
app.post('/', (req, res) => {
let a = req.body.id; //html의 name인 id, pw값을 js로 가져와서 선언
let b = req.body.pw;
connection.query('insert into web(id, pwd) values (' + connection.escape(a)+ ','+ connection.escape(b) +');', function(err){
if(err){
console.log(err);
}
}) //web 테이블의 id, pwd칼럼에 a,b의 값을 INSERT하는 쿼리문 실행
testQuery = "SELECT * FROM Web";
connection.query(testQuery, function (err, results, fields) { // testQuery 실행
if (err) {
console.log(err);
}
console.log(results);
}); //콘솔로그에서 DB 조회 (INSERT 확인)
connection.end();
});
그리고 node.js로 웹 서버를 실행한 뒤,
웹 서버 페이지에서 id, pw에 각각 1234라는 값을 넣고 보내었을 때
다음과 같이 콘솔로그에서 DB가 조회되어 값이 잘 들어갔는지 확인 가능하다
SQL injection 공격 실습
DB 조회하였을 때 테이블이 존재하는 것을 확인하였다
그리고 SQL injection을 하기에 앞서
SELECT문을 사용하여 데이터를 조회하는 기능을 가진 ID search창을 만들어주었다
<index.html>
<div class="ms">
<h1>ID search</h1>
<h3>
<form action="/mo" id="movie" method="POST"> //id검색시 /mo페이지로 넘어가 결과 출력
아이디 검색 : <input type="text" name="search" ><br>
<button type="submit" id="msend">검색</button>
</form>
</h3>
</div>
<index.js>
app.post('/mo', (req, res) => {
data = req.body.search;
testQuery = `SELECT * FROM web where id='${data}'`;
connection.query( testQuery, (error, rows) => {
if (error) throw error;
console.log('id info is: ', rows);
res.send(rows);
});
});
위의 코드를 통해 만든 웹서버 화면이다 (나는 기존 id, pw 입력 bar 밑에 새로 추가한 것이다)
DB에 들어가 있던 id인 aaa를 입력하였을 때
/mo 페이지로 넘어가 내가 입력한 아이디와 그 아이디의 비밀번호를 출력하는 기능을 만들었다
여기에 '; DROP TABLE web; '-- 을 입력하여 테이블 삭제 인젝션 공격을 하였다
다시 DB 확인을 해보았을 때
테이블이 사라졌으며 DROP TABLE 인젝션 공격이 성공한것을 알 수 있다
'; DROP TABLE web; '-- 을 넣은 이유는?
내가 실행 시키고 싶은 SQL injection구문은 DROP TABLE web;이다
하지만, 정상적으로 코드를 실행했을 때 SELECT * FROM web where id=' 뒤에 내가 검색한 id가 들어간다
이때, SELECT 구문 뒤에 id='로 끝나는데 원래 id를 검색하면
서버에서 자동으로 id='내가 검색한 id값';으로 문장을 마무리하고 실행시킨다
그래서 어떠한 공격 코드를 넣어도 문자 값으로 받을 뿐이다
따라서 문장을 강제로 마무리시키고 SQL injection코드를 넣어야한다 그래서 '; DROP TABLE web;을 넣었으며
뒤의 '--은 뒤에 오는 코드들을 모두 주석 처리시키는 것이다
주석 처리 시키는 이유는 뒷 코드에서 검증로직이 있다면 SQL구문 실행에 영향을 끼칠 수 있기 때문이다
/*
전체 코드
< index.html >
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Min Song Ha</title>
<link rel="stylesheet" href="http://localhost:3000/web.css">
</head>
<body>
<div class="login_box">
<div class="Login">
<h1>Login</h1>
</div>
<div class="id">
<h3>
<form action="/" id="idpw" method="POST">
아이디 : <input type="text" name="id" ><br>
패스워드 : <input type="text" name="pw" ><br>
<button type="submit" id="send">ok</button>
</form>
</h3>
</div>
<div class="ms">
<h1>ID search</h1>
<h3>
<form action="/mo" id="movie" method="POST">
아이디 검색 : <input type="text" name="search" ><br>
<button type="submit" id="msend">검색</button>
</form>
</h3>
</div>
</div>
</body>
</html>
< index.js >
const express = require('express');
const mysql = require('mysql');
const bodyParser = require('body-parser');
const app = express();
const connection = mysql.createConnection({
host : 'localhost',
port : '3306',
user : 'root',
password : 'root',
database : 'web_db',
multipleStatements: true
});
// configuration =========================
app.set('port', process.env.PORT || 3000);
app.use("/", express.static(__dirname + "/css"));
app.use(bodyParser.urlencoded({ extends: true }))
app.get('/', (req, res) => {
res.sendFile(__dirname + '/web.html');
});
app.listen(app.get('port'), () => {
console.log('Express server listening on port ' + app.get('port'));
});
app.post('/', (req, res) => {
let a = req.body.id;
let b = req.body.pw;
var params = [a,b];
connection.query(`insert into web(id, pwd) values ('${a}','${b}');`, function(err){
if(err){
console.log(err);
}
})
testQuery = "SELECT * FROM Web";
connection.query(testQuery, function (err, results, fields) { // testQuery 실행
if (err) {
console.log(err);
}
console.log(results);
});
});
app.post('/mo', (req, res) => {
data = req.body.search;
testQuery = `SELECT * FROM web where id='${data}'`;
connection.query( testQuery, (error, rows) => {
if (error) throw error;
console.log('id info is: ', rows);
res.send(rows);
});
});
/* app.get('/web', (req, res) => {
connection.query('SELECT * from web', (error, rows) => {
if (error) throw error;
console.log('web info is: ', rows);
res.send(rows);
});
});
*/
*/
'Web 개발' 카테고리의 다른 글
로그인 & 회원가입 (Node.js + DB연동) (0) | 2023.07.20 |
---|---|
Selenium을 이용한 Web 크롤링 개발 (0) | 2023.07.02 |
CSS (0) | 2023.02.03 |
JavaScript (자바스크립트) (0) | 2023.01.25 |
HTML 태그 (0) | 2023.01.25 |