일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- ChatGPT
- gitlab
- nvmrc
- 클라우드
- chatGPTAPI
- 패키지설치에러
- iam사용자
- aiapi
- 웹소켓연결
- Database
- 웹소켓재시작
- gptapi
- javascript
- 클래스
- gpt3.5turbo
- 자바
- 호스팅영역
- Github
- 버킷생성
- 웹소켓연결끊김
- db
- 노드버전
- aws
- class
- GPT3.5
- Express
- openaiapi
- java
- git
- nodejs
- Today
- Total
IT's Jenna
Injection attak 본문
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 |