IT's Jenna

Injection attak 본문

Backend/Backend 기본

Injection attak

developer Jenna 2021. 1. 23. 20:49

Injection attack이란?

  • 외부에서 서버에 쿼리문을 보내, 데이터 베이스를 추출하거나 임의로 조작하는 행위

Injection attact 사례

router.get('/', function(req, res, next) {
  console.log('query : ', req.query)

  let {idx, name} = req.query
  console.log('idx : ', idx, 'name :', name 'idx type : ', typeof idx) 
  // idx :  1 name : asdf idx type :  string
  
  let sql
  sql = 'SELECT * FROM Goods WHERE idx = "'+idx+'"'
  pool.query(sql, function(error, results, fields) { 
    if (error) throw error;
    console.log('results : ', results)
    console.log("sql : ", sql)
  })
});

위와 같이 get method를 통해 client에서 데이터를 요청하면 sql의 Goods테이블에서 요청한 값들을 내보내는 스크립트를 하나 만들었다.

 

<코드 분석>

1. req.query

req.query 문을 통해 데이터를 가져오면 client가 url을 통해 요청한 데이터를 내보낼 수 있다. 

localhost:3000?idx=1&name=asdf

예를 들어 client가 url에 위와 같이 req를 보내면 req.query는 { idx: '1', name: 'asdf' }와 같이 객체 형태로 값을 받아온다. 

 

2. sql

받아온 idx값을 SELECT 문에 넣어서 문장을 완성한다. 

  sql = 'SELECT * FROM Goods WHERE idx = "'+idx+'"'

string과 변수를 이어 주기 위해서는 변수에 +를 붙여서 하나의 string으로 만들어 줄 수 있다. 사실 숫자만 들어온다면 idx를 " "로 감싸줄 필요가 없기도 하지만, 숫자와 함께 string이 들어올 수도 있기 때문에 받는 변수를 " "로 감싸준다.

위와 같이 받은 sql을 console에 출력해보면 다음과 같다 : SELECT * FROM Goods WHERE idx = 1

 

3. pool.query

sql에 query를 보내고 콜백 함수로 에러와 결과값을 가져온다.

해당 함수를 실행하면 Goods 테이블의 idx 1 의 데이터를 출력할 수 있다. results :  [ RowDataPacket { idx: 1, name: 'test', price: 2000 } ]

 

4. Injection Attack

이때, url 주소를 다음과 같이 해서 데이터를 모두 가져올 수 있다.

localhost:3000?idx=whatever" or 1="1

이렇게 req를 보내면 sql은 SELECT * FROM Goods WHERE idx = "whatever" or 1="1" 이 된다. 1="1" 이기 때문에 해당 조건은 무조건 true가 되며 Table에 있는 모든 데이터 값이 결과로 표시된다.


그렇다면 Injection Attack을 어떻게 막을 수 있을까?

 

Injection Attack을 막는 방법은 2가지가 있다. 하나는 escape 함수를 사용하는 방법이고, 하나는 Bind 변수를 사용하는 방법이다.

1. escape 함수

escape 함수는 변수를 string으로 encoding 해주는 함수이다. 들어오는 값이 이미 string인데 왜 string으로 바꿔주는 거지 하는 의문을 가질 수도 있겠지만 들어오는 문자의 양 옆에 ' '를 넣어준다고 생각하면 더 편하다.

 cntd = connection.escape(idx) //idx=3 => idx='3'

이렇게 해주는 이유는 실제 예제를 보면 이해가 된다.

  sql = 'SELECT * FROM Goods WHERE idx = '+cntd 
  console.log("sql : ", sql)
  pool.query(sql, function(error, results, fields) { 
    if (error) throw error;
    console.log('results : ', results)
  })

sql문을 위와 같이 만들어주면 localhost:3000?idx=whatever" or 1="1의 방식으로 접근했을 때 query문에 한번 더 ' '를 씌워주면서 sql이 올바르지 않게 만들어지고 결과값이 출력되지 않는다.

query :  { idx: 'whatever" or 1="1' }
cntd :  'whatever\" or 1=\"1' string
sql :  SELECT * FROM Goods WHERE idx = 'whatever\" or 1=\"1'

 

2. Bind 변수

가장 간편하고 많이 사용하는 쿼리문 작성 방식이다. 아래 보이는 ?를 바인드 변수라고 하며 변수값이 들어가야 하는 부분에 바인드 변수를 넣어주면 해당 값이 자동으로 쿼리문에 들어가게 된다.

  pool.query('SELECT * FROM Goods WHERE idx = ?', idx, function (error, results, fields) {
    if (error) throw error;
    console.log('results : ', results)
  });
  
  //--------------------------------------------------------------------
  
  columns=['idx', 'name']
  pool.query('SELECT ?? FROM ?? WHERE idx = ?',[columns, 'Goods', idx], 
    function (error, results, fields) {
    if (error) throw error;
    console.log('results : ', results)
  });

이때 바인드 변수는 자체적으로 들어오는 데이터를 필터링하고 위험한 요소를 제거해준다. 따라서 정상적이지 않은 방식으로 접근했을 때 결과값을 출력하지 않는다.

 

+ 참고로 Bind 변수에서 물음표 2개(??)는 table, columns 등이 필요할 때 사용되고 물음표 1개(?)는 실제 값을 넣을 때 사용한다.

'Backend > Backend 기본' 카테고리의 다른 글

Database 상태변화  (0) 2021.01.27
Callback & Promise & async & await  (0) 2021.01.27
Express 환경 사용하기 3 - 라우팅  (0) 2021.01.20
Express 환경 사용하기 2 - 미들웨어  (0) 2021.01.19
Express 환경 사용하기 1  (0) 2021.01.18
Comments