@blueking/bkui-knowledge 0.0.1-beta.1 → 0.0.1-beta.11
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.
- package/README.md +166 -58
- package/bin/bkui-knowledge.js +229 -86
- package/knowledge/manifest.json +38 -1
- package/knowledge/skills/.template/README.md +1 -1
- package/knowledge/skills/bk-security-redlines/SKILL.md +47 -0
- package/knowledge/skills/bk-security-redlines/references/auth-check.md +73 -0
- package/knowledge/skills/bk-security-redlines/references/data-encryption.md +78 -0
- package/knowledge/skills/bk-security-redlines/references/input-validation.md +96 -0
- package/knowledge/skills/bk-skill-creator/SKILL.md +37 -0
- package/knowledge/skills/bk-skill-creator/references/common-mistakes.md +43 -0
- package/knowledge/skills/bk-skill-creator/references/quick-start.md +42 -0
- package/knowledge/skills/bk-skill-creator/references/skill-checklist.md +93 -0
- package/knowledge/skills/bk-skill-creator/references/structure-guide.md +88 -0
- package/knowledge/skills/bk-skill-creator/references/writing-tips.md +153 -0
- package/knowledge/skills/bkui-quick-start/SKILL.md +52 -0
- package/knowledge/skills/bkui-quick-start/references/components-list.md +17 -0
- package/knowledge/skills/bkui-quick-start/references/skills-index.md +26 -0
- package/knowledge/skills/external/vue-skills/LICENSE +21 -0
- package/knowledge/skills/external/vue-skills/README.md +69 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/SKILL.md +42 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/codeactions-save-performance.md +79 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/data-attributes-config.md +74 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/deep-watch-numeric.md +102 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/define-model-update-event.md +79 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/duplicate-plugin-detection.md +102 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/fallthrough-attributes.md +63 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/hmr-vue-ssr.md +124 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/module-resolution-bundler.md +81 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/pinia-store-mocking.md +159 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/script-setup-jsdoc.md +85 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/strict-css-modules.md +68 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/unplugin-auto-import-conflicts.md +97 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/volar-3-breaking-changes.md +66 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/vue-directive-comments.md +73 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/vue-router-typed-params.md +81 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/vue-tsc-strict-templates.md +69 -0
- package/knowledge/skills/external/vue-skills/skills/vue-best-practices/rules/with-defaults-union-types.md +102 -0
- package/knowledge/skills/web-security-guide/SKILL.md +48 -0
- package/knowledge/skills/web-security-guide/references/access-control.md +123 -0
- package/knowledge/skills/web-security-guide/references/auth-session.md +99 -0
- package/knowledge/skills/web-security-guide/references/csrf.md +59 -0
- package/knowledge/skills/web-security-guide/references/data-exposure.md +108 -0
- package/knowledge/skills/web-security-guide/references/deserialization.md +59 -0
- package/knowledge/skills/web-security-guide/references/injection.md +357 -0
- package/knowledge/skills/web-security-guide/references/logging-monitoring.md +47 -0
- package/knowledge/skills/web-security-guide/references/security-config.md +73 -0
- package/knowledge/skills/web-security-guide/references/ssrf.md +55 -0
- package/knowledge/skills/web-security-guide/references/xss.md +134 -0
- package/package.json +3 -3
- package/server/mcp-core.js +48 -33
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# XSS(跨站脚本攻击)
|
|
2
|
+
|
|
3
|
+
## 1. 漏洞原理
|
|
4
|
+
|
|
5
|
+
- XSS(Cross-Site Scripting) 是指攻击者将恶意脚本注入到网页中,当其他用户访问该网页时,恶意脚本在其浏览器中执行,从而窃取用户信息、劫持账号或控制浏览器。
|
|
6
|
+
- **本质是**:用户输入 -> 未转义输出 -> 浏览器执行脚本。
|
|
7
|
+
|
|
8
|
+
## 2. 漏洞影响
|
|
9
|
+
|
|
10
|
+
- 会话劫持:获取 document.cookie,冒用用户身份
|
|
11
|
+
- 页面伪造:嵌入钓鱼表单,诱导用户操作
|
|
12
|
+
- 权限滥用:使用 JS 执行接口请求,冒用用户操作(CSRF + XSS 联合攻击)
|
|
13
|
+
- 木马注入:植入脚本实现远程控制、广告弹窗、挖矿脚本等
|
|
14
|
+
- 数据篡改:修改页面结构,引导转账、误导点击等
|
|
15
|
+
|
|
16
|
+
## 3. 典型业务场景
|
|
17
|
+
|
|
18
|
+
### 3.1 【反射型 XSS】URL/表单参数未过滤即输出
|
|
19
|
+
|
|
20
|
+
- 原理:攻击者构造 URL,诱导用户点击,恶意代码随参数被反射到页面并执行。
|
|
21
|
+
- 特点:代码不落地,不存储,仅当前响应携带。
|
|
22
|
+
- 漏洞示例代码如下:
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from flask import Flask, request, render_template_string
|
|
26
|
+
app = Flask(__name__)
|
|
27
|
+
|
|
28
|
+
@app.route('/greet')
|
|
29
|
+
def greet():
|
|
30
|
+
name = request.args.get("name")
|
|
31
|
+
return render_template_string("Hello %s" % name)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- 访问 URL:`/greet?name=<script>alert(1)</script>`
|
|
35
|
+
|
|
36
|
+
### 3.2 【存储型 XSS】恶意脚本被写入数据库并展示
|
|
37
|
+
|
|
38
|
+
- 原理:攻击者提交评论、工单内容等含 JS 的文本,系统将其存入数据库并在前端原样输出。
|
|
39
|
+
- 特点:影响持续存在,攻击范围广,可批量感染用户。
|
|
40
|
+
- 漏洞示例代码如下:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
# 假设以下是评论展示逻辑
|
|
44
|
+
@app.route("/comment/<int:id>")
|
|
45
|
+
def show_comment(id):
|
|
46
|
+
content = db.get_comment(id) # 数据库中含 <script> 标签
|
|
47
|
+
return render_template("comment.html", content=content)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- 若 content 来自用户输入,且未转义
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<!-- HTML 模板(Jinja2) -->
|
|
54
|
+
{{ content }}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 3.3 【DOM 型 XSS】JavaScript中操作DOM时拼接用户输入
|
|
58
|
+
|
|
59
|
+
- 原理:客户端 JavaScript 使用 innerHTML、document.write() 等方式拼接不可信输入,导致脚本执行。
|
|
60
|
+
- 特点:漏洞存在于前端代码,绕过后端防御。
|
|
61
|
+
- 漏洞示例代码如下:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
<!-- 不可信输入拼接到 innerHTML 中 -->
|
|
65
|
+
<script>
|
|
66
|
+
const param = new URLSearchParams(location.search).get('msg');
|
|
67
|
+
document.getElementById("result").innerHTML = param;
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- 访问:`http://example.com/?msg=<img src=1 onerror=alert(1)>`
|
|
72
|
+
|
|
73
|
+
### 3.4 【混合型 XSS】后端输出配合前端执行形成复合攻击
|
|
74
|
+
|
|
75
|
+
- 原理:后端将可控输入存入响应,前端再将该值通过 DOM 操作执行,形成复合型 XSS。
|
|
76
|
+
- 特点:攻击链复杂,漏洞位置跨层。
|
|
77
|
+
- 漏洞示例代码如下:
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
<!-- 后端输出:<input id="msg" value="{{ user_input }}" hidden> -->
|
|
81
|
+
<!-- 前端JS拼接未清洗的input值 -->
|
|
82
|
+
<script>
|
|
83
|
+
const msg = document.getElementById("msg").value;
|
|
84
|
+
document.getElementById("box").innerHTML = msg;
|
|
85
|
+
</script>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
- 攻击者输入字段:`"><img src=1 onerror=alert(1)>`
|
|
89
|
+
|
|
90
|
+
## 4. 漏洞修复方案
|
|
91
|
+
|
|
92
|
+
### 4.1 【必须】使用 CSP(内容安全策略)
|
|
93
|
+
|
|
94
|
+
- 限制页面只能加载自身 JS,禁止外链与内联脚本:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 4.2 【必须】后端模板引擎开启自动转义
|
|
101
|
+
|
|
102
|
+
- Flask(Jinja2):默认开启,不要使用 |safe
|
|
103
|
+
- Django:默认开启,严禁对用户输入使用 |safe
|
|
104
|
+
|
|
105
|
+
### 4.3 【必须】所有输入内容严格做 XSS 过滤(非转义)
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from markupsafe import escape
|
|
109
|
+
html = escape(user_input)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 4.4 【必须】严禁前端 innerHTML 拼接用户输入
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
// Bad Code:
|
|
116
|
+
document.getElementById("box").innerHTML = location.search.slice(1);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// Good Code:
|
|
121
|
+
document.getElementById("box").textContent = location.search.slice(1);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 4.5 【必须】禁止在模板中使用 |safe 修饰用户可控字段
|
|
125
|
+
|
|
126
|
+
- 禁止使用:{{ user_input|safe }}
|
|
127
|
+
|
|
128
|
+
### 4.6 【建议】启用 HttpOnly cookie
|
|
129
|
+
|
|
130
|
+
- 避免 JS 读取 cookie
|
|
131
|
+
|
|
132
|
+
### 4.7 【建议】启用 SameSite=Strict
|
|
133
|
+
|
|
134
|
+
- 防止 XSS 联合 CSRF
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blueking/bkui-knowledge",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
4
|
-
"description": "蓝鲸前端知识库 MCP 服务 - 自动同步 skills,支持 Cursor/
|
|
3
|
+
"version": "0.0.1-beta.11",
|
|
4
|
+
"description": "蓝鲸前端知识库 MCP 服务 - 自动同步 skills,支持 Cursor/CodeBuddy",
|
|
5
5
|
"main": "server/mcp-core.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"bkui-knowledge": "./bin/bkui-knowledge.js"
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git"
|
|
22
22
|
},
|
|
23
|
-
"keywords": ["mcp", "cursor", "ai", "knowledge-base", "bkui", "vue3"],
|
|
23
|
+
"keywords": ["mcp", "cursor", "codebuddy", "ai", "knowledge-base", "bkui", "vue3"],
|
|
24
24
|
"author": "ielgnaw",
|
|
25
25
|
"license": "ISC"
|
|
26
26
|
}
|
package/server/mcp-core.js
CHANGED
|
@@ -21,31 +21,17 @@ const KNOWLEDGE_DIR = path.join(ROOT_DIR, 'knowledge');
|
|
|
21
21
|
// 重要: 工具描述会被自动注入到 AI 上下文,因此在此嵌入核心规则
|
|
22
22
|
// ---------------------------------------------------------
|
|
23
23
|
const TOOLS = [
|
|
24
|
-
// L0 工具: 获取索引
|
|
24
|
+
// L0 工具: 获取索引
|
|
25
25
|
{
|
|
26
26
|
name: "get_knowledge_index",
|
|
27
|
-
description:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
|
|
35
|
-
## 强制规范
|
|
36
|
-
- 组件库: bkui-vue (前缀 bk-)
|
|
37
|
-
- 语法: Vue 3 <script setup lang="ts">
|
|
38
|
-
- 样式: MagicBox 原子类 (mt10, mb20)
|
|
39
|
-
|
|
40
|
-
## ⚠️ 常见错误
|
|
41
|
-
- bk-navigation 用 default-open,不是 default-open-keys
|
|
42
|
-
- bk-menu 用 opened-keys,不是 default-open-keys
|
|
43
|
-
- bk-dialog 用 v-model:isShow,不是 v-model
|
|
44
|
-
|
|
45
|
-
## 工作流程
|
|
46
|
-
1. 使用 bk- 组件前,先调用 get_component_api 获取 API
|
|
47
|
-
2. 需要页面模板时,调用 get_skill({ skillId: 'bkui-builder' }) 获取规则
|
|
48
|
-
3. 根据布局分析报告按需加载模版资源`,
|
|
27
|
+
description: `【蓝鲸前端知识库】遇到 bk- 组件、bkui-vue、蓝鲸组件库时必须使用。
|
|
28
|
+
|
|
29
|
+
首次使用时,请先读取 .cursor/skills/bkui-quick-start.md 获取完整规范和索引。
|
|
30
|
+
|
|
31
|
+
快速参考:
|
|
32
|
+
- bk-dialog 用 v-model:isShow(不是 v-model)
|
|
33
|
+
- bk-menu 用 opened-keys(不是 default-open-keys)
|
|
34
|
+
- bk-navigation 用 default-open(不是 default-open-keys)`,
|
|
49
35
|
inputSchema: {
|
|
50
36
|
type: "object",
|
|
51
37
|
properties: {
|
|
@@ -61,7 +47,7 @@ const TOOLS = [
|
|
|
61
47
|
// L1 工具: 获取 Skill 详情
|
|
62
48
|
{
|
|
63
49
|
name: "get_skill",
|
|
64
|
-
description: "获取技能文档 (Markdown)。可用 ID: bkui-builder(设计稿还原),
|
|
50
|
+
description: "获取技能文档 (Markdown)。可用 ID: bkui-quick-start(入门指南), bkui-builder(设计稿还原), bkui-cheatsheet(速查表), api-standard(请求封装), pinia-setup(状态管理), vite-migration(Vite迁移), bundle-optimization(构建优化), virtual-list(虚拟滚动), unit-testing(单测), code-review(代码评审)",
|
|
65
51
|
inputSchema: {
|
|
66
52
|
type: "object",
|
|
67
53
|
properties: {
|
|
@@ -119,6 +105,22 @@ const TOOLS = [
|
|
|
119
105
|
type: "object",
|
|
120
106
|
properties: {}
|
|
121
107
|
}
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// L3 工具: 获取资源文件 (绕过 Cursor FetchMcpResource bug)
|
|
111
|
+
{
|
|
112
|
+
name: "get_resource",
|
|
113
|
+
description: "获取 skill 或 example 资源文件内容。URI 格式: skill://skillId/subDir/path 或 example://componentId/exampleName。用于获取布局模板、代码示例等资源。",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: "object",
|
|
116
|
+
properties: {
|
|
117
|
+
uri: {
|
|
118
|
+
type: "string",
|
|
119
|
+
description: "资源 URI,如: skill://bkui-builder/assets/layouts/admin-layout-dark.vue, example://table/basic"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
required: ["uri"]
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
125
|
];
|
|
124
126
|
|
|
@@ -167,8 +169,9 @@ function buildResources() {
|
|
|
167
169
|
if (manifest.skills && manifest.skills.items) {
|
|
168
170
|
const skillsBasePath = path.join(KNOWLEDGE_DIR, manifest.skills.base_path);
|
|
169
171
|
manifest.skills.items.forEach(skill => {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
+
// 使用 skill.path 推断目录(支持外部 skill)
|
|
173
|
+
const skillDir = path.join(skillsBasePath, path.dirname(skill.path));
|
|
174
|
+
['scripts', 'references', 'assets', 'rules'].forEach(subDir => {
|
|
172
175
|
const subDirPath = path.join(skillDir, subDir);
|
|
173
176
|
if (fs.existsSync(subDirPath)) {
|
|
174
177
|
scanSkillDir(subDirPath, '').forEach(filePath => {
|
|
@@ -289,7 +292,7 @@ const Handlers = {
|
|
|
289
292
|
|
|
290
293
|
// 检查 skill 目录下的附属资源,生成 skill:// URIs
|
|
291
294
|
const skillDir = path.dirname(filePath);
|
|
292
|
-
const subDirs = ['scripts', 'references', 'assets'];
|
|
295
|
+
const subDirs = ['scripts', 'references', 'assets', 'rules'];
|
|
293
296
|
const availableResources = [];
|
|
294
297
|
|
|
295
298
|
subDirs.forEach(dir => {
|
|
@@ -447,7 +450,6 @@ ${recommendedIds.map(id => {
|
|
|
447
450
|
### 同步位置
|
|
448
451
|
|
|
449
452
|
- \`.cursor/skills/*.md\` - 技能文档
|
|
450
|
-
- \`.cursor/commands/*.md\` - 斜杠指令 (可通过 /${recommendedIds[0]} 调用)
|
|
451
453
|
- \`.cursor/rules/bkui.mdc\` - 规则文件 (自动注入 AI 上下文)
|
|
452
454
|
- \`.cursor/.bkui-knowledge-version\` - 版本标记
|
|
453
455
|
|
|
@@ -462,6 +464,17 @@ ${recommendedIds.map(id => {
|
|
|
462
464
|
return { content: [{ type: "text", text: result }] };
|
|
463
465
|
},
|
|
464
466
|
|
|
467
|
+
// L3: 获取资源文件 (绕过 Cursor FetchMcpResource bug)
|
|
468
|
+
async get_resource({ uri }) {
|
|
469
|
+
const result = await readResource(uri);
|
|
470
|
+
// readResource 返回 { content: string } 或 { contents: [{ text }] }
|
|
471
|
+
const text = result.content || (result.contents && result.contents[0] && result.contents[0].text);
|
|
472
|
+
if (!text) {
|
|
473
|
+
throw new Error(`Resource not found or empty: ${uri}`);
|
|
474
|
+
}
|
|
475
|
+
return { content: [{ type: "text", text }] };
|
|
476
|
+
},
|
|
477
|
+
|
|
465
478
|
// Prompt 处理
|
|
466
479
|
async get_prompt({ name }) {
|
|
467
480
|
if (name === "BKUI-EXPERT") {
|
|
@@ -566,8 +579,8 @@ async function handleExampleResource(uri) {
|
|
|
566
579
|
throw new Error(`Example '${exampleName}' not found for ${componentId}. Available: ${compExamples.examples.map(e => e.name).join(', ')}`);
|
|
567
580
|
}
|
|
568
581
|
|
|
569
|
-
// 读取示例文件
|
|
570
|
-
const examplePath = path.join(
|
|
582
|
+
// 读取示例文件 (base_path 相对于 KNOWLEDGE_DIR)
|
|
583
|
+
const examplePath = path.join(KNOWLEDGE_DIR, manifest.componentExamples.base_path, example.file);
|
|
571
584
|
if (!fs.existsSync(examplePath)) {
|
|
572
585
|
throw new Error(`Example file not found: ${example.file}`);
|
|
573
586
|
}
|
|
@@ -588,8 +601,8 @@ async function handleSkillResource(uri) {
|
|
|
588
601
|
|
|
589
602
|
const [, skillId, subDir, filePath] = match;
|
|
590
603
|
|
|
591
|
-
if (!['scripts', 'references', 'assets'].includes(subDir)) {
|
|
592
|
-
throw new Error(`Invalid skill subDir: ${subDir}. Must be scripts, references, or
|
|
604
|
+
if (!['scripts', 'references', 'assets', 'rules'].includes(subDir)) {
|
|
605
|
+
throw new Error(`Invalid skill subDir: ${subDir}. Must be scripts, references, assets, or rules`);
|
|
593
606
|
}
|
|
594
607
|
|
|
595
608
|
const manifest = loadManifest();
|
|
@@ -598,7 +611,9 @@ async function handleSkillResource(uri) {
|
|
|
598
611
|
throw new Error(`Skill not found: ${skillId}`);
|
|
599
612
|
}
|
|
600
613
|
|
|
601
|
-
|
|
614
|
+
// 使用 skill.path 推断目录(支持外部 skill)
|
|
615
|
+
const skillDir = path.dirname(skill.path);
|
|
616
|
+
const fullPath = path.join(KNOWLEDGE_DIR, manifest.skills.base_path, skillDir, subDir, filePath);
|
|
602
617
|
if (!fs.existsSync(fullPath)) {
|
|
603
618
|
throw new Error(`Skill resource not found: ${subDir}/${filePath}`);
|
|
604
619
|
}
|