Node.js에서 SQL 주입 방지


86

PHP가이를 방지하는 Prepared Statements를 가지고있는 것과 같은 방식으로 Node.js (가급적 모듈 사용)에서 SQL 주입을 방지 할 수 있습니까?

그렇다면 어떻게? 그렇지 않은 경우 내가 제공 한 코드를 우회 할 수 있는 몇 가지 예는 무엇입니까 (아래 참조).


일부 컨텍스트 :

node-mysql 모듈을 사용하여 Node.js + MySql로 구성된 백엔드 스택으로 웹 애플리케이션을 만들고 있습니다. 유용성의 관점에서, 모듈은 매우 중요하지만, 아직 PHP의 유사 뭔가를 구현하지 않은 문 준비 (나는 그것이에 알고 있어요하지만 할 일 ).

필자가 이해 한 바에 따르면 PHP의 준비된 명령문 구현은 무엇보다도 SQL 삽입을 방지 하는 데 크게 도움이되었습니다 . 하지만 기본적으로 제공되는 문자열 이스케이프 (아래 코드 스 니펫 참조)를 사용 하더라도 내 node.js 앱이 유사한 공격에 노출 될 수 있다는 점이 걱정 됩니다.

node-mysql은 node.js를위한 가장 인기있는 mysql 커넥터 인 것 같습니다. 그래서 다른 사람들이이 문제를 설명하기 위해 무엇을하는지 궁금합니다. (사용자 / 클라이언트 측 입력이 관련되어 있기 때문에 이것이 어떻게 될지 확실하지 않습니다).

준비된 명령문을 제공하므로 당분간 node-mysql-native 로 전환해야합니까 ? 이것은 node-mysql만큼 활동적이지 않은 것 같기 때문에 주저합니다.

다음은 새니 타이 저 모듈 을 사용하는 사용자 등록 코드 와 node-mysql의 준비된 문과 유사한 구문 (위에서 언급했듯이 문자 이스케이프를 수행함)을 사용하여 사이트 간 스크립팅 및 SQL 삽입을 각각 방지하는 코드입니다.

// Prevent xss
var clean_user = sanitizer.sanitize(username);

// assume password is hashed already
var post = {Username: clean_user, Password: hash};

// This just uses connection.escape() underneath
var query = connection.query('INSERT INTO users SET ?', post,
   function(err, results)
   {
       // Can a Sql injection happen here?
   });

답변:


59

node-mysql라이브러리는 자동으로 당신이 이미하고있는로 사용하는 경우 탈출 수행한다. 참조 https://github.com/felixge/node-mysql#escaping-query-values를


3
내 게시물에서 언급했듯이 라이브러리가 문자를 이스케이프한다는 것을 알고 있지만 준비된 명령문을 구현 한 라이브러리로 전환하지 않으면 보안 의미에 대해 더 걱정됩니다. 나는 현재하고 있습니까?
funseiki

2
이스케이프 문자는 SQL 삽입을 방지합니다. 인젝션은 문자가 이스케이프되지 않을 때 발생하며 악의적 인 사용자는이를 악용하여 쿼리를 닫고 새로운 쿼리를 시작하여 테이블을 삭제하거나 가짜 레코드를 삽입 할 수 있습니다. 이스케이프 된 문자로는 불가능합니다. Wikipedia 에는 SQL Injection에 대한 몇 가지 추가 정보가 있습니다.
Michael Pratt 2013

4
그러나 모든 SQL 주입을 방지합니까? 이 답변 은 (적어도 PHP + MySQL의 경우) 아니라고 제안하며 PHP의 Prepared Statements를 의미합니다. 다시 말하지만 이것은 PHP의 맥락입니다.
funseiki

1
귀하의 링크에 따르면 MySQL의 오래된 버전에서만 작동합니다. 특정 공격이 Node에서 작동하는지 여부는 알 수 없지만 매우 구체적인 PHP 취약점과 관련이있는 것처럼 보이므로 내 직감은 아니오입니다. 나는 node-mysql에 절대적으로 취약점이 없다고 말하는 것이 아니라 이미 많은 프로덕션 환경에서 사용되고 있습니다. 여전히 SQL 주입에 대해 걱정하고 있다면 총알을 깨물고 MongoDB와 같은 것을 시도하는 것이 좋습니다. SQL을 사용하지 않으면 SQL 주입을 할 수 없습니다.
Michael Pratt

1
그렇게 보였고 MongoDB 경로는 좋은 점입니다. 현재 디자인은 관계형 스키마에 적합합니다. 합의 그냥 노드 MySQL과 고집으로처럼, 그렇지 않으면 보인다 - 나는 다른 사람이 보안 취약점에 대한 통찰력을 가지고 있는지 확인하기 위해 기다릴 것
funseiki

12

라이브러리에는 이스케이프에 대한 추가 정보 섹션 이 있습니다 . Javascript-native이므로 node-mysql-native로 전환하는 것은 권장하지 않습니다 . 문서에는 이스케이프에 대한 다음 지침이 나와 있습니다.

편집 : node-mysql-native 는 또한 순수 자바 스크립트 솔루션입니다.

  • 숫자는 그대로 둡니다.
  • 부울은 true/ false문자열 로 변환 됩니다.
  • 날짜 개체는 YYYY-mm-dd HH:ii:ss문자열 로 변환 됩니다.
  • 버퍼는 16 진 문자열로 변환됩니다. X'0fa5'
  • 문자열은 안전하게 이스케이프됩니다.
  • 배열은 목록 ['a', 'b']으로 변환됩니다.'a', 'b'
  • 중첩 된 배열은 그룹화 된 목록 (대량 삽입 용) [['a', 'b'], ['c', 'd']]으로 변환됩니다.('a', 'b'), ('c', 'd')
  • 개체는 key = 'val'쌍 으로 바뀝니다. 중첩 된 개체는 문자열로 캐스팅됩니다.
  • undefined/ null변환NULL
  • NaN/ Infinity그대로 둡니다. MySQL은이를 지원하지 않으며 값으로 삽입하려고하면 지원을 구현할 때까지 MySQL 오류가 트리거됩니다.

이를 통해 다음과 같은 작업을 수행 할 수 있습니다.

var userId = 5;
var query = connection.query('SELECT * FROM users WHERE id = ?', [userId], function(err, results) {
  //query.sql returns SELECT * FROM users WHERE id = '5'
});

뿐만 아니라 :

var post  = {id: 1, title: 'Hello MySQL'};
var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) {
  //query.sql returns INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
});

이러한 함수 외에도 이스케이프 함수를 사용할 수도 있습니다.

connection.escape(query);
mysql.escape(query);

쿼리 식별자를 이스케이프하려면 :

mysql.escapeId(identifier);

준비된 진술에 대한 귀하의 의견에 대한 응답으로 :

사용성 관점에서이 모듈은 훌륭하지만 아직 PHP의 Prepared Statements와 유사한 것을 구현하지 않았습니다.

준비된 명령문은 이 커넥터의 할 목록에 있지만이 모듈은 최소한 준비된 명령문과 매우 유사한 사용자 정의 형식을 지정할 수 있도록합니다. Readme의 예는 다음과 같습니다.

connection.config.queryFormat = function (query, values) {
  if (!values) return query;
  return query.replace(/\:(\w+)/g, function (txt, key) {
    if (values.hasOwnProperty(key)) {
      return this.escape(values[key]);
    }
    return txt;
  }.bind(this));
};

이렇게하면 연결의 쿼리 형식이 변경되므로 다음과 같은 쿼리를 사용할 수 있습니다.

connection.query("UPDATE posts SET title = :title", { title: "Hello MySQL" });
//equivalent to
connection.query("UPDATE posts SET title = " + mysql.escape("Hello MySQL");

답변 해주셔서 감사합니다. 준비된 스타일을 알고 있습니다. 그러나 그 아래에서는 캐릭터가 이스케이프되고 있습니다. 참조 : "그러나 실제로는 동일한 connection.escape ()"를 사용 합니다. node-mysql-native를 사용하지 않는 한 : 이것이 제가 고심하고있는 것입니다. node-mysql-native가 준비된 명령문을 구현하고 그 구현이 SQL 주입을 방지한다면 node-mysql이이를 가질 때까지 전환해야합니까?
funseiki

일종의 닭고기와 달걀 질문입니다. 대부분의 사람들이 @felixge를 사용하기 때문에 드라이버를 적극적으로 개발하고 있지 않습니다. 준비된 명령문을 node-mysql로 ​​이식 할 시간을 찾으려고 노력할 것입니다. 당신이 한번 풀어주는 것을 결정하는 경우에 코멘트 / 사후 문제에 대한 부담
안드레이 시도 로프

1
@funseiki 나는 준비된 진술이 최선의 해결책이 될 것이라고 확신하지만 이스케이프가 SQL 주입을 막을 것이라고 확신합니다. 모듈 자체가 Joyent에 의해 지원되기 때문에 모듈은 활성 상태이며 분명히 철저히 검사됩니다. 이 모듈이 생산 준비가되지 않았다면 지난달에이 모듈이 하루 평균 1000 회 다운로드를 할 수 없을 것이라고 생각합니다. node-mysql-native는 마지막으로 개발 된 지 6 개월이 지났으며 node-mysql은 여러 사람이 작업하면서 매우 활동적입니다.
hexacyanide

@AndreySidorov 의견을 보내 주셔서 감사합니다. 문제를 해결하려고하면 업데이트를 게시하겠습니다. 나는 그것이 처리하기 쉬운 짐승처럼 보이지 않기 때문에 조만간이 될 것이라고 생각하지 않습니다 (현재 시간보다 더 많은 연구가 필요할 것입니다). 또한 드라이버를 만들어 주셔서 감사합니다. Node.js를 사용하여 앱을 빠르게 실행할 수있는 이유는 바로 여러분입니다
funseiki

@hexacyanide node-mysql은 매우 인기가 많기 때문에 커뮤니티 구성원이 직면 한 (또는 예방할 수있는) 보안 문제에 대한 응답과 현재 문자 이스케이프 접근 방식이 안전한 이유에 대한 설득력있는 주장을 얻을 수 있기를 바랐습니다. 코드에 충분합니다.
funseiki

12

나는 이것이 오래된 게시물이라는 것을 알고 있지만 답변이 표시되지 않은 것 같아서 이것을 밖으로 던질 것입니다.

사용중인 모듈이 안전한지 여부를 테스트하는 것과 관련하여 취할 수있는 여러 경로가 있습니다. 더 많은 정보에 입각 한 결정을 내릴 수 있도록 각각의 장단점을 다루겠습니다.

현재 사용중인 모듈에 대한 취약점은 없지만, 현재 사용중인 모듈 / 소프트웨어 패키지를 악용하는 취약점이있을 수 있으며 경고를받지 못하므로 종종 잘못된 보안 감각으로 이어질 수 있습니다. 공급 업체가 수정 / 패치를 적용 할 때까지

  1. 취약성을 파악하려면 메일 링리스트, 포럼, IRC 및 기타 해킹 관련 토론을 따라야합니다. 장점 : 공급 업체가 경고를 받거나 소프트웨어에 대한 잠재적 인 공격 경로를 수정하기 위해 수정 / 패치를 발행하기 전에 라이브러리 내의 잠재적 문제를 인식하는 경우가 많습니다. 단점 : 이것은 매우 시간과 리소스를 많이 사용합니다. RSS 피드를 사용하는 봇, 로그 구문 분석 (IRC 채팅 로그) 및 또는 핵심 구문 (이 경우 node-mysql-native) 및 알림을 사용하는 웹 스크레이퍼를 사용하면 이러한 리소스를 트롤링하는 데 소요되는 시간을 줄이는 데 도움이 될 수 있습니다.

  2. fuzzer를 만들고, fuzzer 또는 metasploit , sqlMap 등과 같은 기타 취약성 프레임 워크 를 사용하여 공급 업체가 찾지 못한 문제를 테스트하는 데 도움을줍니다. PRO : 이것은 구현중인 모듈 / 소프트웨어가 공개 액세스에 안전한지 여부를 허용 가능한 수준으로 보장하는 확실한 화재 방법임을 입증 할 수 있습니다. 단점 : 이것은 또한 시간과 비용이 많이 듭니다. 다른 문제는 잘못된 긍정과 문제가 존재하지만 알아 차리지 못한 결과에 대한 교육받지 못한 검토에서 비롯됩니다.

실제로 보안 및 일반적으로 애플리케이션 보안은 시간과 리소스를 많이 소모 할 수 있습니다. 관리자가 항상 사용하는 한 가지는 위의 두 가지 옵션을 수행하는 비용 효율성 (인력, 자원, 시간, 급여 등)을 결정하는 공식입니다.

어쨌든, 나는 이것이 바라고있을 수있는 '예'또는 '아니오'대답이 아니라는 것을 알고 있지만 문제의 소프트웨어에 대한 분석을 수행 할 때까지 아무도 당신에게 그것을 줄 수 있다고 생각하지 않습니다.


3

나는이 질문이 오래되었다는 것을 알고 있지만 관심있는 사람이라면 Mysql-native가 구식이어서 원래 MySQL 모듈 팀의 도움으로 만든 새로운 모듈 인 MySQL2 가되었습니다 . 이 모듈은 더 많은 기능을 가지고 있으며 더 많은 보안을 위해 PHP에서와 같이 문을 준비 (using.execute ())했기 때문에 원하는 것을 가지고 있다고 생각합니다.

또한 매우 활동적입니다 (마지막 변경은 2-1 일이었습니다). 전에는 해본 적이 없지만 원하는 것 이상이라고 생각합니다.


-1

가장 쉬운 방법은 경로로 내보내는 자체 모듈에서 모든 데이터베이스 상호 작용을 처리하는 것입니다. 경로에 데이터베이스 컨텍스트가 없으면 SQL은 어쨌든 그것을 건드릴 수 없습니다.


그것은 살균 방법에 대한 OP의 질문에 실제로 대답하지 않습니다.
Christopher
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.