Index
NoSQLインジェクション
説明
NoSQLインジェクションは、攻撃者がNoSQLデータベースを使用するアプリケーションの弱点を悪用したときに発生するセキュリティの脆弱性です。これには、入力フィールドに悪意のあるデータや予期しないデータをインジェクションして、攻撃者がクエリを操作し、不正な情報にアクセスできるようにすることが含まれます。
SQLデータベースに対するSQLインジェクション攻撃と同様に、NoSQLインジェクションは、MongoDB、CassandraなどのNoSQLデータベースを利用するアプリケーションを標的とします。攻撃者は、特殊文字やペイロードなどの入力を巧妙に作成して、アプリケーションによって実行されるNoSQLデータベースクエリを操作します。
作成された入力をインジェクションすることで、攻撃者はデータベースクエリのロジックを変更したり、認証をバイパスしたり、データベースに保存されている機密情報を取得したりすることを目的とします。NoSQLインジェクション攻撃は、不正なデータアクセス、データ変更、またはデータベースの完全な侵害につながる可能性があり、アプリケーションとそのデータの機密性、完全性、可用性が損なわれます。
例
import com.mongodb.*;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/login")
public class NoSQLInjectionController {
@PostMapping
public void login(@RequestParam String userName, @RequestParam String password) {
MongoClientURI uri = new MongoClientURI("mongodb://localhost:27017");
MongoClient mongoClient = new MongoClient(uri);
try {
DB database = mongoClient.getDB("test");
DBCollection collection = database.getCollection("users");
BasicDBObject query = new BasicDBObject();
query.put("$where", "this.sharedWith == \"" + userName + "\" && this.password == \"" + password + "\"");
DBCursor cursor = collection.find(query);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
} finally {
mongoClient.close();
}
}
}
const MongoClient = require('mongodb').MongoClient;
const express = require('express');
const app = express();
app.post('/login', async (req, res) => {
const username = req.body.username;
const password = req.body.password;
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('test');
const usersCollection = database.collection('users');
// Vulnerable query susceptible to NoSQL Injection
query = { $where: `this.username == '${username}' && this.password == '${password}'` }
const user = await usersCollection.find(query);
res.json({ success: user !== null });
} finally {
await client.close();
}
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
<?php
$username = $_POST['username'];
$password = $_POST['password'];
$manager = new MongoDB\Driver\Manager('mongodb://localhost:27017');
$query = [ "username" => $username, 'password' => $password ];
$testquery = new MongoDB\Driver\Query($query, []);
$cursor = $manager->executeQuery('test.users', $testquery);
foreach ($cursor as $document) {
var_dump($document);
}
?>
推奨事項
NoSQLインジェクション攻撃を防ぐには、次の対策を検討してください。
-
安全なクエリ構築: データベースの特定のメソッドまたはAPIによって提供されるクエリビルダーを使用してクエリを構築します。ユーザー入力をクエリに直接連結しないでください。代わりに、安全なクエリ構築のためにデータベースAPIによって提供される適切なメカニズムを使用してください。
-
入力の検証とサニタイズ: ユーザーが提供したデータが予期されたフォーマットを満たしていることを確認するために、堅牢な入力検証を実装します。許可される文字のホワイトリスト登録などのサニタイズ手法を使用して、不要な入力を防ぎます。
-
受け入れられるキーのホワイトリストを使用する: オペレーターのインジェクションを防ぐために、受け入れられるキーのホワイトリストを使用して、
$where、$in、$neなどのクエリオペレーターのインジェクションを防ぎます。
例
import com.mongodb.*;
import java.util.regex.Pattern;
public class SecureNoSQLInjection {
public static void main(String[] args) {
String username = sanitizeInput(args[0]);
String password = sanitizeInput(args[1]);
MongoClientURI uri = new MongoClientURI("mongodb://localhost:27017");
MongoClient mongoClient = new MongoClient(uri);
DB database = mongoClient.getDB("test");
DBCollection collection = database.getCollection("users");
BasicDBObject query = new BasicDBObject();
query.put("username", username);
query.put("password", password);
DBCursor cursor = collection.find(query);
while (cursor.hasNext()) {
System.out.println(cursor.next());
}
}
// Function to sanitize input (escape special characters)
private static String sanitizeInput(String input) {
return Pattern.quote(input); // Escapes special characters in the input string
}
}
const MongoClient = require('mongodb').MongoClient;
const express = require('express');
const mongoSanitize = require('mongo-sanitize');
const app = express();
// Middleware to parse incoming JSON requests
app.use(express.json());
app.post('/login', async (req, res) => {
const username = mongoSanitize.sanitize(req.body.username);
const password = mongoSanitize.sanitize(req.body.password);
const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);
try {
await client.connect();
const database = client.db('test');
const usersCollection = database.collection('users');
// Secure query using parameterization to prevent NoSQL Injection
const user = await usersCollection.findOne({ username, password }); // Secure code with input sanitization
res.json({ success: user !== null });
} finally {
await client.close();
}
});
app.listen(3000, () => {
console.log('Server started on port 3000');
});
<?php
$username = $_POST['username'] ?? null;
$password = $_POST['password'] ?? null;
$sanitizedUsername = filter_var($username, FILTER_SANITIZE_STRING);
$manager = new MongoDB\Driver\Manager('mongodb://localhost:27017');
// Using prepared statements for the query
$query = new MongoDB\Driver\Query([
'username' => $sanitizedUsername,
'password' => ['$eq' => $password] // Use an exact match for the password
]);
try {
$cursor = $manager->executeQuery('test.users', $query);
foreach ($cursor as $document) {
var_dump($document);
}
} catch (MongoDB\Driver\Exception\Exception $e) {
echo "Exception: ", $e->getMessage();
}
?>
リンク
標準
- GDPR:
- ART_5
- ART_32
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_3
- REQ_6_5
- REQ_8_6
- SOC2_CONTROLS:
- CC_2_1
- CC_3_4
- CC_4_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- HIPAA_CONTROLS:
- SECURITY212
- SECURITY213
- SECURITY255