なぜここに?
JavaScriptによるSQLインジェクション攻撃について耳にしたことはあるだろうが、実際にどのようなものなのか、そもそも心配する必要があるのか、まったくわからない。もしかしたら、それがどの程度悪いものなのか把握しようとしているかもしれない。
要するに、MySQLやPostgreSQLのようなSQLデータベースを使用してアプリケーションを構築している場合、あなたは危険にさらされているのです。開発者としては、ユーザーデータを保護するガードレールを実装し、基礎となるインフラが決して侵入されたり、探索されたり、徴用されたりしないようにする責任があります。
新しいツールはすべて、あなたを助けると言っているが、開発をより複雑にしているだけだ。
Sequelizeや TypeORMの ようなオブジェクトリレーショナルマッパー(ORM)を追加することで、MySQLやPostgreSQLのようなSQLデータベースでの作業を簡素化することはできるが、リスクを完全に回避できるわけではない。ウェブアプリケーションファイアウォール(WAF)は、ネットワークレベルでの攻撃をブロックするのに役立つが、高価なインフラと継続的なメンテナンスが必要だ。コードスキャナー(Code Scanner)は、明らかな欠陥を特定するのに役立つが、未知の未知数や潜んでいるゼロデイテクニックに対しては、ほとんど役に立たない。
SQLインジェクション攻撃がどのようなもので、どのようなリスクがあり、どのような開発ミスがSQLインジェクション攻撃を可能にしているのかを明確に説明します。そして、グローバルなHotfixのインストール方法を説明することで、お客様のアプリが安全であることを確実にお伝えします。
SQLインジェクション攻撃の例とその影響
SQLインジェクション攻撃の最も基本的な定義は、アプリがデータベースクエリを実行するために、検証もサニタイズもされていないユーザー入力を許可することで、攻撃者がSQLデータベースを読んだり、レコードを変更したり、思いのままに削除したりできるようにすることです。
いつものように、XKCDはSQLの危険性を、私たちが夢見るような暗いシナリオよりもうまく説明している:

脆弱なJavaScriptアプリはどのようなものか?
簡単な擬似コードの例から始めましょう。ユーザーが猫のデータベースを検索できる入力要素を持つJavaScriptアプリです。以下のJavaScriptコード例では、アプリは/catsパスのPOSTリクエストに応答して、リクエストボディからユーザー入力を抽出し、一致するidを持つすべての猫を返すクエリでデータベースに接続します。そして、アプリはJSONレスポンスを使って猫を表示します。
app.post("/cats", (request, response) => {
const query = `SELECT * FROM cats WHERE id = ${request.body.id}`;
connection.query(query, (err, rows) => {
if(err) throw err;
response.json({
data: rows
});
});
});
この例はSQLインジェクション攻撃の訓練を受けていない人には無害に見えるかもしれませんが、非常に脆弱です。特筆すべきは、このアプリは潜在的に危険な文字列やエンコーディング方法について、ユーザー入力を検証したりサニタイズしたりしようとせず、ユーザー入力をSQLクエリに直接連結していることです。
JavaScriptのSQL攻撃ペイロードの例
SQLインジェクションは、アプリがSQLクエリを生成する方法によって、MySQLやPostgreSQLデータベースを騙してアクションを起こさせたり、想定外のデータで応答させたりすることにかかっています。
会社情報 1=1は常に真 攻撃は、アポストロフィや引用符のようなトリックを使って、猫の表全体を返すことができる。 1=1
は確かに常に 本当だ:
- ユーザーは入力する:
ボビー・テーブル'または1='1
- データベースはSQLクエリを実行する:
SELECT * FROM Users WHERE Cat = BOBBY TABLES OR 1=1;
同様に、攻撃者は = は常に真である というのも、すべての猫を返せという攻撃だからだ。 ""=""
は常に 本当だ:
- ユーザーは入力する:
"OR ""=""
- データベースはSQLクエリを実行する:
SELECT * FROM Cats WHERE CatId ="" または ""="";
攻撃者はしばしば、データベースがインラインコメントをどのように扱うかを悪用し、コメント (/* ... */)
をクエリに入れることで、意図を難読化したり、フィルタを迂回したりすることができる。
- ユーザーは入力する:
DR/*hello world*/OP/*sneak attack*/ TABLE Cats;
- データベースはSQLクエリを実行する:
DROP TABLE Cats;
これは、攻撃者に無害な文字列で開始させ、セミコロン(;)を使ってそのステートメントを終了させ、インジェクションを含む別のステートメントを開始させるものです。攻撃者はクエリスタッキングを使って、DROP TABLEコマンドでデータベース全体を一挙に削除することがよくあります:
- ユーザーは入力する:
ボビー; DROP TABLE キャッツ--。
- アプリはSQLクエリーを構築する:
const query = "SELECT * FROM Cats WHERE CatId = " + input;
- データベースはSQLクエリを実行する:
SELECT * FROM Cats WHERE CatId = BOBBY; DROP TABLE Cats;
NoSQLインジェクション攻撃についてはどうだろうか?
NoSQLインジェクション攻撃は、アプリとユーザーデータのセキュリティにとって同様に危険だが、MongoDBのようなデータベースを使用する技術スタックにのみ影響する。SQLとNoSQLのクエリはまったく独自の構文を使用するため、一方のカテゴリーから他方のカテゴリーに変換することはできません。
SQLデータベースを使用していれば、NoSQLインジェクション攻撃のリスクはない。
基本的な方法:SQLインジェクションの脆弱性をすべて手動で修正する。
この時点では、可能性のあるインジェクションのトリックがどのようなものかにはあまり興味がなく、MySQL や PostgreSQL にあるデータをどのように保護するかに関心があるかもしれません。
- パラメータ化されたクエリを使用する:SQLにはクエリと値の実行を切断する機能があり、インジェクション攻撃からデータベースを保護します。上記のJavaScript/Node.jsの例では、SQLクエリにクエスチョンマーク(
?
).そのconnection.query()
メソッドは第2引数にパラメータを取り、インジェクション防止メソッドと同じ結果を提供する。
app.post("/cats", (request, response) => {
const query = `SELECT * FROM Cats WHERE id = ?`;
const value = request.body.id;
connection.query(query, value, (err, rows) => {
if(err) throw err;
response.json({
data: rows
});
});
});
- ユーザー入力の検証とサニタイズ:パラメータ化されたクエリは、SQLデータベースを侵入や攻撃から保護するのに役立ちますが、ユーザーが潜在的に危険な文字列をアプリケーションに入力するのを防ぐこともできます。
サニタイズとバリデーションのためのオープンソースのライブラリをアプリに追加するのも一つの方法だ。例えば バリデータ.js JavaScript/Node.jsエコシステムにおいて、ユーザーがサインアップフォームにSQLインジェクション攻撃ではなく、本物のメールアドレスを入力しようとしていることをダブルチェックする。
同じような作業を行うために、正規表現ベースのカスタムバリデータを開発することもできますが、調査や膨大な手作業によるテストなど、膨大な時間と複雑な道のりが待ち受けています。さらに、この正規表現例を本当にEメールバリデーションのために解釈できるでしょうか?const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
のような文字列を防ぐのにも同じ考え方が適用される。...' OR 1-'1.
このような機会をすべて自分で調査し、潰していくこともできるが、それよりも新機能の構築に時間を費やした方がいいだろう。
- WAFやエージェントベースのセキュリティ・プラットフォームを導入する:
第一に、高価であることが多く、オンプレミスまたはクラウド上に新しいインフラを立ち上げる必要がある。第二に、ルールセットを更新するために手作業によるメンテナンスが必要になり、SQLインジェクションに対する他の手作業による介入から注意をそらすことになる。最後に、計算負荷が増えたり、分析のためにすべてのリクエストを自社のプラットフォーム経由でリダイレクトすることで、待ち時間が増え、エンドユーザー・エクスペリエンスが損なわれることがよくある。
大きな問題は、SQLインジェクション攻撃の機会は雑草のようなものであることだ。これらのツールを使えば一度はすべて刈り取ることができるが、二度と芽が出ないようにコードベース全体を常に警戒しなければならない。
JavaScriptのSQLインジェクション攻撃を解決する代替パス:Aikido ファイアウォール
Aikido Securityが最近リリースしたFirewallは、SQLインジェクション攻撃から自律的にあなたを守る、フリーでオープンソースのセキュリティ・エンジンだ。
Node.jsを使用していない場合、私たちは将来的に他の言語やフレームワークのサポートを開始する予定です。FirewallがJavaScriptの世界を超えて拡大する正確な情報を得るために、いつでも製品ニュースレターを購読することができますし、特定の言語を売り込みたい場合はhello@aikido.devまでメールしてください。
JavaSciptのSQLインジェクションに脆弱なアプリのテスト
オープンソースのリポジトリに同梱されているサンプルアプリを使って、Aikido Firewallの動作を紹介しよう。ローカルのMySQLデータベースをデプロイするためにDocker/DockerComposeも必要だ。
まず、firewall-nodeリポジトリをフォークし、そのフォークをローカルのワークステーションにクローンします。
git clone https://github.com/<YOUR-GITHUB-USERNAME>/firewall-node.gitcd firewall-node
Dockerを使って、ローカルのMySQLデータベースをポート27015にデプロイする。このdocker-compose.ymlファイルは、s3mock、MongoDB、PostgreSQLコンテナも作成します。これは、Aikido チームがFirewallが様々な攻撃をどのようにブロックするかをテストするために作成されたものです。
docker-compose -f sample-apps/docker-compose.yml up -d
次に、サンプルアプリを起動します:
node sample-apps/express-mysql2/app.js
オープン http://localhost:4000
をブラウザで開いて、とてもシンプルな猫アプリをチェックしよう。テキストエリアに猫の名前をいくつか入力して 追加 ボタンをクリックします。SQLインジェクションをテストするには テスト噴射 リンクをクリックするか、テキストエリアに以下を入力してください: キティ'); DELETE FROM cats;-- H
をクリックしてください。 追加 もう一度。いずれにせよ、このアプリを使えば、複数のクエリーをまとめて、卑劣なクエリーコメントを使って、ネコのデータベース全体を削除することができる。
どうしてこうなるのか?先に警告したように、このアプリは単に いずれも SQLクエリの最後にユーザー入力を入力するが、これは本質的に安全ではない。
const query = `INSERT INTO cats(petname) VALUES ('${name}');`
ここでの結果は小さいかもしれないが、このしばしば起こる正直なミスが、本番アプリに悲惨な結果をもたらすことは想像に難くない。
Aikido FirewallでJavaScriptのSQLインジェクションをブロックする
では、私たちのオープンソースのセキュリティ・エンジンが、あなたのコードにあるデータベースのやり取りをすべて手作業で修正することなく、JavaScriptのSQLインジェクション攻撃をどれだけ素早くブロックするか見てみましょう。
まだAikido アカウントを持っていない場合は、先に進んでください。 無料で作る.すでにお持ちの場合は、ログインして GitHubアカウントに接続する.その過程で、Aikido あなたのフォークを読むことを許可する。 ファイアウォールノード
プロジェクトに参加している。
に行く。 ファイアウォール・ダッシュボード をクリックし、Add Serviceをクリックします。サービス名を付け、再度、フォークを選択して ファイアウォールノード
プロジェクトに参加している。

Aikido 、Aikido Firewallをインストールして実装する方法を説明します。サンプルアプリを使用しているので、その作業はすでに終わっていますが、JavaScriptのSQLインジェクション攻撃に脆弱な可能性のあるすべてのNode.jsアプリに、私たちのオープンソースのセキュリティエンジンを導入する方法について参考になります。

をクリックする。 トークンの生成 ボタンをクリックし、Aikido FirewallがブロックされたSQLインジェクション攻撃に関する情報をAikido セキュリティプラットフォームに安全に渡すためのトークンを作成します。で始まる生成されたトークンをコピーします。 AIK_RUNTIME...
そしてターミナルに戻ってサンプルアプリを再実行する:
AIKIDO_TOKEN=<YOUR-AIKIDO-TOKEN> AIKIDO_DEBUG=true AIKIDO_BLOCKING=true node sample-apps/express-mysql2/app.js
オープン ローカルホスト:4000
を実行し、もう一度SQLインジェクション攻撃を実行する。今回、Aikido ブラウザであなたをブロックし、ローカルのウェブサーバのログに出力し、新しいイベントを生成します。これをクリックすると、ペイロードやアプリが危険なSQLクエリを生成した場所など、SQLインジェクションの試みに関する包括的な詳細が表示されます。

Aikido Firewallは、JavaScriptによるSQLインジェクション攻撃からアプリを永遠に守ることに悩む代わりに、攻撃ソース、一般的なペイロード、潜在的な弱点について常に情報を提供する包括的なブロックと洗練された観測機能を提供します。
次はどうする?
Aikido Firewallは、Node.jsベースのアプリケーションに無料でインストール、実装することができます。私たちのオープンソースの組み込みセキュリティエンジンは、JavaScriptのSQLインジェクション攻撃、コマンドインジェクション、プロトタイプ汚染、パストラバーサル、およびすぐに来るより多くからあなたのインフラストラクチャとユーザーデータを保護します。
Firewall が SQL インジェクションから守るための開発のベストプラクティス(パラメータ化されたクエリを使 うとか、ユーザの入力を信用しないとか)に取って代わるべきだと言っているわけではありません。コードベースに欠陥はなく、正直な間違いは常に起こります。
FirewallはSQLインジェクションのグローバルな修正プログラムだと思ってください。カスタム開発された正規表現、レイテンシーを誘発するWAF、あるいは高額な費用がかかる複雑なセキュリティ・エージェントとは異なり、Firewallはこの1つの仕事を非常にうまく、しかも影響はごくわずかで、完全に無料で行うことができる。
もし気に入っていただけたなら、ロードマップをご覧いただき、GitHub リポジトリ(https://github.com/AikidoSec/firewall-node) に星をつけてください。⭐