web-dev-qa-db-ja.com

Node.jsでのSQLインジェクションの防止

PHPがそれらに対して保護するPrepared Statementを持っているのと同じ方法で、Node.jsで(できればモジュールを使用して)SQLインジェクションを防ぐことは可能ですか?.

もしそうなら、どのように?そうでない場合、私が提供したコードをバイパスする可能性のあるいくつかの例は何ですか(以下を参照)。


コンテキスト:

node-mysql モジュールを使用して、Node.js + MySqlで構成されるバックエンドスタックでWebアプリケーションを作成しています。使いやすさの観点からは、このモジュールは優れていますが、PHPの Prepared Statements に似たものはまだ実装されていません(ただし、 todo にあります)。

私の理解では、PHPのプリペアドステートメントの実装、とりわけ、SQLインジェクションの防止における 大いに役立ちました 。ただし、node.jsアプリが同様の攻撃にさらされる可能性があるのではないかと心配しています デフォルトで提供される文字列エスケープを使用しても (以下のコードスニペットのように)。

node-mysqlはnode.jsの最も人気のあるmysqlコネクタであるように思えるので、この問題を説明するために他の人が何をしているのか(もしあれば)考えていましたか? (ユーザー/クライアント側の入力が関係するため、これがどのように行われないかはわかりません)。

node-mysql-native に切り替える必要があります。準備されたステートメントを提供するためです。私はためらっていますこれを行うには、node-mysqlほどアクティブではないようです(ただし、完全であることを意味する場合もあります)。

以下に、ユーザー登録コードのスニペットを示します。これは、クロスサイトスクリプティングを防ぐために、ノードのmysqlの準備されたステートメントのような構文(前述のように文字エスケープを行います)とともに sanitizer モジュールを使用しますそれぞれ、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?
   });
78
funseiki

node-mysqlライブラリーは、既に使用しているように使用されると自動的にエスケープを実行します。 https://github.com/felixge/node-mysql#escaping-query-values を参照してください

50
Michael Pratt

これは古い投稿であることに気づきましたが、回答にマークが付けられていなかったように思われるので、ここに捨てます。

利用しているモジュールが安全かどうかのテストに関しては、いくつかのルートがあります。あなたがより多くの情報に基づいた決定を下せるように、私はそれぞれの長所/短所に触れます。

現在、使用しているモジュールに脆弱性はありませんが、使用しているモジュール/ソフトウェアパッケージを現在悪用している脆弱性が存在する可能性があり、警告されないため、これはしばしば誤ったセキュリティ感覚につながる可能性がありますベンダーが修正/パッチを適用するまで問題に対処します。

  1. 脆弱性に遅れないようにするには、メーリングリスト、フォーラム、IRCおよびその他のハッキング関連の議論をフォローする必要があります。 PRO:ベンダーに警告が出されたり、ソフトウェアに対する潜在的な攻撃手段を修正するための修正/パッチが発行される前に、ライブラリ内の潜在的な問題に気付くことがよくあります。 CON:これは非常に時間がかかり、リソースを大量に消費する可能性があります。 RSSフィード、ログ解析(IRCチャットログ)を使用するボット、またはキーフレーズ(この場合はnode-mysql-native)と通知を使用するWebスクレーパーを使用してボットをこのルートに移動すると、これらのリソースのトローリングに費やす時間を削減できます。

  2. ファザーを作成し、 fuzzer または metasploitsqlMap などの他の脆弱性フレームワークを使用して、ベンダーが抱えていない可能性のある問題をテストします。探した。 PRO:これは、実装しているモジュール/ソフトウェアがパブリックアクセスに対して安全であるかどうかに関係なく、許容できるレベルまで確保する確実な方法であることが証明できます。 CON:これも時間がかかり、コストがかかります。もう1つの問題は、誤検知と、問題が存在するが気づいていない結果の教育されていないレビューに起因します。

本当にセキュリティ、および一般的なアプリケーションセキュリティは、非常に時間がかかり、リソースを大量に消費します。マネージャーが常に使用するものの1つは、上記の2つのオプションを実行する費用対効果(人材、リソース、時間、給与など)を決定する公式です。

とにかく、これは望んでいた「はい」または「いいえ」の答えではないことを理解していますが、問題のソフトウェアの分析を実行するまで誰もあなたにそれを与えることができないと思います。

10
jas-

ライブラリには、エスケープに関するreadmeに section があります。 Javascriptネイティブなので、 node-mysql-native に切り替えることはお勧めしません。ドキュメントには、これらのエスケープのガイドラインが記載されています。

Edit:node-mysql-native もpure-Javascriptソリューションです。

  • 数字はそのままです
  • ブール値は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/nullNULLに変換されます
  • 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に類似したものはまだ実装されていません。

準備済みステートメントは、このコネクタの todo リストにありますが、このモジュールでは、少なくとも、準備済みステートメントに非常によく似たカスタム形式を指定できます。 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");
10
hexacyanide

私はこの質問が古いことを知っていますが、興味のある人にとっては、Mysql-nativeは古くなっているため、元のMySQLモジュールのチームの助けを借りて作成された新しいモジュールである MySQL2 になりました。このモジュールにはより多くの機能があり、PHPのようにステートメントを(using.execute()で)用意しているので、セキュリティを強化するために必要なものがあると思います。

また、非常にアクティブです(最後の変更は2-1日からでした)私は前にそれを試しませんでしたが、それはあなたが望むものともっと多くだと思います。

1
Boy pro

最も簡単な方法は、ルートにエクスポートする独自のモジュールですべてのデータベースインタラクションを処理することです。ルートがデータベースのコンテキストを持たない場合、SQLはそれとは関係ありません。

0
Bird Dad