You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复基于用户输入动态数组的盲SQL注入(NodeJS+PSQL环境)

Fixing Blind SQL Injection in Dynamic Node.js + PostgreSQL Queries

Hey there! Let's tackle that blind SQL injection issue you're facing—you're absolutely right that parameterized queries are the correct fix here, and it's totally feasible even with your dynamic room and category lists. Let's break this down step by step.

Why Your Current Code Is Risky

Right now, you're directly interpolating user input into your SQL string. If an attacker modifies the request to send something like ' OR 1=1-- as a room or category name, your SQL becomes:

SELECT products.* FROM products WHERE products.room_id IN (SELECT DISTINCT rooms.id FROM rooms WHERE rooms.name = 'common area' OR rooms.name = 'OR 1=1--') ...

This would return every product in your database, which is a classic SQL injection vulnerability. Parameterized queries eliminate this by separating SQL logic from user input entirely.

Step-by-Step Parameterized Query Solution

Instead of hardcoding user input into the SQL string, we'll create placeholder values (like $1, $2) and pass the actual input values as a separate array to db.query(). PostgreSQL handles escaping and type safety automatically.

1. Build Parameterized Conditions for Rooms

First, generate a list of parameterized conditions for rooms, along with the corresponding values:

const roomConditions = [];
const roomParams = [];
let paramCounter = 1;

for (const room of query.rooms) {
  // Add a parameterized condition (e.g., "rooms.name = $1")
  roomConditions.push(`rooms.name = $${paramCounter}`);
  // Store the actual room name as a parameter value
  roomParams.push(room);
  paramCounter++;
}

2. Build Parameterized Conditions for Categories

Do the same for categories—note we'll keep incrementing the parameter counter to avoid duplicate placeholders:

const categoryConditions = [];
const categoryParams = [];

// Use Object.values() to iterate over category objects more cleanly
for (const category of Object.values(categories)) {
  categoryConditions.push(`categories.name = $${paramCounter}`);
  categoryParams.push(category.name);
  paramCounter++;
}

3. Handle Edge Cases (Empty Lists)

If a user submits an empty list of rooms or categories, your WHERE clause would be empty, causing a SQL syntax error. Add fallback logic to handle this:

// If no rooms are selected, match all rooms (adjust this logic if you need to exclude instead)
const roomWhereClause = roomConditions.length > 0 
  ? roomConditions.join(' OR ') 
  : '1=1';

// Same for categories
const categoryWhereClause = categoryConditions.length > 0 
  ? categoryConditions.join(' OR ') 
  : '1=1';

4. Construct and Execute the Final Query

Now assemble the full SQL string with our parameterized clauses, and pass all parameters together:

const finalQuery = `
  SELECT products.* 
  FROM products 
  WHERE products.room_id IN (
    SELECT DISTINCT rooms.id 
    FROM rooms 
    WHERE ${roomWhereClause}
  ) 
  AND products.category_id IN (
    SELECT DISTINCT categories.id 
    FROM categories 
    WHERE ${categoryWhereClause}
  ) 
  ORDER BY products.price
`;

// Combine all parameter values into a single array
const allParams = [...roomParams, ...categoryParams];

// Execute the parameterized query
const productsRoomAndCategories = (await db.query(finalQuery, allParams)).rows;

Why This Works

  • No Injection Risk: PostgreSQL parses the SQL template first, then substitutes the parameter values—user input can never be interpreted as SQL code.
  • No Manual Quoting: You don't need to add single quotes around values; the parameterization system handles string escaping and type matching automatically.
  • Performance Bonus: PostgreSQL can cache the execution plan for the parameterized query, making repeated runs faster than dynamically generated SQL.

内容的提问来源于stack exchange,提问作者Jamie Huff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:52:44