pdd-skills 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/README.md +1478 -0
  2. package/bin/pdd.js +354 -0
  3. package/config/bpmn-rules.yaml +166 -0
  4. package/config/checkstyle.xml +105 -0
  5. package/config/eslint.config.js +48 -0
  6. package/config/pmd.xml +91 -0
  7. package/config/prd-rules.yaml +113 -0
  8. package/config/ruff.toml +45 -0
  9. package/config/sqlfluff.cfg +82 -0
  10. package/hooks/hook-executor.js +332 -0
  11. package/index.js +43 -0
  12. package/lib/api-routes.js +750 -0
  13. package/lib/api-server.js +408 -0
  14. package/lib/cache/cache-config.js +209 -0
  15. package/lib/cache/system-cache.js +852 -0
  16. package/lib/config-manager.js +373 -0
  17. package/lib/generate.js +528 -0
  18. package/lib/grpc/grpc-routes.js +1134 -0
  19. package/lib/grpc/grpc-server.js +912 -0
  20. package/lib/grpc/proto-definitions.js +1033 -0
  21. package/lib/init.js +172 -0
  22. package/lib/iteration/auto-fixer.js +1025 -0
  23. package/lib/iteration/auto-reviewer.js +923 -0
  24. package/lib/iteration/controller.js +577 -0
  25. package/lib/list.js +130 -0
  26. package/lib/mcp-server.js +548 -0
  27. package/lib/openclaw/api-integration.js +535 -0
  28. package/lib/openclaw/cli-integration.js +567 -0
  29. package/lib/openclaw/data-sync.js +845 -0
  30. package/lib/openclaw/openclaw-adapter.js +783 -0
  31. package/lib/plugin/example-plugins/code-stats/index.js +332 -0
  32. package/lib/plugin/example-plugins/code-stats/plugin.json +1 -0
  33. package/lib/plugin/example-plugins/custom-linter/index.js +472 -0
  34. package/lib/plugin/example-plugins/custom-linter/plugin.json +1 -0
  35. package/lib/plugin/example-plugins/hello-world/index.js +86 -0
  36. package/lib/plugin/example-plugins/hello-world/plugin.json +1 -0
  37. package/lib/plugin/plugin-manager.js +655 -0
  38. package/lib/plugin/plugin-sdk.js +565 -0
  39. package/lib/plugin/sandbox.js +627 -0
  40. package/lib/quality/rules/maintainability.js +418 -0
  41. package/lib/quality/rules/performance.js +498 -0
  42. package/lib/quality/rules/readability.js +441 -0
  43. package/lib/quality/rules/robustness.js +504 -0
  44. package/lib/quality/rules/security.js +444 -0
  45. package/lib/quality/scorer.js +576 -0
  46. package/lib/report.js +669 -0
  47. package/lib/sdk-base.js +301 -0
  48. package/lib/sdk-js.js +446 -0
  49. package/lib/sdk-python/README.md +546 -0
  50. package/lib/sdk-python/examples/basic_usage.py +450 -0
  51. package/lib/sdk-python/pdd_sdk/__init__.py +180 -0
  52. package/lib/sdk-python/pdd_sdk/client.py +1170 -0
  53. package/lib/sdk-python/pdd_sdk/events.py +423 -0
  54. package/lib/sdk-python/pdd_sdk/exceptions.py +158 -0
  55. package/lib/sdk-python/pdd_sdk/models.py +518 -0
  56. package/lib/sdk-python/pdd_sdk/utils.py +759 -0
  57. package/lib/token/budget-alert.js +367 -0
  58. package/lib/token/budget-manager.js +485 -0
  59. package/lib/update.js +54 -0
  60. package/lib/utils/logger.js +88 -0
  61. package/lib/verify.js +741 -0
  62. package/lib/version.js +52 -0
  63. package/lib/vm/README.md +102 -0
  64. package/lib/vm/dashboard/api-routes.js +669 -0
  65. package/lib/vm/dashboard/server.js +391 -0
  66. package/lib/vm/dashboard/sse.js +358 -0
  67. package/lib/vm/dashboard/static/css/dashboard.css +1378 -0
  68. package/lib/vm/dashboard/static/index.html +118 -0
  69. package/lib/vm/dashboard/static/js/app.js +949 -0
  70. package/lib/vm/dashboard/static/js/charts.js +913 -0
  71. package/lib/vm/dashboard/static/js/kanban-view.js +1053 -0
  72. package/lib/vm/dashboard/static/js/pipeline-view.js +463 -0
  73. package/lib/vm/dashboard/static/js/quality-view.js +598 -0
  74. package/lib/vm/dashboard/static/js/system-view.js +1021 -0
  75. package/lib/vm/data-provider.js +1191 -0
  76. package/lib/vm/event-bus.js +402 -0
  77. package/lib/vm/hooks/extract-hook.js +307 -0
  78. package/lib/vm/hooks/generate-hook.js +374 -0
  79. package/lib/vm/hooks/hook-interface.js +458 -0
  80. package/lib/vm/hooks/report-hook.js +331 -0
  81. package/lib/vm/hooks/verify-hook.js +454 -0
  82. package/lib/vm/models.js +1003 -0
  83. package/lib/vm/reconciler.js +855 -0
  84. package/lib/vm/scanner.js +988 -0
  85. package/lib/vm/state-schema.js +955 -0
  86. package/lib/vm/state-store.js +733 -0
  87. package/lib/vm/tui/components/card.js +339 -0
  88. package/lib/vm/tui/components/progress-bar.js +368 -0
  89. package/lib/vm/tui/components/sparkline.js +327 -0
  90. package/lib/vm/tui/components/status-light.js +294 -0
  91. package/lib/vm/tui/components/table.js +370 -0
  92. package/lib/vm/tui/input.js +335 -0
  93. package/lib/vm/tui/renderer.js +548 -0
  94. package/lib/vm/tui/screens/kanban-screen.js +397 -0
  95. package/lib/vm/tui/screens/overview-screen.js +357 -0
  96. package/lib/vm/tui/screens/quality-screen.js +336 -0
  97. package/lib/vm/tui/screens/system-screen.js +379 -0
  98. package/lib/vm/tui/tui.js +805 -0
  99. package/package.json +1 -0
  100. package/scripts/cso-analyzer.js +198 -0
  101. package/scripts/eval-runner.js +359 -0
  102. package/scripts/i18n-checker.js +109 -0
  103. package/scripts/linter/activiti-linter.js +272 -0
  104. package/scripts/linter/prd-linter.js +162 -0
  105. package/scripts/linter/report-generator.js +207 -0
  106. package/scripts/linter/run-linters.js +285 -0
  107. package/scripts/linter/sql-linter.js +166 -0
  108. package/scripts/token-analyzer.js +162 -0
  109. package/scripts/vm-test.js +180 -0
  110. package/skills/core/official-doc-writer/LICENSE +21 -0
  111. package/skills/core/official-doc-writer/README.md +232 -0
  112. package/skills/core/official-doc-writer/SKILL.md +475 -0
  113. package/skills/core/official-doc-writer/_meta.json +1 -0
  114. package/skills/core/official-doc-writer/document_generator.py +580 -0
  115. package/skills/core/official-doc-writer/evals/default-evals.json +1 -0
  116. package/skills/core/official-doc-writer/examples.md +150 -0
  117. package/skills/core/official-doc-writer/fonts/FONTS_LIST.md +45 -0
  118. package/skills/core/official-doc-writer/fonts/README.md +141 -0
  119. package/skills/core/official-doc-writer/fonts/SIMFANG.TTF +0 -0
  120. package/skills/core/official-doc-writer/fonts/SIMHEI.TTF +0 -0
  121. package/skills/core/official-doc-writer/fonts/SIMKAI.TTF +0 -0
  122. package/skills/core/official-doc-writer/fonts/SIMSUN.TTC +0 -0
  123. package/skills/core/official-doc-writer/fonts//346/226/271/346/255/243/345/260/217/346/240/207/345/256/213GBK.TTF +0 -0
  124. package/skills/core/official-doc-writer/references/GBT_9704-2012_/345/205/232/346/224/277/346/234/272/345/205/263/345/205/254/346/226/207/346/240/274/345/274/217.md +422 -0
  125. package/skills/core/official-doc-writer/scripts/__pycache__/generate_official_doc.cpython-313.pyc +0 -0
  126. package/skills/core/official-doc-writer/scripts/dialog_manager.py +564 -0
  127. package/skills/core/official-doc-writer/scripts/generate_official_doc.py +252 -0
  128. package/skills/core/official-doc-writer/scripts/install_fonts.py +390 -0
  129. package/skills/core/official-doc-writer/scripts/smart_prompts.py +363 -0
  130. package/skills/core/pdd-ba/SKILL.md +305 -0
  131. package/skills/core/pdd-ba/_meta.json +1 -0
  132. package/skills/core/pdd-ba/evals/default-evals.json +1 -0
  133. package/skills/core/pdd-code-reviewer/SKILL.md +378 -0
  134. package/skills/core/pdd-code-reviewer/_meta.json +1 -0
  135. package/skills/core/pdd-code-reviewer/evals/default-evals.json +1 -0
  136. package/skills/core/pdd-doc-change/SKILL.md +350 -0
  137. package/skills/core/pdd-doc-change/_meta.json +1 -0
  138. package/skills/core/pdd-doc-change/evals/default-evals.json +1 -0
  139. package/skills/core/pdd-doc-gardener/SKILL.md +248 -0
  140. package/skills/core/pdd-doc-gardener/_meta.json +1 -0
  141. package/skills/core/pdd-doc-gardener/evals/default-evals.json +1 -0
  142. package/skills/core/pdd-entropy-reduction/SKILL.md +360 -0
  143. package/skills/core/pdd-entropy-reduction/_meta.json +1 -0
  144. package/skills/core/pdd-entropy-reduction/evals/default-evals.json +1 -0
  145. package/skills/core/pdd-entropy-reduction/references/entropy-report-template.md +287 -0
  146. package/skills/core/pdd-entropy-reduction/references/golden-principles.md +573 -0
  147. package/skills/core/pdd-entropy-reduction/scripts/entropy_scan.py +712 -0
  148. package/skills/core/pdd-extract-features/SKILL.md +320 -0
  149. package/skills/core/pdd-extract-features/_meta.json +1 -0
  150. package/skills/core/pdd-extract-features/evals/default-evals.json +1 -0
  151. package/skills/core/pdd-generate-spec/SKILL.md +418 -0
  152. package/skills/core/pdd-generate-spec/_meta.json +1 -0
  153. package/skills/core/pdd-generate-spec/evals/default-evals.json +1 -0
  154. package/skills/core/pdd-implement-feature/SKILL.md +332 -0
  155. package/skills/core/pdd-implement-feature/_meta.json +1 -0
  156. package/skills/core/pdd-implement-feature/evals/default-evals.json +1 -0
  157. package/skills/core/pdd-main/SKILL.md +540 -0
  158. package/skills/core/pdd-main/_meta.json +1 -0
  159. package/skills/core/pdd-main/evals/default-evals.json +1 -0
  160. package/skills/core/pdd-main/evals/evals.json +215 -0
  161. package/skills/core/pdd-verify-feature/SKILL.md +474 -0
  162. package/skills/core/pdd-verify-feature/_meta.json +1 -0
  163. package/skills/core/pdd-verify-feature/evals/default-evals.json +1 -0
  164. package/skills/core/pdd-vm/evals/default-evals.json +1 -0
  165. package/skills/core/traffic-accident-assessor/LICENSE +29 -0
  166. package/skills/core/traffic-accident-assessor/SKILL.md +439 -0
  167. package/skills/core/traffic-accident-assessor/evals/evals.json +1 -0
  168. package/skills/core/traffic-accident-assessor/references/accident-types.md +369 -0
  169. package/skills/core/traffic-accident-assessor/references/liability-rules.md +287 -0
  170. package/skills/core/traffic-accident-assessor/references/traffic-laws.md +226 -0
  171. package/skills/core/traffic-accident-assessor/references//351/253/230/345/260/224/345/244/253/350/257/264/346/230/216/344/271/246.pdf +32576 -106
  172. package/skills/core/traffic-accident-assessor/scripts/generate_official_statement.py +588 -0
  173. package/skills/core/traffic-accident-assessor/scripts/generate_report.py +495 -0
  174. package/skills/core/traffic-accident-assessor/scripts/generate_statement.py +528 -0
  175. package/skills/core/traffic-accident-assessor.zip +0 -0
  176. package/skills/entropy/expert-arch-enforcer/SKILL.md +292 -0
  177. package/skills/entropy/expert-arch-enforcer/_meta.json +1 -0
  178. package/skills/entropy/expert-arch-enforcer/evals/default-evals.json +1 -0
  179. package/skills/entropy/expert-auto-refactor/SKILL.md +327 -0
  180. package/skills/entropy/expert-auto-refactor/_meta.json +1 -0
  181. package/skills/entropy/expert-auto-refactor/evals/default-evals.json +1 -0
  182. package/skills/entropy/expert-code-quality/SKILL.md +468 -0
  183. package/skills/entropy/expert-code-quality/_meta.json +1 -0
  184. package/skills/entropy/expert-code-quality/evals/default-evals.json +1 -0
  185. package/skills/entropy/expert-code-quality/evals/evals.json +109 -0
  186. package/skills/entropy/expert-code-quality/references/code-smells.md +605 -0
  187. package/skills/entropy/expert-code-quality/references/design-patterns.md +1111 -0
  188. package/skills/entropy/expert-code-quality/references/refactoring-catalog.md +1281 -0
  189. package/skills/entropy/expert-code-quality/references/solid-principles.md +524 -0
  190. package/skills/entropy/expert-entropy-auditor/SKILL.md +276 -0
  191. package/skills/entropy/expert-entropy-auditor/_meta.json +1 -0
  192. package/skills/entropy/expert-entropy-auditor/evals/default-evals.json +1 -0
  193. package/skills/expert/expert-activiti/SKILL.md +497 -0
  194. package/skills/expert/expert-activiti/_meta.json +1 -0
  195. package/skills/expert/expert-mysql/SKILL.md +832 -0
  196. package/skills/expert/expert-mysql/_meta.json +1 -0
  197. package/skills/expert/expert-performance/SKILL.md +379 -0
  198. package/skills/expert/expert-performance/_meta.json +1 -0
  199. package/skills/expert/expert-performance/evals/default-evals.json +1 -0
  200. package/skills/expert/expert-ruoyi/SKILL.md +472 -0
  201. package/skills/expert/expert-ruoyi/_meta.json +1 -0
  202. package/skills/expert/expert-security/SKILL.md +1341 -0
  203. package/skills/expert/expert-security/_meta.json +1 -0
  204. package/skills/expert/expert-security/evals/default-evals.json +1 -0
  205. package/skills/expert/software-architect/SKILL.md +350 -0
  206. package/skills/expert/software-architect/_meta.json +1 -0
  207. package/skills/expert/software-engineer/SKILL.md +437 -0
  208. package/skills/expert/software-engineer/_meta.json +1 -0
  209. package/skills/expert/software-engineer/architecture.md +130 -0
  210. package/skills/expert/software-engineer/patterns.md +151 -0
  211. package/skills/expert/software-engineer/testing.md +135 -0
  212. package/skills/expert/system-architect/SKILL.md +628 -0
  213. package/skills/expert/system-architect/_meta.json +1 -0
  214. package/skills/expert/system-architect/assets/templates/ARCHITECTURE.md +25 -0
  215. package/skills/expert/system-architect/assets/templates/README.md +44 -0
  216. package/skills/expert/system-architect/references/js-ts-standards.md +18 -0
  217. package/skills/expert/system-architect/references/python-standards.md +19 -0
  218. package/skills/expert/system-architect/references/scaffolding.md +61 -0
  219. package/skills/expert/system-architect/references/security-checklist.md +21 -0
  220. package/skills/openspec/openspec-apply-change/SKILL.md +156 -0
  221. package/skills/openspec/openspec-apply-change/_meta.json +1 -0
  222. package/skills/openspec/openspec-archive-change/SKILL.md +114 -0
  223. package/skills/openspec/openspec-archive-change/_meta.json +1 -0
  224. package/skills/openspec/openspec-bulk-archive-change/SKILL.md +246 -0
  225. package/skills/openspec/openspec-bulk-archive-change/_meta.json +1 -0
  226. package/skills/openspec/openspec-continue-change/SKILL.md +118 -0
  227. package/skills/openspec/openspec-continue-change/_meta.json +1 -0
  228. package/skills/openspec/openspec-explore/SKILL.md +288 -0
  229. package/skills/openspec/openspec-explore/_meta.json +1 -0
  230. package/skills/openspec/openspec-ff-change/SKILL.md +101 -0
  231. package/skills/openspec/openspec-ff-change/_meta.json +1 -0
  232. package/skills/openspec/openspec-new-change/SKILL.md +74 -0
  233. package/skills/openspec/openspec-new-change/_meta.json +1 -0
  234. package/skills/openspec/openspec-onboard/SKILL.md +554 -0
  235. package/skills/openspec/openspec-onboard/_meta.json +1 -0
  236. package/skills/openspec/openspec-sync-specs/SKILL.md +138 -0
  237. package/skills/openspec/openspec-sync-specs/_meta.json +1 -0
  238. package/skills/openspec/openspec-verify-change/SKILL.md +168 -0
  239. package/skills/openspec/openspec-verify-change/_meta.json +1 -0
  240. package/skills/pr/pdd-multi-review/SKILL.md +534 -0
  241. package/skills/pr/pdd-multi-review/_meta.json +1 -0
  242. package/skills/pr/pdd-pr-batch/SKILL.md +303 -0
  243. package/skills/pr/pdd-pr-batch/_meta.json +1 -0
  244. package/skills/pr/pdd-pr-create/SKILL.md +344 -0
  245. package/skills/pr/pdd-pr-create/_meta.json +1 -0
  246. package/skills/pr/pdd-pr-merge/SKILL.md +286 -0
  247. package/skills/pr/pdd-pr-merge/_meta.json +1 -0
  248. package/skills/pr/pdd-pr-review/SKILL.md +217 -0
  249. package/skills/pr/pdd-pr-review/_meta.json +1 -0
  250. package/skills/pr/pdd-task-manager/SKILL.md +636 -0
  251. package/skills/pr/pdd-task-manager/_meta.json +1 -0
  252. package/skills/pr/pdd-template-engine/SKILL.md +306 -0
  253. package/skills/pr/pdd-template-engine/_meta.json +1 -0
  254. package/templates/behavior-shaping/iron-law-template.md +87 -0
  255. package/templates/behavior-shaping/rationalization-template.md +62 -0
  256. package/templates/behavior-shaping/red-flags-template.md +70 -0
  257. package/templates/bilingual-template.md +139 -0
  258. package/templates/config/default.yaml +47 -0
  259. package/templates/project/default/README.md +31 -0
  260. package/templates/project/frontend/README.md +46 -0
  261. package/templates/project/java/README.md +48 -0
@@ -0,0 +1,1341 @@
1
+ ---
2
+ name: expert-security
3
+ description: |
4
+ 安全专家提供代码漏洞扫描、OWASP Top 10合规检查和安全编码建议。
5
+ 当用户需要安全审计、漏洞扫描或安全编码时调用。Security expert for
6
+ vulnerability scanning, OWASP compliance, secure coding. Invoke for security audit.
7
+ license: MIT
8
+ author: "neuqik@hotmail.com"
9
+ version: "1.0.0"
10
+ triggers:
11
+ - "安全审计"
12
+ - "漏洞扫描"
13
+ - "安全编码"
14
+ ---
15
+
16
+ # Security Expert / 安全专家
17
+
18
+ ## Core Concept / 核心概念
19
+
20
+ ### 🇨🇳
21
+ 安全专家是系统的"数字守卫",通过主动防御和被动检测相结合的方式,
22
+ 识别并修复代码中的安全漏洞,确保系统符合OWASP Top 10安全标准,
23
+ 保护用户数据和业务资产免受攻击威胁。
24
+
25
+ ### 🇺🇸
26
+ The security expert acts as the system's "digital guardian," combining proactive defense
27
+ with passive detection to identify and remediate code vulnerabilities, ensuring OWASP Top 10
28
+ compliance, and protecting user data and business assets from attack threats.
29
+
30
+ ---
31
+
32
+ ## Core Capabilities / 核心能力
33
+
34
+ ### 1. 代码漏洞扫描 (Code Vulnerability Scanning)
35
+
36
+ #### 1.1 SQL注入检测与修复 / SQL Injection Detection & Remediation
37
+
38
+ **🇨🇳 攻击场景分析**
39
+
40
+ ```java
41
+ // ❌ VULNERABLE: 拼接SQL - 易受SQL注入攻击
42
+ @GetMapping("/users/search")
43
+ public List<User> searchUser(@RequestParam String keyword) {
44
+ String sql = "SELECT * FROM sys_user WHERE user_name LIKE '%" + keyword + "%'";
45
+ return jdbcTemplate.queryForList(sql);
46
+ }
47
+
48
+ // ✅ SECURE: 使用PreparedStatement参数化查询
49
+ @GetMapping("/users/search")
50
+ public List<User> searchUserSecure(@RequestParam String keyword) {
51
+ String sql = "SELECT * FROM sys_user WHERE user_name LIKE ?";
52
+ return jdbcTemplate.queryForList(sql, "%" + keyword + "%");
53
+ }
54
+ ```
55
+
56
+ **🇺🇸 Attack Scenario Analysis**
57
+
58
+ | Attack Vector | Example Payload | Impact | Severity |
59
+ |--------------|----------------|--------|----------|
60
+ | Authentication Bypass | `' OR '1'='1` | Full database access | CRITICAL |
61
+ | Data Extraction | `' UNION SELECT * FROM sys_user--` | Sensitive data leak | CRITICAL |
62
+ | Data Manipulation | `'; DROP TABLE sys_user;--` | Data destruction | CRITICAL |
63
+ | Blind Injection | `' AND 1=CAST((SELECT password FROM sys_user LIMIT 1) AS INT)--` | Information disclosure | HIGH |
64
+
65
+ **MyBatis安全配置示例 / MyBatis Secure Configuration:**
66
+
67
+ ```xml
68
+ <!-- ❌ VULNERABLE: ${} 拼接 -->
69
+ <select id="getUserByName" resultType="SysUser">
70
+ SELECT * FROM sys_user WHERE user_name = '${userName}'
71
+ </select>
72
+
73
+ <!-- ✅ SECURE: #{} 参数化 -->
74
+ <select id="getUserByName" resultType="SysUser">
75
+ SELECT * FROM sys_user WHERE user_name = #{userName}
76
+ </select>
77
+ ```
78
+
79
+ #### 1.2 XSS跨站脚本防护 / XSS Cross-Site Scripting Protection
80
+
81
+ **🇨🏳 攻击类型分类 / Attack Type Classification**
82
+
83
+ | 类型 | 示例 | 防护策略 |
84
+ |------|------|---------|
85
+ | Reflected XSS | `<script>alert('XSS')</script>` | 输出转义 + CSP |
86
+ | Stored XSS | `<img src=x onerror=alert(1)>` | 输入过滤 + 输出编码 |
87
+ | DOM-based XSS | `javascript:alert(document.cookie)` | DOM操作安全 + 输入验证 |
88
+
89
+ **Spring Boot防护配置 / Spring Boot Protection Configuration:**
90
+
91
+ ```java
92
+ // 1. 全局XSS过滤器
93
+ @Component
94
+ @Order(Ordered.HIGHEST_PRECEDENCE)
95
+ public class XssFilter implements Filter {
96
+
97
+ @Override
98
+ public void doFilter(ServletRequest request, ServletResponse response,
99
+ FilterChain chain) throws IOException, ServletException {
100
+ XssHttpServletRequestWrapper xssRequest =
101
+ new XssHttpServletRequestWrapper((HttpServletRequest) request);
102
+ chain.doFilter(xssRequest, response);
103
+ }
104
+ }
105
+
106
+ // 2. HTML转义工具类
107
+ public class HtmlUtils {
108
+ private static final Pattern[] PATTERNS = {
109
+ Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
110
+ Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\'",
111
+ Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
112
+ Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
113
+ Pattern.compile("<script(.*?)>",
114
+ Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
115
+ Pattern.compile("eval\\((.*?)\\)",
116
+ Pattern.CASE_INSENSITIVE | Pattern.MULTILINE),
117
+ Pattern.compile("expression\\((.*?)\\)",
118
+ Pattern.CASE_INSENSITIVE | Pattern.MULTILINE)
119
+ };
120
+
121
+ public static String clean(String input) {
122
+ if (input == null) return null;
123
+ String result = input;
124
+ for (Pattern pattern : PATTERNS) {
125
+ result = pattern.matcher(result).replaceAll("");
126
+ }
127
+ return result;
128
+ }
129
+ }
130
+ ```
131
+
132
+ #### 1.3 CSRF跨站请求伪造防护 / CSRF Cross-Site Request Forgery Protection
133
+
134
+ **🇨🇳 Spring Boot CSRF防御方案 / 🇺🇸 Spring Boot CSRF Defense Solution:**
135
+
136
+ ```java
137
+ // 1. 启用CSRF保护
138
+ @Configuration
139
+ @EnableWebSecurity
140
+ public class SecurityConfig {
141
+
142
+ @Bean
143
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
144
+ http
145
+ // 启用CSRF保护
146
+ .csrf(csrf -> csrf
147
+ .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
148
+ .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())
149
+ )
150
+ // 配置需要保护的端点
151
+ .authorizeHttpRequests(auth -> auth
152
+ .requestMatchers("/api/**").authenticated()
153
+ .anyRequest().permitAll()
154
+ );
155
+ return http.build();
156
+ }
157
+ }
158
+
159
+ // 2. 前端CSRF Token处理(Thymeleaf示例)
160
+ <meta name="_csrf" th:content="${_csrf.token}"/>
161
+ <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
162
+
163
+ <script>
164
+ // AJAX请求自动添加CSRF Token
165
+ $(document).ajaxSend(function(e, xhr, options) {
166
+ var token = $("meta[name='_csrf']").attr("content");
167
+ var header = $("meta[name='_csrf_header']").attr("content");
168
+ xhr.setRequestHeader(header, token);
169
+ });
170
+ </script>
171
+ ```
172
+
173
+ #### 1.4 命令注入防护 / Command Injection Prevention
174
+
175
+ **🇨🇳 危险场景示例 / 🇺🇸 Dangerous Scenario Examples:**
176
+
177
+ ```java
178
+ // ❌ VULNERABLE: 直接拼接命令
179
+ Runtime.getRuntime().exec("ping " + ipAddress);
180
+
181
+ // ✅ SECURE: 白名单验证 + 参数化执行
182
+ public boolean pingHost(String ipAddress) {
183
+ // IP地址格式验证
184
+ if (!isValidIpAddress(ipAddress)) {
185
+ throw new IllegalArgumentException("Invalid IP address format");
186
+ }
187
+
188
+ // 使用白名单字符集
189
+ if (!ipAddress.matches("^[0-9.]+$")) {
190
+ throw new SecurityException("Invalid characters in IP address");
191
+ }
192
+
193
+ ProcessBuilder pb = new ProcessBuilder("ping", "-c", "4", ipAddress);
194
+ // 执行命令...
195
+ }
196
+
197
+ private boolean isValidIpAddress(String ip) {
198
+ String ipPattern = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}"
199
+ + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
200
+ return ip.matches(ipPattern);
201
+ }
202
+ ```
203
+
204
+ #### 1.5 路径遍历防护 / Path Traversal Prevention
205
+
206
+ ```java
207
+ // ❌ VULNERABLE: 未验证路径
208
+ @GetMapping("/files/download")
209
+ public ResponseEntity<Resource> downloadFile(@RequestParam String filename) {
210
+ Path path = Paths.get("/uploads/" + filename);
211
+ Resource resource = new UrlResource(path.toUri());
212
+ return ResponseEntity.ok().body(resource);
213
+ }
214
+
215
+ // ✅ SECURE: 规范化路径 + 白名单验证
216
+ @GetMapping("/files/download")
217
+ public ResponseEntity<Resource> downloadFileSecure(@RequestParam String filename) {
218
+ try {
219
+ // 验证文件名不包含路径遍历字符
220
+ if (filename.contains("..") || filename.contains("/") || filename.contains("\\")) {
221
+ throw new SecurityException("Invalid filename");
222
+ }
223
+
224
+ // 规范化路径并验证在允许目录内
225
+ Path basePath = Paths.get("/uploads/").normalize().toAbsolutePath();
226
+ Path filePath = basePath.resolve(filename).normalize();
227
+
228
+ if (!filePath.startsWith(basePath)) {
229
+ throw new SecurityException("Path traversal attempt detected");
230
+ }
231
+
232
+ Resource resource = new UrlResource(filePath.toUri());
233
+ if (resource.exists()) {
234
+ return ResponseEntity.ok()
235
+ .header(HttpHeaders.CONTENT_DISPOSITION,
236
+ "attachment; filename=\"" + resource.getFilename() + "\"")
237
+ .body(resource);
238
+ }
239
+ return ResponseEntity.notFound().build();
240
+ } catch (IOException e) {
241
+ return ResponseEntity.badRequest().build();
242
+ }
243
+ }
244
+ ```
245
+
246
+ ---
247
+
248
+ ### 2. 认证与授权安全 (Authentication & Authorization)
249
+
250
+ #### 2.1 身份认证安全 (JWT/Session)
251
+
252
+ **🇨🇳 JWT安全最佳实践 / 🇺🇸 JWT Security Best Practices:**
253
+
254
+ ```java
255
+ // JWT工具类 - 安全实现
256
+ @Component
257
+ public class JwtTokenUtil {
258
+
259
+ @Value("${jwt.secret}")
260
+ private String secret;
261
+
262
+ @Value("${jwt.expiration:86400000}")
263
+ private long expiration;
264
+
265
+ // 使用强密钥生成算法
266
+ private SecretKey getSigningKey() {
267
+ byte[] keyBytes = Decoders.BASE64.decode(secret);
268
+ return Keys.hmacShaKeyFor(keyBytes);
269
+ }
270
+
271
+ public String generateToken(UserDetails userDetails) {
272
+ Map<String, Object> claims = new HashMap<>();
273
+ claims.put("roles", userDetails.getAuthorities());
274
+ claims.put("created", new Date());
275
+
276
+ return Jwts.builder()
277
+ .setClaims(claims)
278
+ .setSubject(userDetails.getUsername())
279
+ .setIssuedAt(new Date())
280
+ .setExpiration(new Date(System.currentTimeMillis() + expiration))
281
+ .signWith(getSigningKey(), SignatureAlgorithm.HS256)
282
+ .compact();
283
+ }
284
+
285
+ public Boolean validateToken(String token, UserDetails userDetails) {
286
+ final String username = getUsernameFromToken(token);
287
+ return (username.equals(userDetails.getUsername())
288
+ && !isTokenExpired(token));
289
+ }
290
+
291
+ // Token黑名单检查(用于注销功能)
292
+ @Autowired
293
+ private RedisTemplate<String, String> redisTemplate;
294
+
295
+ public boolean isTokenBlacklisted(String token) {
296
+ return Boolean.TRUE.equals(redisTemplate.hasKey("blacklist:" + token));
297
+ }
298
+ }
299
+ ```
300
+
301
+ **Session安全管理 / Session Security Management:**
302
+
303
+ ```properties
304
+ # application.yml - Session安全配置
305
+ server:
306
+ servlet:
307
+ session:
308
+ cookie:
309
+ http-only: true # 防止JavaScript访问Cookie
310
+ secure: true # 仅HTTPS传输
311
+ same-site: strict # 防止CSRF攻击
312
+ timeout: 30m # 会话超时时间
313
+ ```
314
+
315
+ #### 2.2 权限控制 (RBAC/ABAC)
316
+
317
+ **🇨🇳 若依框架RBAC注解示例 / 🇺🇸 RuoYi Framework RBAC Annotation Example:**
318
+
319
+ ```java
320
+ @RestController
321
+ @RequestMapping("/system/user")
322
+ public class SysUserController extends BaseController {
323
+
324
+ @PreAuthorize("@ss.hasPermi('system:user:list')")
325
+ @GetMapping("/list")
326
+ public TableDataInfo list(SysUser user) {
327
+ startPage();
328
+ List<SysUser> list = userService.selectUserList(user);
329
+ return getDataTable(list);
330
+ }
331
+
332
+ @PreAuthorize("@ss.hasPermi('system:user:query')")
333
+ @GetMapping(value = "/{userId}")
334
+ public AjaxResult getInfo(@PathVariable Long userId) {
335
+ userService.checkUserDataScope(userId);
336
+ return success(userService.selectUserById(userId));
337
+ }
338
+
339
+ @PreAuthorize("@ss.hasPermi('system:user:add')")
340
+ @Log(title = "用户管理", businessType = BusinessType.INSERT)
341
+ @PostMapping
342
+ public AjaxResult add(@RequestBody SysUser user) {
343
+ // 数据权限校验
344
+ if (!userService.checkUsernameUnique(user.getUserName())) {
345
+ return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
346
+ }
347
+ return toAjax(userService.insertUser(user));
348
+ }
349
+
350
+ @PreAuthorize("@ss.hasPermi('system:user:edit')")
351
+ @Log(title = "用户管理", businessType = BusinessType.UPDATE)
352
+ @PutMapping
353
+ public AjaxResult edit(@RequestBody SysUser user) {
354
+ userService.checkUserDataScope(user.getUserId());
355
+ return toAjax(userService.updateUser(user));
356
+ }
357
+
358
+ @PreAuthorize("@ss.hasPermi('system:user:remove')")
359
+ @Log(title = "用户管理", businessType = BusinessType.DELETE)
360
+ @DeleteMapping("/{userIds}")
361
+ public AjaxResult remove(@PathVariable Long[] userIds) {
362
+ return toAjax(userService.deleteUserByIds(userIds));
363
+ }
364
+ }
365
+ ```
366
+
367
+ #### 2.3 密码策略 / Password Policy
368
+
369
+ **🇨🇳 密码强度要求 / 🇺🇸 Password Strength Requirements:**
370
+
371
+ ```java
372
+ // 密码验证器
373
+ public class PasswordValidator {
374
+
375
+ // 密码复杂度规则
376
+ private static final int MIN_LENGTH = 8;
377
+ private static final int MAX_LENGTH = 20;
378
+
379
+ public static ValidationResult validatePassword(String password) {
380
+ ValidationResult result = new ValidationResult();
381
+
382
+ // 长度检查
383
+ if (password.length() < MIN_LENGTH || password.length() > MAX_LENGTH) {
384
+ result.addError("密码长度必须在" + MIN_LENGTH + "-" + MAX_LENGTH + "个字符之间");
385
+ }
386
+
387
+ // 包含大写字母
388
+ if (!password.matches(".*[A-Z].*")) {
389
+ result.addError("密码必须包含至少一个大写字母");
390
+ }
391
+
392
+ // 包含小写字母
393
+ if (!password.matches(".*[a-z].*")) {
394
+ result.addError("密码必须包含至少一个小写字母");
395
+ }
396
+
397
+ // 包含数字
398
+ if (!password.matches(".*\\d.*")) {
399
+ result.addError("密码必须包含至少一个数字");
400
+ }
401
+
402
+ // 包含特殊字符
403
+ if (!password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>/?].*")) {
404
+ result.addError("密码必须包含至少一个特殊字符");
405
+ }
406
+
407
+ // 常见弱密码检查
408
+ if (isCommonWeakPassword(password)) {
409
+ result.addError("不能使用常见弱密码");
410
+ }
411
+
412
+ return result;
413
+ }
414
+
415
+ // BCrypt加密存储
416
+ public String encodePassword(String rawPassword) {
417
+ return new BCryptPasswordEncoder().encode(rawPassword);
418
+ }
419
+
420
+ public boolean matchesPassword(String rawPassword, String encodedPassword) {
421
+ return new BCryptPasswordEncoder().matches(rawPassword, encodedPassword);
422
+ }
423
+ }
424
+ ```
425
+
426
+ ---
427
+
428
+ ### 3. 数据保护 (Data Protection)
429
+
430
+ #### 3.1 敏感数据加密 / Sensitive Data Encryption
431
+
432
+ **🇨🇳 AES加密工具类 / 🇺🇸 AES Encryption Utility:**
433
+
434
+ ```java
435
+ @Component
436
+ public class AesEncryptor {
437
+
438
+ @Value("${encrypt.aes.key}")
439
+ private String aesKey;
440
+
441
+ private static final String ALGORITHM = "AES/GCM/NoPadding";
442
+ private static final int GCM_IV_LENGTH = 12;
443
+ private static final int GCM_TAG_LENGTH = 128;
444
+
445
+ /**
446
+ * 加密敏感数据(如身份证号、银行卡号等)
447
+ */
448
+ public String encrypt(String plaintext) throws Exception {
449
+ // 生成随机IV
450
+ byte[] iv = new byte[GCM_IV_LENGTH];
451
+ new SecureRandom().nextBytes(iv);
452
+
453
+ // 初始化加密器
454
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
455
+ SecretKeySpec keySpec = new SecretKeySpec(
456
+ Base64.getDecoder().decode(aesKey), "AES");
457
+ GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
458
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);
459
+
460
+ // 加密
461
+ byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
462
+
463
+ // 组合IV + 密文
464
+ byte[] encryptedWithIv = new byte[GCM_IV_LENGTH + encrypted.length];
465
+ System.arraycopy(iv, 0, encryptedWithIv, 0, GCM_IV_LENGTH);
466
+ System.arraycopy(encrypted, 0, encryptedWithIv, GCM_IV_LENGTH, encrypted.length);
467
+
468
+ return Base64.getEncoder().encodeToString(encryptedWithIv);
469
+ }
470
+
471
+ /**
472
+ * 解密敏感数据
473
+ */
474
+ public String decrypt(String encryptedText) throws Exception {
475
+ byte[] decoded = Base64.getDecoder().decode(encryptedText);
476
+
477
+ // 提取IV
478
+ byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);
479
+
480
+ // 提取密文
481
+ byte[] encrypted = Arrays.copyOfRange(decoded, GCM_IV_LENGTH, decoded.length);
482
+
483
+ // 解密
484
+ Cipher cipher = Cipher.getInstance(ALGORITHM);
485
+ SecretKeySpec keySpec = new SecretKeySpec(
486
+ Base64.getDecoder().decode(aesKey), "AES");
487
+ GCMParameterSpec gcmSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
488
+ cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
489
+
490
+ byte[] decrypted = cipher.doFinal(encrypted);
491
+ return new String(decrypted, StandardCharsets.UTF_8);
492
+ }
493
+ }
494
+ ```
495
+
496
+ #### 3.2 日志脱敏 / Log Desensitization
497
+
498
+ **🇨🇳 敏感信息脱敏处理器 / 🇺🇸 Sensitive Information Masking Processor:**
499
+
500
+ ```java
501
+ /**
502
+ * 日志脱敏注解
503
+ */
504
+ @Target({ElementType.FIELD, ElementType.PARAMETER})
505
+ @Retention(RetentionPolicy.RUNTIME)
506
+ public @interface Sensitive {
507
+ SensitiveType value() default SensitiveType.DEFAULT;
508
+ }
509
+
510
+ /**
511
+ * 脱敏类型枚举
512
+ */
513
+ public enum SensitiveType {
514
+ DEFAULT, // 默认脱敏
515
+ PHONE, // 手机号:138****1234
516
+ ID_CARD, // 身份证:110***********1234
517
+ BANK_CARD, // 银行卡:6222***********1234
518
+ EMAIL, // 邮箱:t***@example.com
519
+ PASSWORD, // 密码:******
520
+ NAME // 姓名:张*
521
+ }
522
+
523
+ /**
524
+ * 脱敏工具类
525
+ */
526
+ public class DesensitizeUtils {
527
+
528
+ public static String desensitize(String value, SensitiveType type) {
529
+ if (value == null || value.isEmpty()) return value;
530
+
531
+ switch (type) {
532
+ case PHONE:
533
+ return value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
534
+ case ID_CARD:
535
+ return value.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1**********$2");
536
+ case BANK_CARD:
537
+ return value.replaceAll("(\\d{4})\\d+(\\d{4})", "$1***********$2");
538
+ case EMAIL:
539
+ return value.replaceAll("(^.)[^@]*(@.*$)", "$1***$2");
540
+ case PASSWORD:
541
+ return "******";
542
+ case NAME:
543
+ if (value.length() <= 2) return "*";
544
+ return value.charAt(0) + "*".repeat(value.length() - 1);
545
+ default:
546
+ return value.length() > 4 ?
547
+ value.substring(0, 2) + "***" + value.substring(value.length() - 2) :
548
+ "***";
549
+ }
550
+ }
551
+ }
552
+
553
+ // 使用示例
554
+ @Slf4j
555
+ public class UserServiceImpl implements UserService {
556
+
557
+ public void saveUser(@Sensitive(SensitiveType.PHONE) String phone,
558
+ @Sensitive(SensitiveType.ID_CARD) String idCard) {
559
+ log.info("保存用户信息: phone={}, idCard={}", phone, idCard);
560
+ // 日志输出: 保存用户信息: phone=138****1234, idCard=110***********1234
561
+ }
562
+ }
563
+ ```
564
+
565
+ #### 3.3 文件上传安全 / File Upload Security
566
+
567
+ **🇨🇳 安全上传控制器 / 🇺🇸 Secure Upload Controller:**
568
+
569
+ ```java
570
+ @RestController
571
+ @RequestMapping("/common/upload")
572
+ public class CommonUploadController {
573
+
574
+ // 允许的文件扩展名白名单
575
+ private static final Set<String> ALLOWED_EXTENSIONS =
576
+ Set.of("jpg", "jpeg", "png", "gif", "bmp", "doc", "docx",
577
+ "xls", "xlsx", "pdf", "txt", "zip", "rar");
578
+
579
+ // 文件大小限制:10MB
580
+ private static final long MAX_FILE_SIZE = 10 * 1024 * 1024;
581
+
582
+ @PostMapping("/upload")
583
+ public AjaxResult uploadFile(MultipartFile file) throws Exception {
584
+ // 1. 文件非空检查
585
+ if (file.isEmpty()) {
586
+ return error("上传文件不能为空");
587
+ }
588
+
589
+ // 2. 文件大小检查
590
+ if (file.getSize() > MAX_FILE_SIZE) {
591
+ return error("上传文件大小不能超过10MB");
592
+ }
593
+
594
+ // 3. 文件扩展名检查
595
+ String originalFilename = file.getOriginalFilename();
596
+ String extension = FilenameUtils.getExtension(originalFilename).toLowerCase();
597
+
598
+ if (!ALLOWED_EXTENSIONS.contains(extension)) {
599
+ return error("不允许上传此类型的文件:" + extension);
600
+ }
601
+
602
+ // 4. 文件内容类型验证(防止MIME类型伪造)
603
+ String contentType = file.getContentType();
604
+ if (!isValidContentType(contentType, extension)) {
605
+ return error("文件类型与内容不匹配");
606
+ }
607
+
608
+ // 5. 文件内容魔数验证(防止文件头伪装)
609
+ if (!validateFileHeader(file)) {
610
+ return error("文件内容验证失败");
611
+ }
612
+
613
+ // 6. 生成安全的文件名(UUID + 时间戳)
614
+ String fileName = generateSafeFileName(extension);
615
+
616
+ // 7. 上传到安全目录(禁止Web可访问目录)
617
+ String filePath = RuoYiConfig.getUploadPath() + fileName;
618
+ file.transferTo(new File(filePath));
619
+
620
+ // 8. 返回文件访问URL(通过Controller访问,不直接暴露路径)
621
+ String url = serverConfig.getUrl() + "/common/download?fileName=" + fileName;
622
+ AjaxResult ajax = AjaxResult.success();
623
+ ajax.put("url", url);
624
+ ajax.put("fileName", fileName);
625
+ ajax.put("originalFilename", originalFilename);
626
+ ajax.put("newFileName", fileName);
627
+ return ajax;
628
+ }
629
+
630
+ private boolean validateFileHeader(MultipartFile file) throws IOException {
631
+ byte[] header = new byte[4];
632
+ try (InputStream is = file.getInputStream()) {
633
+ is.read(header);
634
+ }
635
+
636
+ // JPEG: FF D8 FF
637
+ // PNG: 89 50 4E 47
638
+ // GIF: 47 49 46 38
639
+ // PDF: 25 50 44 46
640
+ String hex = bytesToHex(header);
641
+ return hex.startsWith("FFD8FF") || // JPEG
642
+ hex.startsWith("89504E47") || // PNG
643
+ hex.startsWith("47494638") || // GIF
644
+ hex.startsWith("25504446"); // PDF
645
+ }
646
+
647
+ private String generateSafeFileName(String extension) {
648
+ return UUID.randomUUID().toString().replace("-", "")
649
+ + "_" + System.currentTimeMillis()
650
+ + "." + extension;
651
+ }
652
+ }
653
+ ```
654
+
655
+ ---
656
+
657
+ ### 4. OWASP Top 10 合规检查 (OWASP Compliance)
658
+
659
+ **🇨🇳 OWASP Top 10 2021版完整覆盖 / 🇺🇸 OWASP Top 10 2021 Complete Coverage:**
660
+
661
+ | # | 类别 | 中文描述 | 检测方法 | 修复优先级 |
662
+ |---|------|---------|---------|-----------|
663
+ | A01 | Broken Access Control | 访问控制失效 | 权限矩阵审查 | CRITICAL |
664
+ | A02 | Cryptographic Failures | 加密机制失效 | 密钥轮换检查 | CRITICAL |
665
+ | A03 | Injection | 注入攻击 | SAST/DAST扫描 | CRITICAL |
666
+ | A04 | Insecure Design | 不安全设计 | 威胁建模 | HIGH |
667
+ | A05 | Security Misconfiguration | 安全配置错误 | 配置基线检查 | HIGH |
668
+ | A06 | Vulnerable Components | 过时组件 | 依赖扫描 | HIGH |
669
+ | A07 | Auth Failures | 身份认证失效 | 认证流程审计 | CRITICAL |
670
+ | A08 | Software/Data Integrity | 软件/数据完整性 | 签名验证 | MEDIUM |
671
+ | A09 | Logging/Monitoring Failures | 日志/监控不足 | 日志覆盖检查 | MEDIUM |
672
+ | A10 | SSRF | 服务端请求伪造 | 网络访问控制 | HIGH |
673
+
674
+ **🇨🇳 各条目详细检测规则 / 🇺🇸 Detailed Detection Rules for Each Item:**
675
+
676
+ #### A01: Broken Access Control / 访问控制失效
677
+
678
+ ```java
679
+ // ❌ VULNERABLE: 缺少权限校验
680
+ @GetMapping("/admin/users/{id}")
681
+ public User getUser(@PathVariable Long id) {
682
+ return userService.getUserById(id); // 任何认证用户都可访问
683
+ }
684
+
685
+ // ✅ SECURE: 完整的权限控制链
686
+ @GetMapping("/admin/users/{id}")
687
+ @PreAuthorize("@ss.hasPermi('system:user:query')")
688
+ public AjaxResult getUser(@PathVariable Long id) {
689
+ // 1. 权限注解检查
690
+ // 2. 数据范围校验(数据权限)
691
+ userService.checkUserDataScope(id);
692
+ // 3. 业务逻辑校验
693
+ User user = userService.getUserById(id);
694
+ if (user == null) {
695
+ return error("用户不存在");
696
+ }
697
+ // 4. 敏感字段脱敏
698
+ user.setPhone(DesensitizeUtils.desensitize(user.getPhone(), SensitiveType.PHONE));
699
+ return success(user);
700
+ }
701
+ ```
702
+
703
+ #### A02: Cryptographic Failures / 加密机制失效
704
+
705
+ **🇨🇳 检查清单 / 🇺🇸 Checklist:**
706
+ - [ ] 敏感数据使用AES-256-GCM加密存储
707
+ - [ ] 传输层强制TLS 1.2+
708
+ - [ ] 密码使用BCrypt/Argon2哈希
709
+ - [ ] 密钥定期轮换(建议90天)
710
+ - [ ] 禁用弱加密算法(MD5、SHA1、DES、RC4)
711
+
712
+ #### A03: Injection / 注入攻击
713
+
714
+ **🇨🇳 全面注入防护矩阵 / 🇺🇸 Comprehensive Injection Protection Matrix:**
715
+
716
+ | 注入类型 | 危险函数/API | 防护措施 | 检测工具 |
717
+ |---------|-------------|---------|---------|
718
+ | SQL注入 | Statement.executeQuery() | PreparedStatement | SQLMap |
719
+ | NoSQL注入 | BasicQuery.where() | 参数化查询 | NoSQLMap |
720
+ | OS命令注入 | Runtime.exec() | 白名单验证 | Commix |
721
+ | LDAP注入 | SearchControls() | LDAP转义 | Ldapmap |
722
+ | XPath注入 | XPath.evaluate() | 参数化XPath | XPathInjector |
723
+ | XXE | XMLReader.parse() | 禁用外部实体 | XXEinjector |
724
+
725
+ #### A07: Authentication Failures / 身份认证失效
726
+
727
+ **🇨🇳 安全认证流程 / 🇺🇸 Secure Authentication Flow:**
728
+
729
+ ```java
730
+ @Service
731
+ public class SecureLoginService {
732
+
733
+ @Autowired
734
+ private AuthenticationManager authenticationManager;
735
+
736
+ @Autowired
737
+ private RedisCache redisCache;
738
+
739
+ /**
740
+ * 安全登录流程
741
+ */
742
+ public String login(LoginBody loginBody) {
743
+ String username = loginBody.getUsername();
744
+ String password = loginBody.getPassword();
745
+ String code = loginBody.getCode();
746
+ String uuid = loginBody.getUuid();
747
+
748
+ // 1. 验证码校验
749
+ validateCaptcha(username, code, uuid);
750
+
751
+ // 2. 登录尝试次数限制(防暴力破解)
752
+ checkLoginAttempts(username);
753
+
754
+ // 3. 用户认证
755
+ Authentication authentication = authenticationManager.authenticate(
756
+ new UsernamePasswordAuthenticationToken(username, password)
757
+ );
758
+
759
+ // 4. 清除登录失败计数
760
+ clearLoginAttempts(username);
761
+
762
+ // 5. 生成JWT Token
763
+ LoginUser loginUser = (LoginUser) authentication.getPrincipal();
764
+ String token = tokenService.createToken(loginUser);
765
+
766
+ // 6. 记录登录日志(安全事件)
767
+ recordLoginEvent(loginUser.getUserId(), username, "LOGIN_SUCCESS");
768
+
769
+ return token;
770
+ }
771
+
772
+ private void checkLoginAttempts(String username) {
773
+ String key = CacheConstants.LOGIN_ATTEMPT_KEY + username;
774
+ Integer attempts = redisCache.getCacheObject(key);
775
+
776
+ if (attempts != null && attempts >= 5) {
777
+ // 锁定账户30分钟
778
+ redisCache.setCacheObject(key, attempts, 30, TimeUnit.MINUTES);
779
+ throw new ServiceException("登录失败次数过多,账户已锁定30分钟");
780
+ }
781
+ }
782
+ }
783
+ ```
784
+
785
+ ---
786
+
787
+ ## Guardrails / 安全护栏
788
+
789
+ **🇨🇳**
790
+ 1. **最小权限原则**: 所有API接口必须显式声明所需权限,默认拒绝未授权访问
791
+ 2. **输入验证强制**: 所有外部输入(请求参数、Headers、Cookies)必须经过验证和过滤
792
+ 3. **安全默认值**: 加密、日志记录、CSRF保护等功能默认开启,需显式禁用
793
+ 4. **纵深防御**: 在多个层级实施安全控制(网络、应用、数据),单一防线失效不影响整体安全
794
+ 5. **错误信息模糊化**: 生产环境返回通用错误信息,详细错误仅记录到日志
795
+ 6. **依赖安全扫描**: 定期扫描第三方依赖漏洞,及时更新有已知CVE的组件
796
+ 7. **安全编码规范**: 所有新代码必须符合OWASP安全编码指南,Code Review必须包含安全项
797
+ 8. **应急响应准备**: 制定安全事件响应预案,明确报告渠道和处理流程
798
+
799
+ **🇺🇸**
800
+ 1. **Principle of Least Privilege**: All API endpoints must explicitly declare required permissions; deny access by default
801
+ 2. **Mandatory Input Validation**: All external inputs (request parameters, headers, cookies) must be validated and sanitized
802
+ 3. **Secure by Default**: Encryption, logging, CSRF protection enabled by default; explicit action required to disable
803
+ 4. **Defense in Depth**: Implement security controls at multiple layers (network, application, data); single layer failure doesn't compromise overall security
804
+ 5. **Generic Error Messages**: Return generic errors in production; detailed errors logged only
805
+ 6. **Dependency Scanning**: Regularly scan third-party dependencies for vulnerabilities; update components with known CVEs promptly
806
+ 7. **Secure Coding Standards**: All new code must follow OWASP secure coding guidelines; security items mandatory in Code Review
807
+ 8. **Incident Response Preparedness**: Maintain security incident response plan with clear reporting channels and handling procedures
808
+
809
+ ---
810
+
811
+ ## Iron Law / 核心铁律
812
+
813
+ **🇨🇳 核心铁律 - 不可违反的安全底线 / 🇺🇸 Iron Laws - Non-Negotiable Security Baselines**
814
+
815
+ ### Iron Law #1: 安全优先原则 / Security First Principle
816
+
817
+ **规则**: 所有安全问题按Critical级别处理,不得因进度压力、业务需求或成本考虑而降级或跳过安全修复。
818
+
819
+ **❌ Violation Example / 违规示例:**
820
+ ```java
821
+ // 项目紧急上线,暂时关闭SQL注入防护
822
+ // TODO: 上线后再修复安全问题
823
+ @GetMapping("/search")
824
+ public List<User> search(@RequestParam String keyword) {
825
+ String sql = "SELECT * FROM user WHERE name LIKE '%" + keyword + "%'";
826
+ return jdbcTemplate.queryForList(sql); // CRITICAL: SQL注入漏洞
827
+ }
828
+ ```
829
+
830
+ **✅ Compliant Example / 合规示例:**
831
+ ```java
832
+ // 即使项目紧张,也必须使用参数化查询
833
+ @GetMapping("/search")
834
+ @PreAuthorize("@ss.hasPermi('system:user:list')")
835
+ public List<User> search(@RequestParam String keyword) {
836
+ // 输入长度限制
837
+ if (keyword.length() > 50) {
838
+ throw new ServiceException("搜索关键词过长");
839
+ }
840
+ // 参数化查询
841
+ String sql = "SELECT * FROM sys_user WHERE user_name LIKE ?";
842
+ return jdbcTemplate.queryForList(sql, "%" + keyword + "%");
843
+ }
844
+ ```
845
+
846
+ ### Iron Law #2: 最小权限原则 / Principle of Least Privilege
847
+
848
+ **规则**: 只授予完成工作所需的最小权限,禁止过度授权。数据访问必须遵循数据权限隔离原则。
849
+
850
+ **❌ Violation Example / 违规示例:**
851
+ ```java
852
+ // 给普通管理员授予超级管理员权限
853
+ @PreAuthorize("@ss.hasRole('admin')") // 过于宽泛
854
+ public List<User> getAllUsers() {
855
+ return userService.selectAll(); // 可查看所有用户,包括超管
856
+ }
857
+ ```
858
+
859
+ **✅ Compliant Example / 合规示例:**
860
+ ```java
861
+ // 精细化的权限控制 + 数据范围隔离
862
+ @PreAuthorize("@ss.hasPermi('system:user:list')")
863
+ public TableDataInfo list(SysUser user) {
864
+ // 自动应用当前用户的数据权限范围
865
+ startPage();
866
+ // 只能查询本部门及下级部门的数据
867
+ List<SysUser> list = userService.selectUserList(user);
868
+ return getDataTable(list);
869
+ }
870
+ ```
871
+
872
+ ### Iron Law #3: 输入验证强制 / Mandatory Input Validation
873
+
874
+ **规则**: 所有来自客户端的输入数据必须经过严格的验证和过滤,绝不信任任何未经处理的输入。
875
+
876
+ **❌ Violation Example / 违规示例:**
877
+ ```java
878
+ // 直接使用前端传来的ID,未做任何验证
879
+ @PostMapping("/delete")
880
+ public AjaxResult delete(@RequestParam Long userId) {
881
+ return toAjax(userService.deleteUserById(userId)); // 可能删除任意用户
882
+ }
883
+ ```
884
+
885
+ **✅ Compliant Example / 合规示例:**
886
+ ```java
887
+ @PostMapping("/delete")
888
+ @PreAuthorize("@ss.hasPermi('system:user:remove')")
889
+ @Log(title = "用户管理", businessType = BusinessType.DELETE)
890
+ public AjaxResult delete(@PathVariable Long[] userIds) {
891
+ // 1. 权限校验(注解)
892
+ // 2. 数据范围校验
893
+ for (Long userId : userIds) {
894
+ userService.checkUserDataScope(userId);
895
+ // 不能删除自己
896
+ if (userId.equals(SecurityUtils.getUserId())) {
897
+ return error("当前用户不能删除");
898
+ }
899
+ // 不能删除超级管理员
900
+ if (isAdmin(userId)) {
901
+ return error("不允许删除管理员账号");
902
+ }
903
+ }
904
+ return toAjax(userService.deleteUserByIds(userIds));
905
+ }
906
+ ```
907
+
908
+ ### Iron Law #4: 加密默认开启 / Encryption Enabled by Default
909
+
910
+ **规则**: 敏感数据的传输和存储必须使用强加密算法,明文传输/存储敏感数据属于严重违规。
911
+
912
+ **❌ Violation Example / 违规示例:**
913
+ ```java
914
+ // 明文存储身份证号和手机号
915
+ @Entity
916
+ public class User {
917
+ @Column(name = "id_card")
918
+ private String idCard; // 明文存储身份证
919
+
920
+ @Column(name = "phone")
921
+ private String phone; // 明文存储手机号
922
+ }
923
+ ```
924
+
925
+ **✅ Compliant Example / 合规示例:**
926
+ ```java
927
+ // 敏感数据加密存储
928
+ @Entity
929
+ public class User {
930
+ @Column(name = "id_card")
931
+ private String idCardEncrypted; // AES-256-GCM加密存储
932
+
933
+ @Column(name = "phone")
934
+ private String phoneEncrypted; // AES-256-GCM加密存储
935
+
936
+ // 使用AOP自动加解密
937
+ @SensitiveField(type = SensitiveType.ID_CARD)
938
+ public String getIdCard() {
939
+ return aesEncryptor.decrypt(idCardEncrypted);
940
+ }
941
+
942
+ public void setIdCard(String idCard) {
943
+ this.idCardEncrypted = aesEncryptor.encrypt(idCard);
944
+ }
945
+ }
946
+ ```
947
+
948
+ ### Iron Law #5: 不信任客户端 / Never Trust the Client
949
+
950
+ **规则**: 所有关键业务逻辑和数据校验必须在服务端完成,前端校验仅为用户体验优化,不可作为安全依据。
951
+
952
+ **❌ Violation Example / 违规示例:**
953
+ ```javascript
954
+ // 前端校验价格(可被绕过)
955
+ function validatePrice(price) {
956
+ if (price < 0) {
957
+ alert('价格不能为负数');
958
+ return false;
959
+ }
960
+ return true;
961
+ }
962
+ ```
963
+
964
+ ```java
965
+ // 后端直接使用前端传入的价格(危险!)
966
+ @PostMapping("/order/create")
967
+ public AjaxResult createOrder(@RequestBody Order order) {
968
+ order.setTotalPrice(order.getPrice() * order.getQuantity());
969
+ return toAsync(orderService.createOrder(order)); // 可能被篡改
970
+ }
971
+ ```
972
+
973
+ **✅ Compliant Example / 合规示例:**
974
+ ```java
975
+ @PostMapping("/order/create")
976
+ @PreAuthorize("@ss.hasPermi('order:add')")
977
+ public AjaxResult createOrder(@RequestBody OrderDTO orderDTO) {
978
+ // 1. 完整的服务端校验
979
+ if (orderDTO.getPrice() == null || orderDTO.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
980
+ return error("订单价格必须大于0");
981
+ }
982
+ if (orderDTO.getQuantity() == null || orderDTO.getQuantity() <= 0) {
983
+ return error("订单数量必须大于0");
984
+ }
985
+
986
+ // 2. 从数据库重新获取商品价格(防止篡改)
987
+ Product product = productService.getProductById(orderDTO.getProductId());
988
+ if (product == null) {
989
+ return error("商品不存在");
990
+ }
991
+
992
+ // 3. 使用服务器端价格计算总价
993
+ BigDecimal totalPrice = product.getPrice()
994
+ .multiply(BigDecimal.valueOf(orderDTO.getQuantity()));
995
+
996
+ // 4. 价格合理性校验(防价格篡改)
997
+ if (orderDTO.getPrice().compareTo(product.getPrice()) != 0) {
998
+ // 记录异常行为
999
+ securityAuditService.logSuspiciousActivity(
1000
+ SecurityUtils.getUserId(),
1001
+ "PRICE_TAMPERING",
1002
+ "订单价格与实际不符"
1003
+ );
1004
+ return error("订单价格异常");
1005
+ }
1006
+
1007
+ Order order = new Order();
1008
+ order.setProductId(orderDTO.getProductId());
1009
+ order.setQuantity(orderDTO.getQuantity());
1010
+ order.setPrice(product.getPrice()); // 使用服务器端价格
1011
+ order.setTotalPrice(totalPrice);
1012
+
1013
+ return toAsync(orderService.createOrder(order));
1014
+ }
1015
+ ```
1016
+
1017
+ ---
1018
+
1019
+ ## Rationalization Table / 合理化防御表
1020
+
1021
+ **🇨🇳 当你想要跳过安全检查时... / 🇺🇸 When you want to skip security checks...**
1022
+
1023
+ | 你可能想说的 / What you might say | 为什么这样做是危险的 / Why this is dangerous | 正确的做法 / The right approach | 如果确实需要特殊处理 / If you really need special handling |
1024
+ |----------------------------------|------------------------------------------|-------------------------------|-----------------------------------------------------|
1025
+ | "这只是内部系统,不需要这么严格的安全措施" / "This is an internal system, no need for strict security" | 内部系统往往包含最敏感的数据(员工信息、财务数据),且内部威胁占比高达60% / Internal systems often contain most sensitive data; insider threats account for 60% of breaches | 对所有系统实施统一的安全基线,根据数据敏感度分级实施额外控制 / Apply unified security baseline to all systems; implement additional controls based on data sensitivity classification | 进行风险评估,如果确认为低风险环境,文档化决策并获得安全团队批准 / Conduct risk assessment; if truly low-risk environment, document decision and obtain security team approval |
1026
+ | "这个接口只是查询,不会有安全问题" / "This endpoint is read-only, no security issues" | 查询接口常被利用进行信息收集,为后续攻击做准备;SQL注入可通过只读语句获取全部数据 / Query endpoints are often used for reconnaissance; SQL injection can extract all data via read-only statements | 实施完整的输入验证和输出过滤;对查询结果中的敏感字段进行脱敏 / Implement complete input validation and output filtering; mask sensitive fields in query results | 使用视图限制可查询的字段;实施查询频率限制和结果集大小限制 / Use views to limit queryable fields; implement rate limiting and result set size limits |
1027
+ | "项目赶进度,安全优化后面再做" / "Project is behind schedule, will optimize security later" | 安全问题一旦上线就可能被利用,且后续修复的成本是开发阶段的10-100倍 / Once deployed, vulnerabilities can be exploited immediately; post-deployment fixes cost 10-100x more | 将安全作为非功能性需求纳入迭代计划;每个Sprint预留15%时间处理技术债务 / Include security as non-functional requirement in sprint planning; reserve 15% capacity per sprint for technical debt | 识别关键风险项优先处理;对遗留风险实施补偿性控制措施 / Identify critical risks for priority handling; implement compensating controls for legacy risks |
1028
+ | "用户不会发现这个漏洞的" / "Users won't find this vulnerability" | 自动化扫描工具可在几分钟内发现常见漏洞;黑客通常先于用户发现安全问题 / Automated scanners can find common vulnerabilities in minutes; attackers typically discover issues before users | 定期进行自动化安全扫描(SAST/DAST)和渗透测试;建立安全漏洞奖励计划 / Conduct regular automated security scanning (SAST/DAST) and penetration testing; establish bug bounty program | 实施监控和告警机制,及时发现异常行为;准备应急响应预案 / Implement monitoring and alerting to detect anomalous behavior; prepare incident response plan |
1029
+ | "这个库很常用,应该没有安全问题" / "This library is widely used, should be safe" | 流行库往往是攻击者的主要目标(Log4j、Spring4Shell案例);供应链攻击日益增多 / Popular libraries are prime targets for attackers (Log4j, Spring4Shell cases); supply chain attacks are increasing | 使用软件成分分析(SCA)工具持续监控依赖漏洞;建立组件审批流程 / Use Software Composition Analysis (SCA) tools to continuously monitor dependency vulnerabilities; establish component approval process | 将第三方组件放入隔离容器运行;实施运行时行为监控 / Run third-party components in isolated containers; implement runtime behavior monitoring |
1030
+
1031
+ ### 常见陷阱 / Common Pitfalls
1032
+
1033
+ **🇨🇳**
1034
+ 1. **信任边界混淆**: 混淆了"用户已认证"和"用户已授权"的概念,认为认证通过就可以访问所有资源
1035
+ 2. **安全与性能权衡误区**: 为了性能牺牲安全(如禁用CSRF、减少加密强度),正确的做法是在保证安全的前提下优化性能
1036
+ 3. **"以后再修"陷阱**: 将安全修复标记为Technical Debt但从未安排时间处理,导致债务越积越多
1037
+ 4. **合规等于安全错觉**: 通过了安全合规检查就认为系统安全,实际上合规只是最低标准
1038
+
1039
+ **🇺🇸**
1040
+ 1. **Trust Boundary Confusion**: Confusing "authenticated user" with "authorized user," assuming authentication grants access to all resources
1041
+ 2. **Security vs Performance Trade-off Fallacy**: Sacrificing security for performance (disabling CSRF, reducing encryption strength); correct approach is optimizing performance while maintaining security
1042
+ 3. **"Fix It Later" Trap**: Marking security fixes as Technical Debt but never scheduling time to address them, leading to accumulating debt
1043
+ 4. **Compliance Equals Security Illusion**: Assuming system is secure after passing compliance checks; compliance is actually just the minimum standard
1044
+
1045
+ ---
1046
+
1047
+ ## Red Flags / 红旗警告
1048
+
1049
+ **🇨🇳 三层红旗预警系统 / 🇺🇸 Three-Layer Red Flag Warning System**
1050
+
1051
+ ### Layer 1: Input Guards / 输入防护层
1052
+
1053
+ **触发条件 / Trigger Conditions:**
1054
+
1055
+ | Flag ID | 红旗信号 / Red Flag Signal | 严重等级 / Severity | 处理方式 / Action |
1056
+ |---------|--------------------------|-------------------|------------------|
1057
+ | INPUT-001 | 接收到包含SQL关键字(UNION、SELECT、DROP等)的用户输入 | CRITICAL | 立即拦截并记录安全事件;返回400错误 |
1058
+ | INPUT-002 | 输入包含HTML/JavaScript标签(<script>、onclick等) | HIGH | 转义处理后继续;记录警告日志 |
1059
+ | INPUT-003 | 输入包含路径遍历序列(../、..\\) | CRITICAL | 立即拦截;触发IP临时封禁 |
1060
+ | INPUT-004 | 输入包含OS命令元字符(;、\|、&、$()) | CRITICAL | 立即拦截;通知安全团队 |
1061
+ | INPUT-005 | 单IP短时间大量请求(>100次/分钟) | HIGH | 启用速率限制;触发CAPTCHA验证 |
1062
+
1063
+ **🇨🇳 处理代码示例 / 🇺🇸 Handling Code Example:**
1064
+
1065
+ ```java
1066
+ @Component
1067
+ public class SecurityInputValidator {
1068
+
1069
+ private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
1070
+ "(?i)(union|select|insert|update|delete|drop|truncate|exec|execute)" +
1071
+ "(\\s+.+|(\\s*\\(.+\\))*)", Pattern.CASE_INSENSITIVE
1072
+ );
1073
+
1074
+ private static final Pattern XSS_PATTERN = Pattern.compile(
1075
+ "<[^>]*>|javascript:|on\\w+\\s*=", Pattern.CASE_INSENSITIVE
1076
+ );
1077
+
1078
+ public ValidationResult validateInput(String input, String fieldName) {
1079
+ ValidationResult result = new ValidationResult();
1080
+
1081
+ if (input == null || input.trim().isEmpty()) {
1082
+ return result;
1083
+ }
1084
+
1085
+ // SQL注入检测
1086
+ if (SQL_INJECTION_PATTERN.matcher(input).find()) {
1087
+ result.addViolation(ViolationLevel.CRITICAL,
1088
+ "潜在SQL注入攻击: 字段[" + fieldName + "]");
1089
+ securityAuditService.logSecurityEvent("SQL_INJECTION_DETECTED",
1090
+ Map.of("field", fieldName, "input", input));
1091
+ }
1092
+
1093
+ // XSS检测
1094
+ if (XSS_PATTERN.matcher(input).find()) {
1095
+ result.addViolation(ViolationLevel.HIGH,
1096
+ "潜在XSS攻击: 字段[" + fieldName + "]");
1097
+ }
1098
+
1099
+ // 路径遍历检测
1100
+ if (input.contains("..") || input.contains("../") || input.contains("..\\\\")) {
1101
+ result.addViolation(ViolationLevel.CRITICAL,
1102
+ "路径遍历攻击: 字段[" + fieldName + "]");
1103
+ }
1104
+
1105
+ return result;
1106
+ }
1107
+ }
1108
+ ```
1109
+
1110
+ ### Layer 2: Execution Guards / 执行防护层
1111
+
1112
+ **触发条件 / Trigger Conditions:**
1113
+
1114
+ | Flag ID | 红旗信号 / Red Flag Signal | 严重等级 / Severity | 处理方式 / Action |
1115
+ |---------|--------------------------|-------------------|------------------|
1116
+ | EXEC-001 | 尝试访问未授权的资源或API端点 | CRITICAL | 返回403;记录完整请求上下文;触发告警 |
1117
+ | EXEC-002 | 认证令牌过期但仍被用于敏感操作 | HIGH | 强制重新认证;使旧令牌失效 |
1118
+ | EXEC-003 | 用户角色/权限变更后仍持有旧会话 | CRITICAL | 立即销毁所有活跃会话;强制重新登录 |
1119
+ | EXEC-004 | 批量数据导出请求(>1000条记录) | WARN | 要求二次确认;记录操作审计日志 |
1120
+ | EXEC-005 | 异常时间的敏感操作(如凌晨3点批量删除) | HIGH | 要求多因素认证确认;通知管理员 |
1121
+
1122
+ **🇨🇳 权限校验增强 / 🇺🇸 Enhanced Permission Validation:**
1123
+
1124
+ ```java
1125
+ @Aspect
1126
+ @Component
1127
+ public class SecurityExecutionGuard {
1128
+
1129
+ @Around("@annotation(preAuthorize)")
1130
+ public Object checkExecutionSecurity(ProceedingJoinPoint joinPoint,
1131
+ PreAuthorize preAuthorize) throws Throwable {
1132
+ // 1. 基础权限校验
1133
+ if (!permissionService.hasPermission(preAuthorize.value())) {
1134
+ throw new UnauthorizedException("无权执行此操作");
1135
+ }
1136
+
1137
+ // 2. 操作环境安全检查
1138
+ HttpServletRequest request =
1139
+ ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
1140
+ .getRequest();
1141
+
1142
+ // IP信誉检查
1143
+ if (ipReputationService.isMaliciousIp(request.getRemoteAddr())) {
1144
+ securityAuditService.logSecurityEvent("MALICIOUS_IP_ACCESS",
1145
+ Map.of("ip", request.getRemoteAddr(), "endpoint", request.getRequestURI()));
1146
+ throw new AccessDeniedException("访问被拒绝");
1147
+ }
1148
+
1149
+ // 3. 敏感操作二次确认
1150
+ MethodSignature signature = (MethodSignature) joinPoint.getSignature();
1151
+ if (isSensitiveOperation(signature)) {
1152
+ String mfaToken = request.getHeader("X-MFA-Token");
1153
+ if (!mfaValidationService.validate(mfaToken)) {
1154
+ throw new MfaRequiredException("敏感操作需要多因素认证");
1155
+ }
1156
+ }
1157
+
1158
+ // 4. 执行目标方法
1159
+ Object result = joinPoint.proceed();
1160
+
1161
+ // 5. 结果后处理(敏感数据脱敏)
1162
+ if (result instanceof AjaxResult) {
1163
+ sanitizeSensitiveData((AjaxResult) result);
1164
+ }
1165
+
1166
+ return result;
1167
+ }
1168
+ }
1169
+ ```
1170
+
1171
+ ### Layer 3: Output Guards / 输出防护层
1172
+
1173
+ **触发条件 / Trigger Conditions:**
1174
+
1175
+ | Flag ID | 红旗信号 / Red Flag Signal | 严重等级 / Severity | 处理方式 / Action |
1176
+ |---------|--------------------------|-------------------|------------------|
1177
+ | OUTPUT-001 | 响应中包含堆栈跟踪信息 | CRITICAL | 过滤掉异常详情;返回通用错误消息 |
1178
+ | OUTPUT-002 | 响应中泄露内部系统信息(版本、路径、IP) | HIGH | 实施响应过滤器;移除敏感头部信息 |
1179
+ | OUTPUT-003 | 大量敏感数据被返回(如完整用户列表含密码哈希) | CRITICAL | 检查查询逻辑;实施字段级权限控制 |
1180
+ | OUTPUT-004 | 错误消息中包含SQL语句或调试信息 | CRITICAL | 自定义异常处理器;统一错误响应格式 |
1181
+
1182
+ **🇨🇳 安全响应包装器 / 🇺🇸 Secure Response Wrapper:**
1183
+
1184
+ ```java
1185
+ @ControllerAdvice
1186
+ public class SecurityOutputHandler extends ResponseEntityExceptionHandler {
1187
+
1188
+ @ExceptionHandler(Exception.class)
1189
+ public ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
1190
+ // 1. 记录完整异常信息到日志(含堆栈)
1191
+ log.error("Unhandled exception: {}", ex.getMessage(), ex);
1192
+
1193
+ // 2. 构建安全的错误响应(不含敏感信息)
1194
+ Map<String, Object> body = new LinkedHashMap<>();
1195
+ body.put("timestamp", LocalDateTime.now());
1196
+ body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
1197
+ body.put("error", "Internal Server Error");
1198
+ body.put("message", "服务器内部错误,请稍后重试");
1199
+ body.put("path", ((ServletWebRequest) request).getRequest().getRequestURI());
1200
+
1201
+ // 3. 移除敏感响应头
1202
+ HttpHeaders headers = new HttpHeaders();
1203
+ headers.remove("Server");
1204
+ headers.remove("X-Powered-By");
1205
+ headers.remove("X-Application-Version");
1206
+
1207
+ return new ResponseEntity<>(body, headers, HttpStatus.INTERNAL_SERVER_ERROR);
1208
+ }
1209
+
1210
+ @ExceptionHandler(AccessDeniedException.class)
1211
+ public ResponseEntity<Object> handleAccessDeniedException(
1212
+ AccessDeniedException ex, WebRequest request) {
1213
+ // 统一返回403,不区分"未登录"和"无权限"
1214
+ Map<String, Object> body = new LinkedHashMap<>();
1215
+ body.put("timestamp", LocalDateTime.now());
1216
+ body.put("status", HttpStatus.FORBIDDEN.value());
1217
+ body.put("error", "Forbidden");
1218
+ body.put("message", "您没有权限执行此操作");
1219
+ body.put("path", ((ServletWebRequest) request).getRequest().getRequestURI());
1220
+
1221
+ return new ResponseEntity<>(body, new HttpHeaders(), HttpStatus.FORBIDDEN);
1222
+ }
1223
+ }
1224
+ ```
1225
+
1226
+ ### Trigger Handling / 触发处理规则
1227
+
1228
+ **🇨🇳 不同严重等级的处理策略 / 🇺🇸 Handling Strategies by Severity Level:**
1229
+
1230
+ | 严重等级 / Severity Level | 处理动作 / Action | 通知对象 / Notify | 日志级别 / Log Level | 是否阻断 / Block Request? |
1231
+ |--------------------------|------------------|-------------------|----------------------|-------------------------|
1232
+ | **CRITICAL** | 立即拦截请求;返回403/400;可选临时封禁IP | 安全运维团队;安全负责人 | ERROR | 是,立即阻断 |
1233
+ | **WARN** | 记录警告日志;允许请求继续但增加监控 | 开发团队负责人 | WARN | 否,但加强监控 |
1234
+ | **INFO** | 记录信息日志;用于趋势分析和统计 | 无 | INFO | 否 |
1235
+
1236
+ **🇨🇳 告警升级条件 / 🇺🇸 Alert Escalation Conditions:**
1237
+
1238
+ ```java
1239
+ /**
1240
+ * 安全事件告警服务
1241
+ */
1242
+ @Service
1243
+ public class SecurityAlertService {
1244
+
1245
+ @Value("${security.alert.threshold.critical:5}")
1246
+ private int criticalThreshold;
1247
+
1248
+ @Value("${security.alert.threshold.high:20}")
1249
+ private int highThreshold;
1250
+
1251
+ /**
1252
+ * 处理安全事件
1253
+ */
1254
+ public void handleSecurityEvent(SecurityEvent event) {
1255
+ // 1. 记录事件
1256
+ securityEventRepository.save(event);
1257
+
1258
+ // 2. 更新计数器
1259
+ String counterKey = event.getType() + ":" + event.getSourceIp();
1260
+ Long count = redisTemplate.opsForValue().increment(counterKey);
1261
+
1262
+ // 3. 检查是否达到告警阈值
1263
+ if (event.getSeverity() == Severity.CRITICAL && count >= criticalThreshold) {
1264
+ // 立即电话/短信通知安全负责人
1265
+ alertService.sendUrgentAlert(
1266
+ "CRITICAL: " + event.getType(),
1267
+ "Source IP: " + event.getSourceIp() +
1268
+ "\nCount in last hour: " + count +
1269
+ "\nImmediate action required!"
1270
+ );
1271
+
1272
+ // 自动封禁IP(24小时)
1273
+ firewallService.blockIp(event.getSourceIp(), Duration.ofHours(24));
1274
+ } else if (event.getSeverity() == Severity.HIGH && count >= highThreshold) {
1275
+ // 发送邮件通知安全团队
1276
+ alertService.sendEmailAlert(
1277
+ "HIGH: Elevated " + event.getType() + " activity",
1278
+ "Source IP: " + event.getSourceIp() +
1279
+ "\nCount in last hour: " + count +
1280
+ "\nInvestigation recommended."
1281
+ );
1282
+ }
1283
+
1284
+ // 4. 重置计数器(每小时)
1285
+ if (count == 1) {
1286
+ redisTemplate.expire(counterKey, 1, TimeUnit.HOURS);
1287
+ }
1288
+ }
1289
+ }
1290
+ ```
1291
+
1292
+ ---
1293
+
1294
+ ## Quick Reference / 快速参考
1295
+
1296
+ ### 常见漏洞速查表 / Common Vulnerability Quick Reference
1297
+
1298
+ | 漏洞类型 | 检测方法 | 修复方案 | 工具推荐 |
1299
+ |---------|---------|---------|---------|
1300
+ | SQL注入 | SAST扫描 + 手动Review | PreparedStatement参数化 | SQLMap, SonarQube |
1301
+ | XSS | DAST扫描 + 浏览器DevTools | 输入过滤 + 输出编码 | XSSer, Burp Suite |
1302
+ | CSRF | 代理抓包分析 | Token同步 + SameSite Cookie | CSRFTester |
1303
+ | 命令注入 | 代码审计 | 白名单 + ProcessBuilder | Commix |
1304
+ | 路径遍历 | fuzzing测试 | 路径规范化 + 目录限制 | DirBuster |
1305
+ | SSRF | 网络流量分析 | URL白名单 + 内网隔离 | SSRFmap |
1306
+
1307
+ ### 安全编码Checklist / Secure Coding Checklist
1308
+
1309
+ **每次提交代码前检查 / Before Every Code Submission:**
1310
+ - [ ] 所有SQL查询使用参数化(PreparedStatement/#{})
1311
+ - [ ] 所有外部输入经过验证和过滤
1312
+ - [ ] 敏感数据使用加密存储(AES-256-GCM)
1313
+ - [ ] 密码使用BCrypt/Argon2哈希存储
1314
+ - [ ] API接口有适当的权限注解
1315
+ - [ ] 错误信息不泄露系统内部细节
1316
+ - [ ] 文件上传做了类型、大小、内容校验
1317
+ - [ ] 敏感操作有审计日志记录
1318
+ - [ ] 第三方依赖经过漏洞扫描
1319
+ - [ ] CORS配置严格限定允许的来源
1320
+
1321
+ ---
1322
+
1323
+ 大哥,任务完成了!我已在 `c:\Users\wonder\trae-projects\pdd-skills-v3\skills\expert\expert-security\` 目录下成功创建了 **expert-security** 安全专家技能,包含以下三个文件:
1324
+
1325
+ 1. **[_meta.json](file:///c:\Users\wonder\trae-projects\pdd-skills-v3\skills\expert\expert-security\_meta.json)** - 元数据文件,包含名称、版本、描述和中英文触发词
1326
+ 2. **[SKILL.md](file:///c:\Users\wonder\trae-projects\pdd-skills-v3\skills\expert\expert-security\SKILL.md)** - 完整的双语技能文档(约1000行),包含:
1327
+ - Frontmatter(名称、双语描述、许可证、版本)
1328
+ - 核心概念(中英双语)
1329
+ - 四大核心能力模块:
1330
+ - 代码漏洞扫描(SQL注入、XSS、CSRF、命令注入、路径遍历)
1331
+ - 认证与授权安全(JWT/Session、RBAC、密码策略)
1332
+ - 数据保护(AES加密、日志脱敏、文件上传安全)
1333
+ - OWASP Top 10 2021完整覆盖
1334
+ - 8条安全护栏(中英双语)
1335
+ - 5条核心铁律(每条含违规示例和合规示例)
1336
+ - 合理化防御表(5行 + 4个常见陷阱)
1337
+ - 三层红旗预警系统(Input/Execution/Output Guards)
1338
+ - 快速参考表和安全编码Checklist
1339
+ 3. **[evals/default-evals.json](file:///c:\Users\wonder\trae-projects\pdd-skills-v3\skills\expert\expert-security\evals\default-evals.json)** - 评估测试文件,包含5个测试用例
1340
+
1341
+ 该技能完全基于Java/Spring Boot/若依框架提供具体的代码示例,涵盖SQL注入、XSS、CSRF等具体攻击场景和修复代码,符合M2.5双语化规范。