Node-js & MySql

기존에 사용자가 생성한 동적 콘텐츠를 파일로 저장해서 관리하면서 프로젝트를 진행했다.

하지만, 이런식으로 파일을 통한 저장하는 방식은 매우 비효율적이며, 보안에 취약하다.

파일의 개수가 늘어남에 따라, 사용자가 원하는 파일에 접근하는 데 걸리는 시간이 늘어나고, 제한된 기능만 제공할 수 있다.

이러한 파일 저장방식의 문제점을 해결하기 위해 DB를 이용하게 된다. DB를 이용해 데이터를 저장함으로써, Performance을 극대화 할 수 있으며, SQL을 통한 다양한 쿼리를 통해 사용자의 요구조건을 충족 시킬 수 있다.

Node.js mysql module

MySQL에 접속 및 MySQL DB을 조작하기 위해 Node.js의 mysql 모듈을 활용

Installation

npm install -S mysql

package.json

"dependencies": {
    "mysql": "^2.18.1",
    "sanitize-html": "^2.7.0"
  }

설치를 하면 위 처럼 dependency가 등록되는 것을 확인 할 수 있다.

Connection

const mysql=require('mysql');
const connection=mysql.createConnection({
    host:'localhost',
    user:'root',
    password:'******',
    database:'******'
})

connection.connect();

Results

Debugger attached.

와 함께 connection이 정상적으로 동작함을 확인할 수 있다.

Connection Errors

Client does not support authentication protocol requested by server 위와 같은 에러로 DB 연결이 안되는 경우 MYSQL에 아래의 코드를 실행해서 password authentication protocol을 변경해준다.

-- mysql_native_password 사용하도록 변경
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourRootPassword';

SQL Queries

const connection=mysql.createConnection({
    host:'localhost',
    user:'root',
    password:'******',
    database:'******'
})
connection.connect()
connection.query("SQL",[parameters],(err,results)=>{

})

connection 객체의 query function을 이용해 sql을 통한 DB에 query하는 것이 가능하다. query가 성공적으로 이루어지면 results에 값이 담기고, 실패하면 err 객체에 에러가 전달된다.

Example of results

[
RowDataPacket {
  id: 1,
  title: 'MySQL',
  description: 'MySQL is...',
  created: 2018-01-01T03:10:11.000Z,
  author_id: 1
},
RowDataPacket {
  id: 2,
  title: 'Oracle',
  description: 'Oracle is ...',
  created: 2018-01-03T04:01:10.000Z,
  author_id: 1
},
RowDataPacket {
  id: 3,
  title: 'SQL Server',
  description: 'SQL Server is ...',
  created: 2018-01-20T02:01:10.000Z,
  author_id: 2
},
RowDataPacket {
  id: 4,
  title: 'PostgreSQL',
  description: 'PostgreSQL is ...',
  created: 2018-01-22T16:03:03.000Z,
  author_id: 3
},
RowDataPacket {
  id: 5,
  title: 'MongoDB',
  description: 'MongoDB is ...',
  created: 2018-01-30T03:31:03.000Z,
  author_id: 1
}
]

다음과 같이 배열에 sql의 결과물이 담긴다.

이처럼 DB 관련 부분은 위와 같이 Connection 연결만 잘 되면, 나머지는 SQL query문을 통한 수정을 구현하면 된다.

SQL Injections

만약 MySQL에 쿼리를 보낼때 아래와 같이 parameter 방식이 아닌 sql 자체로 쿼리를 보내게 되면 어떻게 될까?

connection.query(`DELETE FROM TOPIC WHERE ID=${id}`,(error,results)=>{
    ...
})

쿼리에 포함되는 id 값은 사용자로 부터 입력받는 id 값이다. 그런데, 악의적인 사용자가 id를 통해 SQL 문을 입력하게 되면 해당 SQL 문은 실행되게 된다.

/delete?id=1;DROP TABLE TOPIC;

예를 들어 위와 같은 요청을 했다고 가정하면

DELETE FROM TOPIC WHERE ID=1;
DROP TABLE TOPIC;

위 처럼 2개의 sql문이 실행되게 된다. 이러한 sql injection 문제를 방지하기 위해서 parameter 형식으로 query문을 설계하면 된다.

connection.query(`DELETE FROM TOPIC WHERE ID=?`,[id],(error,results)=>{
    ...
})

/delete?id=1;DROP TABLE TOPIC;

DELETE FROM TOPIC WHERE ID='1;DROP TABLE TOPIC';

와 같이 실행되면서 SQL문 자체가 실행이 되지 않는다.

References

link: node.js

link: node.js doc

댓글남기기