脚本怎样过滤非法请求参数

wen 实用脚本 23

本文目录导读:

脚本怎样过滤非法请求参数

  1. 通用过滤逻辑(建议集成到中间件)
  2. 代码实现示例
  3. 针对不同攻击类型的专项过滤
  4. 最佳实践总结
  5. 一个“偷懒但有效”的加固技巧

脚本过滤非法请求参数是保障Web应用安全的重要环节,核心思想是不信赖任何来自客户端的数据,采用 白名单(只允许合法字符)黑名单(禁止非法字符) 更安全。

以下从三个层面提供脚本方案:通用逻辑、代码实现(Node.js/Python/Java示例)、以及具体的防御场景

通用过滤逻辑(建议集成到中间件)

一个健壮的过滤脚本通常包含以下步骤:

  1. 输入清洗(Sanitization):删除或编码危险的字符。
  2. 输入验证(Validation):检查格式、类型、长度、范围。
  3. 参数类型强制转换:确保 id 是整数,page 是数字。

代码实现示例

Node.js (Express 中间件示例)

使用 validator 库和 xss 库进行清洗。

// 安装: npm install validator xss
const validator = require('validator');
const xss = require('xss');
// 过滤函数:对传入的 query/body 进行递归清洗
function sanitizeObject(obj) {
  if (typeof obj === 'string') {
    // 1. 去除首尾空格(Trim)
    let clean = obj.trim();
    // 2. 转义 HTML 特殊字符,防止 XSS
    clean = xss(clean);
    // 3. 去除控制字符(ASCII 0-31, 127)
    clean = clean.replace(/[\x00-\x1f\x7f]/g, '');
    return clean;
  } else if (Array.isArray(obj)) {
    return obj.map(item => sanitizeObject(item));
  } else if (obj && typeof obj === 'object') {
    const cleaned = {};
    for (const [key, value] of Object.entries(obj)) {
      // 过滤参数名:只允许字母、数字、下划线、中划线
      if (!/^[a-zA-Z0-9_-]+$/.test(key)) {
        delete obj[key]; // 删除非法的参数名
        continue;
      }
      cleaned[key] = sanitizeObject(value);
    }
    return cleaned;
  }
  return obj;
}
// Express 中间件
function paramFilter(req, res, next) {
  try {
    req.query = sanitizeObject(req.query);
    req.body = sanitizeObject(req.body);
    // 检查关键参数类型
    if (req.query.id && !validator.isInt(req.query.id)) {
      return res.status(400).json({ error: 'Invalid ID format' });
    }
    next();
  } catch (error) {
    return res.status(400).json({ error: 'Parameter sanitization failed' });
  }
}
// 应用中间件(在路由之前)
app.use(paramFilter);

Python (Flask 示例)

使用 bleach 库清洗 HTML,使用正则校验。

import re
import bleach
from flask import request, abort, jsonify
# 白名单模式:只允许指定的字符
ALLOWED_PATTERN = re.compile(r'^[a-zA-Z0-9_\-\s\.\,\!\?]*$')
def sanitize_param(value, max_length=255):
    """清洗单个参数"""
    if not isinstance(value, str):
        return value
    # 1. 截断长度(防止DOS攻击)
    value = value[:max_length]
    # 2. 去除不可见控制字符(除了空格和换行)
    value = re.sub(r'[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', value)
    # 3. 清洗HTML标签(防止XSS),允许一些安全标签如 <b>, <i>
    value = bleach.clean(value, tags=['b', 'i', 'u'], strip=True)
    return value
def filter_params():
    """过滤请求参数"""
    filtered = {}
    for key, value in request.args.items():
        # 过滤参数名:只允许字母数字
        if not re.match(r'^[a-zA-Z0-9_]+$', key):
            continue  # 跳过非法参数名
        # 对值进行清洗
        filtered[key] = sanitize_param(value)
    return filtered
# 在视图函数中使用
@app.route('/search')
def search():
    params = filter_params()
    keyword = params.get('keyword', '')
    # 具体业务验证
    if len(keyword) > 0 and not ALLOWED_PATTERN.match(keyword):
        abort(400, description="Keyword contains invalid characters")
    return jsonify({"status": "ok", "keyword": keyword})

Java (Spring Boot 统一过滤)

创建自定义的 HttpServletRequestWrapper 或使用过滤器。

import org.springframework.web.util.HtmlUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.regex.Pattern;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private static final Pattern[] XSS_PATTERNS = new Pattern[]{
        Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
        Pattern.compile("onload=(.*?) ", Pattern.CASE_INSENSITIVE | Pattern.DOTALL),
        Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.DOTALL)
    };
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (value == null) return null;
        return cleanXSS(value);
    }
    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        if (values == null) return null;
        String[] cleaned = new String[values.length];
        for (int i = 0; i < values.length; i++) {
            cleaned[i] = cleanXSS(values[i]);
        }
        return cleaned;
    }
    private String cleanXSS(String value) {
        // 1. HTML 转义(核心)
        value = HtmlUtils.htmlEscape(value);
        // 2. 移除危险模式(第二道防线)
        for (Pattern pattern : XSS_PATTERNS) {
            value = pattern.matcher(value).replaceAll("");
        }
        // 3. 限制最大长度
        if (value.length() > 1000) {
            value = value.substring(0, 1000);
        }
        // 4. 移除控制字符
        value = value.replaceAll("[\\x00-\\x1f\\x7f]", "");
        return value;
    }
}

针对不同攻击类型的专项过滤

攻击类型 过滤策略 示例正则/逻辑
SQL 注入 永远不要自己拼SQL,使用参数化查询(PreparedStatement),过滤特殊关键字(, , , , ) 使用 ORM / 参数化查询,配合 \b(UNION|SELECT|DROP)\b 等关键字检测
XSS (跨站脚本) HTML 实体编码 < > & "&lt; 使用 validator.escape()bleach.clean()
命令注入 严格白名单,只允许字母数字,禁用 , &, , , , \n | ^[a-zA-Z0-9_\-\.]+$
路径遍历 移除 , , ,使用 basename() 函数 path.normalize(path.basename(userInput))
NoSQL 注入 对查询参数(如 $gt, $ne, $regex)进行类型校验,禁止传入对象/数组 拒绝 body 中的 {$ne: ''} 结构
文件上传 检查 MIME 类型、文件扩展名,重命名文件,限制大小 使用白名单扩展名:[jpg, png, gif]

最佳实践总结

  1. 不要重复造轮子:使用成熟的库(OWASP ESAPI, validator.js, bleach, Spring Security)。
  2. 深度防御:前端验证(体验) + 后端验证(安全) + 数据库存储过程(备份)。
  3. 记录日志,不暴露细节:发现非法请求时,记录IP和参数,但返回统一的“400 Bad Request”。
  4. 超长字符串:对字符串参数设置最大长度(255 或 1024 字符),防止缓存区溢出或DOS。
  5. 参数名也要过滤:防止通过污染参数名绕过逻辑(例如注入 _method__proto__)。
  6. JSON 与 NoSQL 注入:API 接收 application/json不要直接使用 JSON.parse,先对键值进行类型校验。

一个“偷懒但有效”的加固技巧

如果不确定具体规则,可以执行以下强制类型转换(适用于REST API):

  • ID 参数id = parseInt(id, 10),如果转换失败,返回错误。
  • 布尔值:只接受 true / false 字符串,或 0 / 1
  • 枚举值:用白名单数组 ['admin', 'user', 'guest'] 校验。
  • 富文本:使用专业的 HTML 清洗器(如 DOMPurify, bleach)清理后,再存入数据库。

最安全的脚本是结合了白名单验证、类型强制转换和成熟库的清洗逻辑,并且始终运行在服务端

抱歉,评论功能暂时关闭!