×
¥
查看详情
🔥 会员专享 文生代码 开发者

代码安全审查

👁️ 757 次查看
📅 Nov 24, 2025
💡 核心价值: 针对指定代码进行安全审查,识别潜在漏洞与不良编码实践,并提供可执行的修复方案与安全编码建议,帮助开发团队提升代码安全性和可靠性,适用于安全评估和代码审查流程。

🎯 可自定义参数(4个)

编程语言
需要审查的代码所使用的编程语言
代码内容
需要审查的完整代码或关键模块内容
潜在漏洞类型
需要重点识别的潜在安全漏洞类型
安全标准/规范
参考的安全标准或规范

🎨 效果示例

以下是基于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:即插即用(手动档)
直接复制参数化模版。手动修改 {{变量}} 即可快速发起对话,适合对结果有精准预期的单次任务。
加载中...
💬 模式 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
用户评价与反馈系统,即将上线
倾听真实反馈,在这里留下您的使用心得,敬请期待。
加载中...