代码安全审查

437 浏览
35 试用
8 购买
Nov 24, 2025更新

针对指定代码进行安全审查,识别潜在漏洞与不良编码实践,并提供可执行的修复方案与安全编码建议,帮助开发团队提升代码安全性和可靠性,适用于安全评估和代码审查流程。

以下是基于OWASP Top 10对这段JavaScript/Express代码的安全审查与加固建议,重点覆盖SQL注入与权限绕过,同时包含其他显著安全问题与修复方案。

主要问题与风险

  • A03: 注入(SQL注入)
    • 登录SQL使用字符串拼接:SELECT ... WHERE username='${username}' AND password='${password}',可被构造输入注入。
    • 使用数据库root账户,权限过大,一旦注入成功影响范围极大。
    • 明文密码对比(数据库中存储明文密码),即使后续防注入,仍属于严重的身份认证缺陷。
  • A01: 访问控制缺陷(权限绕过)
    • /admin使用jwt.decode而非jwt.verify,未进行签名验证,攻击者可自造token并填充role=admin直接绕过。
    • /profile忽略过期时间(ignoreExpiration: true),长期有效的过期令牌可继续使用。
    • 接收token通过URL查询参数,易在日志、Referer、浏览器历史记录中泄露,导致会话劫持。
  • A07: 识别与认证失败
    • JWT使用硬编码弱密钥"secret",易被猜测或泄露。
    • 登录流程未实施速率限制与账户锁定,易被暴力破解。
    • 未设定JWT的exp/iat/iss/aud等关键声明与校验,存在令牌滥用与混用风险。
  • A02: 加密失败
    • 明文密码存储与对比;JWT密钥管理不当;未限制允许的算法。
  • A05: 安全配置错误
    • 数据库以root/root连接,未使用最小权限账户;密钥与凭证硬编码在源代码中。
  • 其他
    • 输入未校验(长度/字符集),增加注入与DoS风险。
    • 错误处理不一致,可能导致信息泄露或用户枚举(虽然当前返回较“朴素”,但仍建议统一消息)。

可操作的修复与安全编码实践

  1. 消除SQL注入、加固密码处理
  • 使用参数化查询/预编译语句,不要拼接字符串。
  • 将密码存储为强哈希(如bcrypt,推荐成本系数10-12),登录时使用bcrypt.compare。
  • 使用最小权限的数据库用户,仅允许SELECT/必要操作;不要使用root。
  • 对输入进行白名单校验与长度限制。

示例修复(使用mysql2与bcrypt): const express = require('express'); const mysql2 = require('mysql2/promise'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken');

const app = express(); app.use(express.json());

const pool = mysql2.createPool({ host: process.env.DB_HOST, user: process.env.DB_USER, // 使用最小权限账户 password: process.env.DB_PASS, database: process.env.DB_NAME, connectionLimit: 10, ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: true } : undefined });

function validateLoginInput(username, password) { if (typeof username !== 'string' || typeof password !== 'string') return false; if (username.length < 3 || username.length > 64) return false; if (password.length < 8 || password.length > 128) return false; return true; }

app.post('/login', async (req, res) => { try { const { username, password } = req.body; if (!validateLoginInput(username, password)) return res.status(400).send('invalid');

const [rows] = await pool.execute(
  'SELECT id, username, role, password_hash FROM users WHERE username = ? LIMIT 1',
  [username]
);
if (!rows.length) return res.status(401).send('invalid');

const user = rows[0];
const ok = await bcrypt.compare(password, user.password_hash);
if (!ok) return res.status(401).send('invalid');

const token = jwt.sign(
  { sub: user.id, role: user.role },
  process.env.JWT_SECRET,
  {
    algorithm: 'HS256',
    expiresIn: '15m',           // 设置短期有效期
    issuer: 'your-app',
    audience: 'your-app-api'
  }
);
res.json({ token });

} catch (e) { res.status(500).send('error'); } });

  1. 正确验证JWT、避免权限绕过
  • 始终使用jwt.verify进行签名和声明校验,不使用jwt.decode做授权判断。
  • 不接受token通过查询参数;统一从Authorization: Bearer 头读取。
  • 禁止ignoreExpiration;严格校验exp、iss、aud、iat;限制允许算法algorithms: ['HS256']或使用RS256并配置密钥轮换。
  • 为高权限操作(如admin),建议在验证令牌后再次查询数据库确认当前角色(防止令牌中的角色过期或被撤销)。

示例修复: function getTokenFromHeader(req) { const h = req.headers.authorization || ''; if (!h.startsWith('Bearer ')) return null; return h.slice(7); }

app.get('/profile', (req, res) => { try { const token = getTokenFromHeader(req); if (!token) return res.status(401).send('unauthorized');

const decoded = jwt.verify(token, process.env.JWT_SECRET, {
  algorithms: ['HS256'],
  issuer: 'your-app',
  audience: 'your-app-api'
});
res.json({ userId: decoded.sub, role: decoded.role });

} catch (e) { res.status(401).send('unauthorized'); } });

app.get('/admin', async (req, res) => { try { const token = getTokenFromHeader(req); if (!token) return res.status(401).send('unauthorized');

const decoded = jwt.verify(token, process.env.JWT_SECRET, {
  algorithms: ['HS256'],
  issuer: 'your-app',
  audience: 'your-app-api'
});

const [rows] = await pool.execute('SELECT role FROM users WHERE id = ? LIMIT 1', [decoded.sub]);
if (rows.length && rows[0].role === 'admin') {
  return res.send('admin ok');
}
return res.status(403).send('forbidden');

} catch (e) { res.status(401).send('unauthorized'); } });

  1. 密钥与配置管理
  • 将JWT密钥、数据库凭证放入环境变量或秘密管理服务,不要硬编码。
  • 使用高熵密钥(至少256位随机),定期轮换;考虑使用RS256并配合JWKS进行密钥管理。
  • 在jwt.verify中明确限制algorithms,防止算法降级或混淆。
  1. 身份验证与会话安全强化
  • 实施登录速率限制与账户锁定(如express-rate-limit),防暴力破解。
  • 统一、最小化错误消息,避免用户枚举(登录失败始终返回“invalid”)。
  • 使用短期访问令牌与刷新令牌机制;撤销策略(黑名单/jti),对高权限操作更严格。
  1. 输入校验与通用安全加固
  • 对所有外部输入进行长度与格式校验;使用库如 joi/validator。
  • 全局安全中间件:helmet、严格的CORS策略。
  • 审计日志记录安全事件(失败登录、权限拒绝),但避免记录敏感数据(令牌、密码)。
  • 数据库连接使用TLS(如RDS或支持SSL的MySQL),并限制网络访问。
  • 采用最小权限原则:API进程、数据库用户、服务器文件权限。

与OWASP Top 10的映射

  • A03: 注入 → 采用参数化查询、输入校验。
  • A01: 访问控制缺陷 → 始终verify JWT、禁止query传token、强制声明校验与后端RBAC复核。
  • A07: 识别与认证失败 → 密码哈希、速率限制、短期令牌与刷新机制。
  • A02: 加密失败 → 强密钥、算法限制、密钥管理与轮换。
  • A05: 安全配置错误 → 禁止硬编码凭证、使用最小权限与安全默认配置。

结论 当前代码存在高风险的SQL注入与权限绕过问题,攻击者可通过构造输入获取数据库权限或伪造令牌提升为管理员。请按上述步骤进行参数化查询、密码哈希、严格JWT验证与密钥管理,并补充速率限制、输入校验和最小权限配置,以显著提升整体安全性。

以下是基于OWASP Top 10 的安全审查结论与修复建议。重点覆盖 XSS 与 CSRF,并补充相关的安全配置与最佳实践。

一、主要问题与风险评估

  • 存储型 XSS(A03:2021-Injection / XSS)

    • comments.append(request.form.get('content', '')) 未做任何过滤/编码。
    • 模板中使用 {{ c|safe }} 强制取消转义,用户可注入任意 HTML/JS。
    • /transfer 返回 f-string 字符串,若作为 HTML 渲染,存在反射型 XSS 风险。
  • CSRF(A01:2021-Broken Access Control / A05:2021-Security Misconfiguration)

    • /transfer 仅依赖 Cookie 进行身份识别,无 CSRF Token 校验。
    • 页面中包含可直接提交到 /transfer 的表单,攻击者可在第三方站点构造自动提交的表单完成跨站请求。
    • Cookie 配置不安全:resp.set_cookie('session', 'demo-user', httponly=False)。未设置 HttpOnly、Secure、SameSite,增加CSRF与会话劫持风险。
  • 其他安全问题(防护建议)

    • render_template_string 更容易在错误使用时引入模板注入风险,建议使用模板文件并保持默认 autoescape。
    • debug=True 在生产环境泄露敏感信息(栈、配置等)。
    • 输入未校验:amount、to 缺少格式与范围校验。
    • 安全响应头缺失(CSP、X-Frame-Options、X-Content-Type-Options 等)。

二、修复措施(优先级从高到低)

  1. 修复 XSS
  • 去除不必要的 |safe,使用默认转义:
    • {{ c|safe }}
    • 改为
    • {{ c }}
  • 若确有展示少量 HTML 的需求,存储前进行严格白名单清洗(如 bleach),并在模板中仍保持默认转义:
    • 仅允许特定标签和属性,过滤事件处理器与危险协议(javascript:, data:)。
  • 避免直接在 HTML 中拼接用户输入。/transfer 返回值改为 JSON 或在模板中进行变量输出:
    • 使用 jsonify 返回结构化响应,或使用 markupsafe.escape 进行编码。
  1. 启用 CSRF 防护
  • 使用 Flask-WTF 的 CSRFProtect(推荐,简单稳妥):
    • pip install flask-wtf
    • app.config['SECRET_KEY'] 设置强随机密钥
    • from flask_wtf.csrf import CSRFProtect; CSRFProtect(app)
    • 所有修改状态的表单中包含 {{ csrf_token() }} 隐藏字段。
  • 如不使用 Flask-WTF,至少实现自定义 CSRF Token(双提交 Cookie 或 Session Token 模式)并在 /transfer 验证。
  • 防御加固(不替代 Token):
    • 在敏感接口校验 Origin/Referer 是否为本站域名。
    • 将 SameSite 设置为 Lax 或 Strict。
  1. 安全 Cookie
  • 不要手动设置名为 session 的认证 Cookie;使用 Flask 内置 session(签名、管控更安全)。
  • 配置:
    • SESSION_COOKIE_HTTPONLY = True
    • SESSION_COOKIE_SECURE = True(仅 HTTPS)
    • SESSION_COOKIE_SAMESITE = 'Lax' 或 'Strict'
  • 如必须设置自定义 Cookie,务必添加 httponly=True, secure=True, samesite='Lax'/'Strict',并避免放置敏感会话信息。
  1. 输入校验与输出安全
  • 对 amount、to 做严格校验:
    • amount 必须为正数且不超过业务上限。
    • to 仅允许受限字符集与长度(如 ^[a-zA-Z0-9_]{1,32}$)。
  • 优先返回 JSON(application/json),避免把用户输入拼接到 HTML 中。
  1. 模板与视图改进
  • 使用 render_template 加载模板文件,减少 render_template_string 带来的误用风险。
  • 禁用或限制 Jinja2 中可能的危险过滤器与环境设置(保留默认 autoescape)。
  • 将转账表单从评论页面分离,减少“无意操作”风险,并对转账页启用 CSRF Token 与二次确认。
  1. 安全响应头(防御加固)
  • 在 after_request 中统一设置:
    • Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
    • X-Content-Type-Options: nosniff
    • X-Frame-Options: DENY
    • Referrer-Policy: same-origin
  • 对静态资源使用可靠的来源和完整性校验(SRI)如适用。
  1. 运行配置
  • 生产环境禁用 debug,使用 gunicorn/uwsgi 等生产服务器。
  • 设置强随机 SECRET_KEY 并通过环境变量注入,不要硬编码。

三、参考修复示例(节选)

  • 应用初始化与全局安全设置:
    • 使用 Flask-WTF CSRF
    • 设置安全 Cookie 与安全响应头

示例代码: from flask import Flask, request, render_template, redirect, url_for, jsonify, session from flask_wtf.csrf import CSRFProtect from markupsafe import escape import os, re from decimal import Decimal import bleach

app = Flask(name) app.config.update( SECRET_KEY=os.environ.get("SECRET_KEY", os.urandom(32)), SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SECURE=True, # 生产中启用 HTTPS SESSION_COOKIE_SAMESITE='Lax' ) CSRFProtect(app)

comments = [] ALLOWED_TAGS = ['b', 'i', 'em', 'strong', 'a'] ALLOWED_ATTRS = {'a': ['href', 'title']} ALLOWED_PROTOCOLS = ['http', 'https']

@app.after_request def security_headers(resp): resp.headers['Content-Security-Policy'] = "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" resp.headers['X-Content-Type-Options'] = 'nosniff' resp.headers['X-Frame-Options'] = 'DENY' resp.headers['Referrer-Policy'] = 'same-origin' return resp

@app.route('/comment', methods=['GET', 'POST']) def comment(): if request.method == 'POST': raw = request.form.get('content', '') # 若不允许 HTML,可直接存储原文并在模板中 {{ c }} 输出 clean = bleach.clean(raw, tags=ALLOWED_TAGS, attributes=ALLOWED_ATTRS, protocols=ALLOWED_PROTOCOLS, strip=True) comments.append(clean) return redirect(url_for('comment')) return render_template('comments.html', comments=comments)

@app.route('/transfer', methods=['POST']) def transfer(): to = request.form.get('to', '') amount = request.form.get('amount', '') if not re.fullmatch(r'[A-Za-z0-9_]{1,32}', to or ''): return jsonify(error='invalid recipient'), 400 try: amt = Decimal(amount) if amt <= 0: raise ValueError() except Exception: return jsonify(error='invalid amount'), 400 user = session.get('user', 'anonymous') return jsonify(message=f'Transferred {str(amt)} from {user} to {to}')

if name == 'main': app.run(debug=False)

  • 对应模板 comments.html(关键点:去掉 |safe,并在敏感表单中包含 CSRF token):

Comments

    {% for c in comments %}
  • {{ c }}
  • {% endfor %}
{{ csrf_token() }}

四、核对清单(实施后自测)

  • XSS
    • 提交 到评论,页面不应执行脚本。
    • CSP 生效,内联脚本与外域脚本被阻止。
  • CSRF
    • 从第三方站点自动 POST 到 /transfer 请求应被 CSRF 校验拒绝。
    • Cookie 设置为 HttpOnly+Secure+SameSite,跨站提交不再携带 Cookie(或受 SameSite 限制)。
  • 其他
    • 生产环境 debug=False。
    • 输入校验对异常值返回 400。
    • 安全响应头存在且符合预期。

通过以上修改,可有效消除当前代码中的存储型 XSS 与 CSRF 漏洞,并符合 OWASP Top 10 对输入验证、输出编码、身份与会话管理以及安全配置的要求。

以下为针对所给 C++ 代码的安全审查与加固建议(参考 CERT 安全编码规范)。重点问题集中在缓冲区溢出与命令注入,并补充其他安全实践。

一、发现的问题与影响

  1. 缓冲区溢出(高危)
  • readHeader: 使用 fscanf(f, "%s", r.header) 无字段宽度限制,可能写越界到 r.header(64 字节)。
    • 违反 CERT STR31-C: 保证字符串存储空间足够;ERR33-C: 检查库函数返回值。
  • loadPayload: 读入 tmp[1024] 后用 strcpy(r.payload, tmp) 复制到 r.payload(256 字节),可能越界。
    • 违反 CERT STR31-C/STR32-C;ERR33-C。
  1. 命令注入(高危)
  • system(argv[2]) 直接执行用户提供的命令,存在任意命令执行风险。
    • 违反 CERT MSC06-C/ENV33-C(避免使用 system 或不可控输入调用 system)。
  1. 输入校验与错误处理不足(中危)
  • 未检查 fscanf/fgets 的返回值,可能导致未初始化或半初始化数据被使用。
    • 违反 CERT ERR33-C。
  • 未对读取的 header/payload 进行长度/字符集验证。
  1. 控制台转义/日志注入(低到中危)
  • 直接输出不受信任的数据到终端,可能触发 ANSI 转义序列导致终端欺骗。
    • 可参考 CERT FIO50-CPP(I/O 安全实践)和通用输出净化建议。

二、可行修复方案 A. 在不改变数据结构前提下的最小变更修复

  • 对 fscanf 指定最大字段宽度,检查返回值。
  • 避免 strcpy,直接限定读取到目标缓冲区或使用有界拷贝。
  • 去除换行并确保以 NUL 结尾。

修复示例(C 风格): void readHeader(FILE* f, Record& r) { // 限定最大读取 63 字符,保留 NUL if (fscanf(f, "%63s", r.header) != 1) { // 处理错误/EOF r.header[0] = '\0'; // 可返回错误码或抛异常 } }

void loadPayload(FILE* f, Record& r) { // 直接读取到目标缓冲区,避免中间 tmp 再复制 if (!fgets(r.payload, sizeof(r.payload), f)) { r.payload[0] = '\0'; // 处理错误/EOF return; } // 去除行末换行 size_t len = strcspn(r.payload, "\r\n"); r.payload[len] = '\0'; }

  • 若必须保留中间缓冲 tmp: char tmp[1024]; if (fgets(tmp, sizeof(tmp), f)) { // 安全拷贝:截断到 255 并 NUL 结尾 size_t n = strnlen(tmp, sizeof(tmp)); size_t m = (n < sizeof(r.payload) - 1) ? n : (sizeof(r.payload) - 1); memcpy(r.payload, tmp, m); r.payload[m] = '\0'; } else { r.payload[0] = '\0'; }

B. C++ 方式的结构化重写(更推荐)

  • 使用 std::string 和 std::getline 管理内存与边界,显式长度校验。
  • RAII 管理文件对象,减少资源泄漏风险。

示例: struct Record { std::string header; std::string payload; };

bool readHeader(std::istream& in, Record& r) { std::string line; if (!std::getline(in, line)) return false; if (line.size() > 63) return false; // 超长则拒绝或截断 r.header = line; return true; }

bool loadPayload(std::istream& in, Record& r) { std::string line; if (!std::getline(in, line)) return false; if (line.size() > 255) return false; r.payload = line; return true; }

C. 移除/替代 system 调用(强制建议)

  • 最佳做法:删除该功能或改为内部实现(例如根据 cmd 执行内部枚举动作)。
  • 如必须调用外部程序:
    • 使用白名单,将用户输入映射到有限集合中的固定命令与固定参数;使用绝对路径;不拼接字符串;避免经 shell 解析。
    • 使用 execve/execv/posix_spawn,而非 system;构造 argv 数组,不包含来自用户的任意片段。
    • 示例(伪代码): // map<string, vector> allowed = { {"date", {"/bin/date"}}, {"list", {"/bin/ls","-l"}} }; auto it = allowed.find(cmd); if (it == allowed.end()) { /* 拒绝 */ } // 构造 argv 并 execv(it->second[0], argv)
  • 若出于兼容原因无法移除 system,则必须严格校验 cmd:
    • 仅允许 [A-Za-z0-9._-] 等安全字符,禁止空格、分号、管道、重定向、子命令、通配符等。
    • 仍然不安全(shell 语义复杂),不建议保留。

D. I/O 与错误处理

  • 统一检查 fopen/fscanf/fgets 的返回值与 errno;错误路径将结构清零或置为已知安全状态。参考 CERT ERR33-C。
  • 打印/日志输出前净化不可见控制字符:
    • 将非 isprint 的字节映射为 '.' 或进行转义,防止终端转义注入。

E. 额外防护与工程实践

  • 编译与链接强化:
    • 开启栈保护与 FORTIFY:-D_FORTIFY_SOURCE=2 -fstack-protector-strong
    • 启用 PIE/RELRO/DEP:-fPIE -pie -Wl,-z,relro,-z,now
    • 警告与静态分析:-Wall -Wextra -Wconversion -Wshadow -Werror,并配合 clang-tidy、cppcheck。
  • 运行期检测:使用 AddressSanitizer/UBSan(-fsanitize=address,undefined)进行测试。
  • 最小权限原则:不要以高权限运行该解析器;对输入文件路径做适度校验(不跟随不可信符号链接等场景)。
  • 单元测试覆盖边界条件:0 长度、恰好边界(63/255)、超长、包含非 ASCII/控制字符、空文件/短文件。

三、简化后的主程序建议

  • 去除 system;改用内部命令枚举或白名单 exec。
  • 使用 RAII 管理文件;在每一步检查错误并在失败时安全返回。

示例(C 版本,保留原结构,去除 system): int main(int argc, char** argv) { if (argc < 2) { std::cout << "Usage: parser \n"; return 1; } FILE* f = fopen(argv[1], "r"); if (!f) { std::perror("open"); return 1; } Record r{}; readHeader(f, r); loadPayload(f, r); fclose(f);

// 输出前净化(示意)
// sanitize(r.header); sanitize(r.payload);

std::cout << "Header: " << r.header << "\n";
std::cout << "Payload: " << r.payload << "\n";
return 0;

}

四、结论

  • 主要风险为缓冲区溢出与命令注入,均为可被远程/本地输入触发的高危问题。
  • 通过为 scanf/fgets 设置边界、删除 strcpy、验证长度与返回值、移除 system 并采用白名单 exec 或内部实现,可以显著提升安全性。
  • 辅以编译器/链接器强化、静态/动态分析与输出净化,满足 CERT 相关规则(STR31-C/STR32-C/ERR33-C、MSC06-C/ENV33-C 等)的要求。

示例详情

解决的问题

帮助开发者快速检测代码潜在安全漏洞,并提供专业、可操作的修复建议,提升代码整体安全性,减少安全隐患,保障产品稳定性。

适用用户

软件开发工程师

帮助开发者进行代码自检,快速发现并修复潜在的安全漏洞,从而提升编码质量和产品安全性。

企业信息安全团队

为安全专家提供系统化的代码安全分析,保护企业敏感数据安全,降低业务风险。

技术团队负责人

协助技术领导者优化团队代码质量审查流程,全面提升团队开发效率与代码安全水准。

特征总结

自动扫描代码中的潜在安全漏洞,助您快速发现隐藏的风险。
提供专业的修复建议和安全编码实践,确保代码安全性达到行业标准。
支持多种主流编程语言,轻松应对不同开发环境的审查需求。
注重上下文语义分析,帮助您精确定位问题并理解潜在风险的根源。
一键生成安全提升方案,让代码优化过程更加高效便捷。
强化代码防护能力,显著降低因漏洞导致的数据泄露或系统瘫痪风险。
适配不同业务场景,为产品开发、系统维护和代码评审提供专业的安全支持。
帮助团队建立敏捷高效的安全编码流程,减少后期安全问题的修复成本。
可灵活定制审查范围,聚焦特定漏洞类型以满足具体开发需求。
支持即时反馈,确保问题发现与解决的高效闭环。

如何使用购买的提示词模板

1. 直接在外部 Chat 应用中使用

将模板生成的提示词复制粘贴到您常用的 Chat 应用(如 ChatGPT、Claude 等),即可直接对话使用,无需额外开发。适合个人快速体验和轻量使用场景。

2. 发布为 API 接口调用

把提示词模板转化为 API,您的程序可任意修改模板参数,通过接口直接调用,轻松实现自动化与批量处理。适合开发者集成与业务系统嵌入。

3. 在 MCP Client 中配置使用

在 MCP client 中配置对应的 server 地址,让您的 AI 应用自动调用提示词模板。适合高级用户和团队协作,让提示词在不同 AI 工具间无缝衔接。

AI 提示词价格
¥20.00元
先用后买,用好了再付款,超安全!

您购买后可以获得什么

获得完整提示词模板
- 共 105 tokens
- 4 个可调节参数
{ 编程语言 } { 代码内容 } { 潜在漏洞类型 } { 安全标准/规范 }
获得社区贡献内容的使用权
- 精选社区优质案例,助您快速上手提示词
限时免费

不要错过!

免费获取高级提示词-优惠即将到期

17
:
23
小时
:
59
分钟
:
59