×
¥
查看详情
🔥 会员专享 文生代码 安全

代码安全分析

👁️ 549 次查看
📅 Nov 24, 2025
💡 核心价值: 针对指定代码进行全面安全审查,识别逻辑错误、潜在缺陷及漏洞,并提供可执行的优化方案与防护建议,帮助开发团队提升代码质量、可维护性和安全性,适用于安全评估与代码审查场景。

🎯 可自定义参数(6个)

编程语言
代码所使用的编程语言
代码内容
需要审查的完整代码或关键模块内容
代码目标描述
代码预期功能及业务目标的详细描述
安全标准/规范
遵循的安全标准或规范
已知漏洞示例
已知的漏洞示例以供对比分析
执行环境
代码执行的具体环境

🎨 效果示例

下面是针对这段 Flask/Python 代码的全面审查与改进建议,结合 OWASP Top 10 的问题分类,并给出可直接落地的修复版本示例,满足“基础登录与个人资料读取接口、支持记住登录体验与简单角色展示”的目标。

主要问题与风险(映射 OWASP Top 10)

  • 注入漏洞(A03: Injection)
    • 使用字符串拼接构造 SQL 导致 SQL 注入(f"WHERE username='{username}'")。
  • 认证缺陷(A07: Identification and Authentication Failures)
    • 明文密码比较,未使用安全哈希。
    • 基于 base64 的伪令牌,无签名、无过期、可伪造。
    • 不区分登录失败类型导致用户枚举(返回“user not found”与“wrong password”的差异)。
    • 未限制登录尝试次数,易暴力破解。
  • 敏感数据暴露(A02: Cryptographic Failures)
    • Cookie 未设置 HttpOnly/Secure,令牌可能被前端 JS 读取或在明文传输中被窃取。
    • SECRET 硬编码在代码里。
  • 安全配置不当(A05: Security Misconfiguration)
    • debug=True 在生产/演示中可能暴露内部信息。
    • 未规范响应状态码与错误信息。
    • 缺少日志与审计。
  • 会话管理不足(A07/A01)
    • 无过期控制、无注销接口、无会话旋转与刷新机制。
    • 不支持“记住登录”的明确生命周期控制。
  • 其他设计/实现问题
    • 数据库连接未显式关闭/上下文管理。
    • 错误处理不够稳健(base64 解码失败后默默置空)。
    • 接口输入未校验 content-type 或字段合法性。

改进目标与原则

  • 使用参数化查询防止注入。
  • 使用安全密码哈希(如 werkzeug.security 的 generate_password_hash/check_password_hash)。
  • 使用带签名与过期的令牌(JWT 或 itsdangerous),并设置安全 Cookie 属性。
  • 统一错误提示,避免用户枚举;实现登录尝试速率限制。
  • 支持“记住我”将会话生命周期延长,并提供注销接口。
  • 关闭 debug 于非本地测试;SECRET 从环境变量读取。
  • 尽量保持简单以满足“原型联调与演示”的需求。

参考修复实现示例(依赖:Flask、PyJWT、werkzeug.security) 说明:

  • 使用 JWT(HS256)签名,包含过期时间 exp。
  • 记住登录 remember=True 时将 cookie max_age 延长为 30 天,否则为会话时长(浏览器会话)。
  • 防暴力破解:简单的内存速率限制(可替换为 Flask-Limiter)。
  • 返回登录后角色;Profile 从令牌中读用户名与角色。
  • 安全 Cookie:HttpOnly=True,SameSite=Lax,Secure 在启用 HTTPS 时置为 True。
  • 统一错误信息为“invalid credentials”,避免用户枚举。

代码: import os import sqlite3 import datetime from flask import Flask, request, jsonify, make_response import jwt from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(name) app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'change-this-in-env') app.config['COOKIE_SECURE'] = os.getenv('COOKIE_SECURE', '0') == '1' # 在 HTTPS 环境设为 1 DB_PATH = 'app.db'

def get_db(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn

def get_user_by_username(username): with get_db() as conn: return conn.execute( "SELECT id, username, role, password_hash FROM users WHERE username = ?", (username,) ).fetchone()

def issue_token(user_id, username, role, remember=False): exp = datetime.datetime.utcnow() + (datetime.timedelta(days=30) if remember else datetime.timedelta(hours=8)) payload = {'sub': user_id, 'username': username, 'role': role, 'exp': exp} return jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')

简易登录尝试限制(IP+用户名),5次/5分钟

_attempts = {} ATTEMPT_WINDOW = 300 ATTEMPT_LIMIT = 5

def record_and_check_attempt(key): now = datetime.datetime.utcnow().timestamp() arr = [t for t in _attempts.get(key, []) if now - t < ATTEMPT_WINDOW] if len(arr) >= ATTEMPT_LIMIT: _attempts[key] = arr return True arr.append(now) _attempts[key] = arr return False

@app.route('/login', methods=['POST']) def login(): if not request.is_json: return jsonify({'ok': False, 'msg': 'invalid content type'}), 400 data = request.get_json() or {} username = (data.get('username') or '').strip() password = data.get('password') or '' remember = bool(data.get('remember', False))

if not username or not password:
    return jsonify({'ok': False, 'msg': 'invalid credentials'}), 401

key = f"{request.remote_addr}:{username}"
if record_and_check_attempt(key):
    return jsonify({'ok': False, 'msg': 'too many attempts'}), 429

user = get_user_by_username(username)
if not user or not check_password_hash(user['password_hash'], password):
    return jsonify({'ok': False, 'msg': 'invalid credentials'}), 401

token = issue_token(user['id'], user['username'], user['role'], remember)
resp = make_response(jsonify({'ok': True, 'role': user['role']}))
resp.set_cookie(
    'session',
    token,
    httponly=True,
    secure=app.config['COOKIE_SECURE'],
    samesite='Lax',
    max_age=30*24*3600 if remember else None
)
return resp

@app.route('/profile', methods=['GET']) def profile(): token = request.cookies.get('session', '') if not token: return jsonify({'ok': False, 'msg': 'no session'}), 401 try: payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256']) except jwt.ExpiredSignatureError: return jsonify({'ok': False, 'msg': 'session expired'}), 401 except jwt.InvalidTokenError: return jsonify({'ok': False, 'msg': 'invalid session'}), 401 return jsonify({'ok': True, 'user': payload.get('username'), 'role': payload.get('role')})

@app.route('/logout', methods=['POST']) def logout(): resp = make_response(jsonify({'ok': True})) resp.set_cookie('session', '', max_age=0) return resp

if name == 'main': # 仅限本地开发使用 debug;演示或生产禁用 app.run(debug=False)

数据库示例与密码哈希迁移

  • 建表示例:
    • CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, role TEXT NOT NULL );
  • 新增用户时使用 generate_password_hash(password) 存储哈希。
  • 旧数据为明文密码时的迁移:
    • 读取每条记录的明文密码,使用 generate_password_hash 生成哈希并更新 password_hash 字段,再删除旧密码字段。

进一步安全与设计建议

  • 使用 HTTPS 并将 COOKIE_SECURE 设为 True,避免令牌在明文传输中被窃取。
  • 考虑改用 Flask-Login 管理会话与“记住我”功能,自动处理 remember cookie 与 session 生命周期。
  • 对状态改变的接口(例如将来新增资料修改、密码修改)加入 CSRF 防护(SameSite=Lax 已缓解,但不替代 CSRF Token)。
  • 加入结构化安全日志(登录成功/失败、注销、异常),便于审计与监控(OWASP A09)。
  • 输入校验与速率限制更完备:
    • 用户名长度、字符集白名单。
    • 对 IP 与用户名分别限速。
    • 可集成 Flask-Limiter 或网关层限速。
  • 统一错误响应格式与状态码:
    • 认证失败统一返回 401 + “invalid credentials”,避免用户枚举。
    • 无权限访问返回 403,并在将来支持基于角色的访问控制。
  • 秘钥管理:
    • SECRET_KEY 从环境变量或安全密钥管理服务注入,不在代码中硬编码。
  • 令牌内容与校验:
    • 在原型阶段可将 role 放入 JWT 声明;若担心角色变更不同步,profile 可用 user_id 查询最新角色。
    • 考虑令牌轮换与刷新机制(短期访问令牌 + 长期刷新令牌)。
  • 禁用 debug 模式与Werkzeug调试器在任何非本地环境,避免敏感信息泄露。
  • 数据库连接池与异常处理:
    • 当前为原型可接受;生产建议使用更健壮的连接管理与错误重试。

通过上述修复与建议,模块将基本满足原型联调与演示的需求,并显著降低注入、认证与会话相关的安全风险,符合 OWASP Top 10 的核心防护要点。

总体问题与风险(结合CWE/SANS)

  • CWE-22/CWE-73 路径遍历与外部控制文件名:filename 直接拼接 path.join,攻击者可用 ../ 或包含分隔符的名字越权写入任意路径、覆盖现有文件或写入符号链接目标。
  • CWE-434/CWE-79 无限制上传与跨站脚本:未校验 MIME/扩展名,攻击者可上传 .html/.svg/.js 并在同源下被静态服务,造成存储型 XSS 或前端供应链风险。
  • CWE-400 资源消耗/DoS:未限制大小、并发与速率,长流或大文件可导致磁盘占满、连接耗尽。
  • CWE-306/CWE-311/CWE-778 无鉴权与无审计:任何人可上传;缺少身份信息与审计日志,不满足生产环境可追溯性。
  • CWE-200 信息泄露:将上传目录直接暴露在静态根下,若被误上传敏感文件(如配置、日志),可被直接读。
  • CWE-20 输入校验不足:未验证 Content-Type、文件结构,易触发业务逻辑绕过(例如用图片扩展但内容是脚本)。
  • 错误处理缺失:未监听 stream error/req aborted;finish 事件不足以覆盖异常,可能遗留半文件或悬挂请求。
  • 覆盖/链接攻击:可能覆盖已有文件;若目录内存在用户创建的符号链接,写入可跳转至系统敏感路径。
  • 设计问题:把“存储目录”与“对外根目录”混用;未设置安全响应头;对上传的同源访问缺少隔离策略。

满足目标的改进原则

  • 只允许明确白名单类型(头像/附件:常见为 JPEG/PNG/WebP/PDF),对内容进行魔数/MIME 双重校验。
  • 生成服务器端唯一安全文件名,不使用用户提供文件名;并防止覆盖(fs flags: wx)。
  • 限制文件大小、每请求文件数、上传速率与并发;处理连接中止;失败时清理临时文件。
  • 对上传目录单独挂载静态路由,设置安全响应头(nosniff、禁止 HTML/SVG inline 执行或强制下载)。
  • 增加鉴权、审计与速率限制;记录上传者、来源 IP、文件哈希、时间戳。
  • 防止路径遍历与符号链接利用;用真实路径前缀校验、忽略用户文件名输入。
  • 错误与异常统一处理,保证响应一致性。
  • 生产环境隔离建议:最好将上传资源放在独立子域名(static/uploads.example.com)以降低同源 XSS 影响。

参考修正版示例(保留流式上传,同时安全化) 说明:使用 busboy 进行 multipart/form-data 流式解析;白名单 MIME;随机文件名;大小限制;安全静态挂载;基础防护中间件与速率限制。若前端确实只发 application/octet-stream 原始流,也可以增加一个 /upload/raw 路由,逻辑相同并做长度限制。

const express = require('express'); const path = require('path'); const fs = require('fs'); const fsp = require('fs/promises'); const crypto = require('crypto'); const helmet = require('helmet'); const Busboy = require('busboy'); const { pipeline } = require('stream/promises'); const rateLimit = require('express-rate-limit');

const app = express();

app.disable('x-powered-by'); app.use(helmet({ contentSecurityPolicy: false })); // 可根据前端实际 CSP 配置开启 const UPLOADS_DIR = path.resolve(__dirname, 'public', 'uploads'); const STATIC_ROOT = path.resolve(__dirname, 'public');

// 白名单 MIME -> 扩展名 const ALLOWED = { 'image/jpeg': '.jpg', 'image/png': '.png', 'image/webp': '.webp', 'application/pdf': '.pdf' }; const MAX_SIZE = 10 * 1024 * 1024; // 10MB,按需调整

// 基础静态资源(非上传目录) app.use(express.static(STATIC_ROOT, { dotfiles: 'ignore', etag: true, fallthrough: true, setHeaders: (res) => { res.setHeader('X-Content-Type-Options', 'nosniff'); } }));

// 单独挂载上传目录,设置更严格头部 app.use('/uploads', express.static(UPLOADS_DIR, { dotfiles: 'ignore', etag: true, fallthrough: true, setHeaders: (res, filePath) => { res.setHeader('X-Content-Type-Options', 'nosniff'); const ext = path.extname(filePath).toLowerCase(); // 对非图片类附件强制下载,减少浏览器内执行风险 if (ext === '.pdf') { res.setHeader('Content-Disposition', 'attachment; filename="' + path.basename(filePath) + '"'); } } }));

// 简易鉴权中间件占位(替换为实际 JWT/Session 校验) function requireAuth(req, res, next) { // 示例:检查 Authorization Bearer 或 Cookie // if (!tokenIsValid(req)) return res.status(401).json({ ok: false, error: 'unauthorized' }); next(); }

// 速率限制,避免暴力 DoS const uploadLimiter = rateLimit({ windowMs: 60 * 1000, max: 30, standardHeaders: true, legacyHeaders: false });

// 确保上传目录存在 async function ensureUploadDir() { await fsp.mkdir(UPLOADS_DIR, { recursive: true, mode: 0o750 }); }

// 路由:安全化流式上传(multipart/form-data) app.post('/upload', requireAuth, uploadLimiter, async (req, res, next) => { try { const ctype = req.headers['content-type'] || ''; if (!ctype.startsWith('multipart/form-data')) { return res.status(415).json({ ok: false, error: 'multipart/form-data required' }); }

await ensureUploadDir();

const bb = Busboy({ headers: req.headers, limits: { files: 1, fileSize: MAX_SIZE } });
let responded = false;

bb.on('file', (name, file, info) => {
  const mime = info.mimeType;
  const ext = ALLOWED[mime];
  if (!ext) {
    file.resume();
    bb.emit('error', new Error('unsupported file type'));
    return;
  }

  const id = crypto.randomUUID();
  const filename = id + ext;
  const fullPath = path.join(UPLOADS_DIR, filename);
  const resolved = path.resolve(fullPath);
  const base = path.resolve(UPLOADS_DIR) + path.sep;
  if (!resolved.startsWith(base)) {
    file.resume();
    bb.emit('error', new Error('bad path'));
    return;
  }

  const out = fs.createWriteStream(resolved, { flags: 'wx', mode: 0o640 });

  pipeline(file, out)
    .then(() => {
      if (!responded) {
        responded = true;
        // 审计示例:可记录 req.user、IP、文件ID、mime、大小(Busboy info 有 size 近似)
        // auditLog({ user: req.user?.id, ip: req.ip, id, mime });
        res.json({ ok: true, path: '/uploads/' + filename });
      }
    })
    .catch(async (err) => {
      try { await fsp.unlink(resolved); } catch {}
      if (!responded) {
        responded = true;
        res.status(400).json({ ok: false, error: err.message });
      }
    });
});

bb.on('error', (err) => {
  if (!responded) {
    responded = true;
    res.status(400).json({ ok: false, error: err.message });
  }
});

bb.on('finish', () => {
  if (!responded) {
    responded = true;
    res.status(400).json({ ok: false, error: 'no file received' });
  }
});

req.on('aborted', () => {
  bb.removeAllListeners();
});

req.pipe(bb);

} catch (err) { next(err); } });

// 其他页面 app.get('/files', (req, res) => { res.sendFile(path.join(STATIC_ROOT, 'index.html')); });

// 统一错误处理中间件 app.use((err, req, res, next) => { // 生产环境可接入结构化日志 console.error(err); res.status(500).json({ ok: false, error: 'internal server error' }); });

app.listen(3000);

额外防护与运维建议

  • 同源隔离:把 /uploads 放在独立子域或 CDN 域(如 files.example.com),与主站分离,降低上传 HTML/SVG 被同源执行的风险(XSS)。
  • 更强校验与转码:
    • 对头像仅允许图片格式,并用图像库(如 sharp)重新解码/重编码,剥离可疑元数据,统一输出 JPG/PNG/WebP。
    • 对附件可做魔数检测(file-type 库)或病毒扫描(ClamAV)再入库。
  • 存储策略:将上传落盘到非静态可读目录,再通过受控下载接口返回资源;若必须走静态,确保只创建白名单扩展文件。
  • 访问控制与审计:
    • 上传操作需要鉴权(JWT/Session)与 CSRF 防护(若基于 Cookie);记录用户ID、时间、文件ID、IP、UA、哈希值。
    • 为下载接口或静态路由配置访问日志与监控告警(异常峰值、失败率、超大文件等)。
  • 配额与限速:按用户/租户设置磁盘配额与上传速率;在反向代理层(Nginx)也设置 client_max_body_size 与限流。
  • 处理符号链接与遍历:
    • 上传目录使用受控权限与所有者,禁止用户可写其父级;写前用 path.resolve 前缀校验;写后可 lstat 检查防止 symlink。
  • 安全响应头与CORS:
    • 通过 helmet 配置严格 CSP、Referrer-Policy、Permissions-Policy;按需配置 CORS 白名单。
  • TLS 与代理:仅通过 HTTPS;在反向代理设置超时、缓冲、限速;Express trust proxy 配置与真实客户端 IP 获取。
  • 备份与生命周期:定期清理过期文件;对临时失败上传进行清理;配套备份与恢复策略。
  • 测试与验证:覆盖路径遍历、扩展名假冒、魔数不匹配、超限、连接中止、并发冲突、符号链接攻击、XSS 注入(上传 HTML/SVG)等用例。

通过以上改造,可以在保持“前端流式上传、后端落盘并返回可访问 URL”的原型目标的同时,显著降低路径遍历、无限制上传、DoS、XSS、未鉴权等高危风险,符合生产环境的基本安全基线(CWE/SANS)。

以下是对当前 Go 代码的全面审查与改进建议,目标是让微服务在集成环境中以安全、快速的方式验证基本鉴权流程与错误处理,并符合常见安全规范(参考 CERT、OWASP API Security)。

一、主要问题与风险

  • 鉴权与令牌设计
    • 使用可预测且无签名的 base64("user:exp") 令牌,无法证明来源与完整性(可伪造、篡改)。
    • 未校验令牌过期、颁发者、受众、用途与不可重放标识(jti),易被重放和暴力尝试。
    • 采用非标准方案 Token 前缀,应使用标准 Authorization: Bearer。
  • 错误处理和返回
    • 对缺失令牌返回 401,而对无效令牌直接 403,且返回“missing token”可被用于枚举用户或接口状态。
    • 未设置 WWW-Authenticate 头导致客户端无法获得规范化的认证提示。
    • 返回纯文本,未设置 Content-Type,未使用统一的错误消息体结构。
  • 传输/服务端加固
    • 未启用 TLS(开发环境仍建议在网关或反向代理层保证 TLS)。
    • http.Server 未设置超时(ReadHeaderTimeout、ReadTimeout、WriteTimeout、IdleTimeout),易被慢速攻击拖垮。
    • 未限制最大头部大小或请求速率,缺少速率限制与审计,可能导致资源滥用。
  • 逻辑/设计问题
    • validateToken 对 parts 长度检查不严谨(len(parts) < 1 永远为假),且不检查第二段 exp。
    • 未对 Authorization 格式进行健壮处理(大小写、空白)。
    • ListenAndServe 的错误未处理(应 log.Fatal)。
    • 将用户值直接拼接输出,未来改为 JSON 更安全统一。
  • 可观测性与审计
    • 无结构化日志,无追踪 ID,无失败审计记录,不便定位与取证。
    • 未区分环境配置(密钥、ISS、AUD 等)。

二、威胁场景简述

  • 攻击者可自行构造 base64("attacker:any") 并通过鉴权,获取受保护数据。
  • 对/secure 进行暴力尝试或重放旧令牌,接口没有速率限制和过期判断,会导致未授权访问。
  • 利用慢速请求或大量头部,拖慢或阻塞服务。
  • 通过差异化错误消息与状态码,枚举接口和鉴权策略。

三、分阶段改进与修复建议(优先级从高到低)

  1. 替换令牌方案与验证
  • 使用标准 Bearer JWT(HS256 或 RS256)或不透明令牌+内省,切勿自制 base64 令牌。
  • 校验签名、exp/nbf/iat(含适当的 leeway)、iss、aud、sub,以及必要的 scope/role。
  • 仅允许预期算法(alg 白名单),拒绝 header 中算法降级。
  • 处理重放:校验 jti 并在 TTL 窗口内标记已使用(内存/Redis)。
  • 密钥管理:密钥从环境变量或配置管理平台加载,支持轮换;公钥从 JWKS 获取并缓存。
  1. 认证中间件与错误处理规范化
  • 使用 Authorization: Bearer ;缺失或无效均返回 401 并附带 WWW-Authenticate。
  • 统一返回结构化 JSON 错误,如 {code, message};避免泄漏内部细节。
  • 对用户可见信息不区分错误类型(避免枚举);详细原因只写入审计日志。
  1. 服务端加固
  • 设置 http.Server 的时限参数与头大小限制,减少资源耗尽攻击面。
  • 在反向代理或本服务启用 TLS(至少在集成环境走网关层 TLS)。
  • 增加每客户端速率限制(x/time/rate)与基础审计日志;避免记录令牌原文。
  1. 其他安全与工程实践
  • 安全响应头:Cache-Control: no-store, Content-Type: application/json;在网关层添加 HSTS, X-Content-Type-Options。
  • 采用中间件将鉴权状态置入上下文,业务处理只读取用户与权限。
  • 结构化日志(slog、zap),带请求ID/相关 ID;记录鉴权失败与异常。
  • 单元测试/集成测试:有效令牌、过期、提前生效(nbf)、错误算法、错误签名、速率限制触发。
  • 使用 go vet、gosec 等工具进行静态扫描。

四、参考实现(简化版,适用于集成环境演示) 说明:

  • 使用 HS256 JWT;生产建议 RS256 + JWKS。
  • 校验 exp、iss、aud、scope;统一 401 与 WWW-Authenticate。
  • 添加基本速率限制与 server 超时;结构化 JSON 响应与审计日志。
  • 不记录令牌原文,不暴露内部错误详情。

代码示例(可直接替换当前 main): package main

import ( "context" "encoding/json" "errors" "log" "net" "net/http" "os" "strings" "time"

"github.com/golang-jwt/jwt/v5"
"golang.org/x/time/rate"

)

type ctxKey string

var userKey ctxKey = "user"

type Claims struct { Scope string json:"scope" jwt.RegisteredClaims }

type apiError struct { Code string json:"code" Message string json:"message" }

func writeJSON(w http.ResponseWriter, status int, body any) { w.Header().Set("Content-Type", "application/json") w.Header().Set("Cache-Control", "no-store") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(body) }

func validateJWT(tok string, secret []byte) (string, error) { parser := jwt.NewParser( jwt.WithValidMethods([]string{"HS256"}), jwt.WithIssuedAt(), jwt.WithLeeway(60*time.Second), ) claims := &Claims{} _, err := parser.ParseWithClaims(tok, claims, func(t *jwt.Token) (any, error) { return secret, nil }) if err != nil { return "", err } // 颁发者/受众校验(根据你的环境调整) if claims.Issuer != "demo-issuer" { return "", errors.New("invalid iss") } if !claims.VerifyAudience("demo-aud", true) { return "", errors.New("invalid aud") } // scope 示例:要求 secure:read if claims.Scope != "secure:read" { return "", errors.New("insufficient scope") } // exp/nbf/iat 已由 parser 校验 return claims.Subject, nil }

type ipLimiter struct { limiters map[string]*rate.Limiter r rate.Limit b int }

func newIpLimiter(r rate.Limit, b int) *ipLimiter { return &ipLimiter{limiters: make(map[string]*rate.Limiter), r: r, b: b} }

func (l *ipLimiter) get(ip string) *rate.Limiter { if lim, ok := l.limiters[ip]; ok { return lim } lim := rate.NewLimiter(l.r, l.b) l.limiters[ip] = lim return lim }

func authMiddleware(next http.Handler, secret []byte, ipLim *ipLimiter) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ip, _, _ := net.SplitHostPort(r.RemoteAddr) if ip == "" { ip = "unknown" } if !ipLim.get(ip).Allow() { writeJSON(w, http.StatusTooManyRequests, apiError{Code: "rate_limited", Message: "too many requests"}) return }

	auth := strings.TrimSpace(r.Header.Get("Authorization"))
	if !strings.HasPrefix(auth, "Bearer ") {
		w.Header().Set("WWW-Authenticate", `Bearer realm="secure"`)
		writeJSON(w, http.StatusUnauthorized, apiError{Code: "unauthorized", Message: "invalid or missing token"})
		return
	}
	tok := strings.TrimSpace(strings.TrimPrefix(auth, "Bearer "))
	if tok == "" {
		w.Header().Set("WWW-Authenticate", `Bearer realm="secure"`)
		writeJSON(w, http.StatusUnauthorized, apiError{Code: "unauthorized", Message: "invalid or missing token"})
		return
	}

	user, err := validateJWT(tok, secret)
	if err != nil {
		// 审计日志:不记录 token 原文
		log.Printf("auth_failed ip=%s err=%v", ip, err)
		w.Header().Set("WWW-Authenticate", `Bearer error="invalid_token"`)
		writeJSON(w, http.StatusUnauthorized, apiError{Code: "unauthorized", Message: "invalid or missing token"})
		return
	}

	ctx := context.WithValue(r.Context(), userKey, user)
	next.ServeHTTP(w, r.WithContext(ctx))
})

}

func secureHandler(w http.ResponseWriter, r *http.Request) { user, _ := r.Context().Value(userKey).(string) writeJSON(w, http.StatusOK, map[string]string{ "message": "hello", "user": user, }) }

func main() { secret := []byte(os.Getenv("JWT_SECRET")) if len(secret) == 0 { log.Fatal("JWT_SECRET not set") }

mux := http.NewServeMux()
ipLim := newIpLimiter(5, 10) // 每秒约 5 次,突发 10 次,按需调整
mux.Handle("/secure", authMiddleware(http.HandlerFunc(secureHandler), secret, ipLim))

srv := &http.Server{
	Addr:              ":8080",
	Handler:           mux,
	ReadHeaderTimeout: 2 * time.Second,
	ReadTimeout:       5 * time.Second,
	WriteTimeout:      10 * time.Second,
	IdleTimeout:       60 * time.Second,
	// MaxHeaderBytes 可在需要时设置,例如 1<<20
}

log.Println("listening on :8080")
// 开发环境可用明文;集成/生产环境建议置于启用 TLS 的反向代理后
log.Fatal(srv.ListenAndServe())

}

五、与已知漏洞清单的对照修复

  • 未验证令牌签名与来源:改用 JWT 并强制签名、校验 iss/aud。
  • 未校验过期与重放:校验 exp/nbf/iat;增加 jti(需在发令系统与服务端同用存储)。
  • 可预测 base64 令牌:移除自制令牌,采用 Bearer JWT。
  • 错误信息可被枚举:统一 401 与通用消息,细节仅写入日志;设置 WWW-Authenticate。
  • 缺少速率限制与审计:加入每 IP 限流与失败审计日志。

六、进一步建议(按需实施)

  • 使用 RS256 与 JWKS(OIDC 提供商),减少对称密钥分发风险。
  • 将安全策略(issuer、audience、必需 scope)改为配置项;支持密钥轮换。
  • 在 API 网关层统一 TLS、WAF、HSTS 与额外速率限制。
  • 引入请求跟踪(X-Request-ID)、结构化日志(slog/zap)、Metrics(Prometheus)。
  • 安全测试与静态扫描:gosec、govulncheck、OWASP ZAP;添加单元与集成测试覆盖异常路径。

以上改造能在不牺牲“快速接入与演示”的前提下,使 /secure 的鉴权更接近标准实践,降低伪造、重放与资源耗尽风险,并提升错误处理与审计可用性。

示例详情

该提示词已被收录:
“程序员必备:提升开发效率的专业AI提示词合集”
让 AI 成为你的第二双手,从代码生成到测试文档全部搞定,节省 80% 开发时间
√ 立即可用 · 零学习成本
√ 参数化批量生成
√ 专业提示词工程师打磨

📖 如何使用

模式 1:即插即用(手动档)
直接复制参数化模版。手动修改 {{变量}} 即可快速发起对话,适合对结果有精准预期的单次任务。
加载中...
💬 模式 2:沉浸式引导(交互档)
一键转化为交互式脚本。AI 将化身专业面试官或顾问,主动询问并引导您提供关键信息,最终合成高度定制化的专业结果。
转为交互式
🚀 模式 3:原生指令自动化(智能档)
无需切换,输入 / 唤醒 8000+ 专家级提示词。 插件将全站提示词库深度集成于 Chat 输入框。基于当前对话语境,系统智能推荐最契合的 Prompt 并自动完成参数化,让海量资源触手可及,从此彻底告别“手动搬运”。
安装插件
🔌 发布为 API 接口
将 Prompt 接入自动化工作流,核心利用平台批量评价反馈引擎,实现"采集-评价-自动优化"的闭环。通过 RESTful 接口动态注入变量,让程序在批量任务中自动迭代出更高质量的提示词方案,实现 Prompt 的自我进化。
发布 API
🤖 发布为 Agent 应用
以此提示词为核心生成独立 Agent 应用,内嵌相关工具(图片生成、参数优化等),提供完整解决方案。
创建 Agent

🕒 版本历史

当前版本
v2.1 2024-01-15
优化输出结构,增强情节连贯性
  • ✨ 新增章节节奏控制参数
  • 🔧 优化人物关系描述逻辑
  • 📝 改进主题深化引导语
  • 🎯 增强情节转折点设计
v2.0 2023-12-20
重构提示词架构,提升生成质量
  • 🚀 全新的提示词结构设计
  • 📊 增加输出格式化选项
  • 💡 优化角色塑造引导
v1.5 2023-11-10
修复已知问题,提升稳定性
  • 🐛 修复长文本处理bug
  • ⚡ 提升响应速度
v1.0 2023-10-01
首次发布
  • 🎉 初始版本上线
COMING SOON
版本历史追踪,即将启航
记录每一次提示词的进化与升级,敬请期待。

💬 用户评价

4.8
⭐⭐⭐⭐⭐
基于 28 条评价
5星
85%
4星
12%
3星
3%
👤
电商运营 - 张先生
⭐⭐⭐⭐⭐ 2025-01-15
双十一用这个提示词生成了20多张海报,效果非常好!点击率提升了35%,节省了大量设计时间。参数调整很灵活,能快速适配不同节日。
效果好 节省时间
👤
品牌设计师 - 李女士
⭐⭐⭐⭐⭐ 2025-01-10
作为设计师,这个提示词帮我快速生成创意方向,大大提升了工作效率。生成的海报氛围感很强,稍作调整就能直接使用。
创意好 专业
COMING SOON
用户评价与反馈系统,即将上线
倾听真实反馈,在这里留下您的使用心得,敬请期待。
加载中...