安全注意事项
AI 生成的代码可能存在安全风险。本章介绍 AI 生成代码的常见安全问题及防范措施,帮助你编写更安全的代码。
AI 代码的安全风险
研究数据
研究表明,AI 生成的代码存在较高的安全风险:
- AI 生成代码的漏洞数量是人工代码的 1.7 倍
- 40% 的 AI 生成代码存在安全问题
- 常见漏洞包括:注入攻击、敏感数据泄露、权限控制缺失
风险来源
- 训练数据问题:AI 从包含漏洞的代码中学习
- 上下文不足:AI 不了解项目的安全要求
- 安全意识缺失:AI 优先考虑功能而非安全
- 验证不充分:开发者未充分审查 AI 生成的代码
常见安全问题
问题一:SQL 注入
markdown
// ❌ AI 可能生成的不安全代码
async function getUser(id: string) {
const query = `SELECT * FROM users WHERE id = ${id}`;
return await db.query(query);
}
// ✅ 安全的代码
async function getUser(id: string) {
return await db.user.findUnique({
where: { id }
});
}
// 或使用参数化查询
async function getUser(id: string) {
const query = 'SELECT * FROM users WHERE id = ?';
return await db.query(query, [id]);
}
```text
**防范措施**:
- 始终使用参数化查询或 ORM
- 验证和清理用户输入
- 让 AI 生成安全的查询代码
```markdown
// 提示词示例
"请使用 Prisma ORM 实现用户查询,确保防止 SQL 注入"
```text
### 问题二:XSS 攻击
```markdown
// ❌ AI 可能生成的不安全代码
function displayUserInput(input: string) {
return `<div>${input}</div>`;
}
// ✅ 安全的代码
import DOMPurify from 'dompurify';
function displayUserInput(input: string) {
const sanitized = DOMPurify.sanitize(input);
return `<div>${sanitized}</div>`;
}
// 或使用框架的安全机制
function UserDisplay({ input }: { input: string }) {
return <div>{input}</div>; // React 自动转义
}
```text
**防范措施**:
- 使用框架的安全机制
- 对用户输入进行转义或清理
- 使用 Content Security Policy (CSP)
```markdown
// 提示词示例
"请实现用户输入显示组件,确保防止 XSS 攻击"
```text
### 问题三:敏感数据泄露
```markdown
// ❌ AI 可能生成的不安全代码
async function login(email: string, password: string) {
const user = await db.user.findUnique({ where: { email } });
console.log('User:', user); // 日志泄露敏感信息
return user;
}
async function getUsers() {
const users = await db.user.findMany();
return users; // 返回所有字段,包括密码
}
// ✅ 安全的代码
async function login(email: string, password: string) {
const user = await db.user.findUnique({
where: { email },
select: {
id: true,
email: true,
password: true // 仅用于验证
}
});
if (!user || !(await bcrypt.compare(password, user.password))) {
return null;
}
// 返回时排除敏感字段
const { password: _, ...safeUser } = user;
return safeUser;
}
async function getUsers() {
return await db.user.findMany({
select: {
id: true,
email: true,
name: true,
createdAt: true
// 排除 password 等敏感字段
}
});
}
```text
**防范措施**:
- 不在日志中输出敏感信息
- 返回数据时排除敏感字段
- 使用环境变量存储密钥
```markdown
// 提示词示例
"请实现用户查询接口,确保不返回密码等敏感字段"
```text
### 问题四:身份验证缺陷
```markdown
// ❌ AI 可能生成的不安全代码
async function login(email: string, password: string) {
const user = await db.user.findUnique({ where: { email } });
if (user && user.password === password) { // 明文比较
return generateToken(user);
}
return null;
}
// ✅ 安全的代码
async function login(email: string, password: string) {
const user = await db.user.findUnique({ where: { email } });
if (!user) {
// 统一错误信息,防止用户枚举
throw new Error('Invalid credentials');
}
// 使用 bcrypt 验证密码
const isValid = await bcrypt.compare(password, user.password);
if (!isValid) {
throw new Error('Invalid credentials');
}
// 检查登录失败次数
if (user.loginAttempts >= 5) {
throw new Error('Account locked');
}
// 重置失败次数
await db.user.update({
where: { id: user.id },
data: { loginAttempts: 0, lastLogin: new Date() }
});
return generateToken(user);
}
```text
**防范措施**:
- 使用加密算法存储密码
- 实现登录失败限制
- 防止用户枚举攻击
- 使用安全的 Session 管理
```markdown
// 提示词示例
"请实现安全的登录功能,包括:
- 使用 bcrypt 加密密码
- 登录失败 5 次锁定账户
- 防止用户枚举攻击"
```text
### 问题五:权限控制缺失
```markdown
// ❌ AI 可能生成的不安全代码
async function deletePost(postId: string) {
// 没有检查用户是否有权限删除
return await db.post.delete({ where: { id: postId } });
}
// ✅ 安全的代码
async function deletePost(postId: string, userId: string) {
const post = await db.post.findUnique({ where: { id: postId } });
if (!post) {
throw new Error('Post not found');
}
// 检查权限
if (post.authorId !== userId) {
throw new Error('Unauthorized');
}
return await db.post.delete({ where: { id: postId } });
}
// 或使用 RBAC
async function deletePost(postId: string, user: User) {
if (!user.permissions.includes('post:delete')) {
throw new Error('Unauthorized');
}
return await db.post.delete({ where: { id: postId } });
}
```text
**防范措施**:
- 实现严格的权限检查
- 使用 RBAC 或 ABAC
- 遵循最小权限原则
```markdown
// 提示词示例
"请实现文章删除功能,确保只有作者可以删除自己的文章"
```text
### 问题六:不安全的依赖
```markdown
// ❌ AI 可能建议使用有漏洞的依赖
"使用 md5 进行密码哈希" // md5 已不安全
// ✅ 使用安全的替代方案
import bcrypt from 'bcrypt';
async function hashPassword(password: string) {
return await bcrypt.hash(password, 10);
}
```text
**防范措施**:
- 审查 AI 建议的依赖
- 检查依赖的安全公告
- 使用 `npm audit` 检查漏洞
```markdown
// 提示词示例
"请使用安全的加密库实现密码哈希功能"
```text
## 安全审查清单
### 代码审查时检查
```markdown
## AI 代码安全审查清单
### 输入验证
- [ ] 所有用户输入都经过验证
- [ ] 使用白名单验证而非黑名单
- [ ] 验证数据类型、长度、格式
- [ ] 防止 SQL 注入、XSS 攻击
### 身份认证
- [ ] 密码使用安全算法加密存储
- [ ] 实现登录失败限制
- [ ] 使用安全的 Session 管理
- [ ] 实现密码重置安全流程
### 权限控制
- [ ] 实现严格的权限检查
- [ ] 遵循最小权限原则
- [ ] 检查资源所有权
- [ ] 防止越权访问
### 数据保护
- [ ] 敏感数据加密存储
- [ ] 不在日志中输出敏感信息
- [ ] API 返回时排除敏感字段
- [ ] 使用 HTTPS 传输
### 错误处理
- [ ] 不暴露敏感错误信息
- [ ] 统一错误响应格式
- [ ] 记录错误日志
- [ ] 防止信息泄露
### 依赖安全
- [ ] 检查依赖的安全公告
- [ ] 定期更新依赖版本
- [ ] 使用 npm audit 检查漏洞
- [ ] 移除不必要的依赖
```text
### 让 AI 进行安全审查
```markdown
// 提示词示例
"请对以下代码进行安全审查,检查:
1. SQL 注入风险
2. XSS 攻击风险
3. 敏感数据泄露
4. 权限控制问题
5. 其他安全漏洞
[代码内容]
请列出所有安全问题并提供修复建议。"
```text
## 安全编码实践
### 实践一:明确安全要求
```markdown
// 在提示词中明确安全要求
"实现用户注册功能,要求:
- 密码使用 bcrypt 加密存储
- 邮箱格式验证
- 密码强度检查(至少 8 位,包含字母和数字)
- 防止重复注册
- 不返回敏感信息"
```text
### 实践二:使用安全库
```markdown
// 让 AI 使用经过验证的安全库
"使用以下安全库实现功能:
- 密码哈希:bcrypt
- 输入验证:Joi 或 Zod
- XSS 防护:DOMPurify
- JWT:jsonwebtoken"
```text
### 实践三:防御性编程
```markdown
// 让 AI 实现防御性编程
"请实现防御性编程:
- 验证所有输入参数
- 处理所有可能的错误
- 检查所有边界条件
- 不信任任何外部数据"
```text
### 实践四:最小权限原则
```markdown
// 让 AI 遵循最小权限原则
"请实现最小权限原则:
- 默认拒绝访问
- 只授予必要的权限
- 检查每个操作的权限"
```text
## 安全测试
### 安全测试用例
```markdown
// 让 AI 生成安全测试用例
"请为登录功能生成安全测试用例:
- SQL 注入测试
- XSS 攻击测试
- 暴力破解测试
- 用户枚举测试
- Session 劫持测试"
// AI 生成的测试
```typescript
describe('Login Security', () => {
test('防止 SQL 注入', async () => {
const response = await request(app)
.post('/login')
.send({
email: "admin'--@example.com",
password: 'anything'
});
expect(response.status).toBe(401);
expect(response.body.message).not.toContain('SQL');
});
test('防止 XSS 攻击', async () => {
const response = await request(app)
.post('/login')
.send({
email: 'test@example.com',
password: '<script>alert("xss")</script>'
});
expect(response.status).toBe(401);
expect(response.body.message).not.toContain('<script>');
});
test('防止暴力破解', async () => {
// 连续失败 5 次
for (let i = 0; i < 5; i++) {
await request(app)
.post('/login')
.send({
email: 'test@example.com',
password: 'wrong'
});
}
// 第 6 次应该被锁定
const response = await request(app)
.post('/login')
.send({
email: 'test@example.com',
password: 'correct'
});
expect(response.status).toBe(403);
expect(response.body.message).toContain('locked');
});
test('防止用户枚举', async () => {
const response1 = await request(app)
.post('/login')
.send({
email: 'nonexistent@example.com',
password: 'anything'
});
const response2 = await request(app)
.post('/login')
.send({
email: 'existing@example.com',
password: 'wrong'
});
// 两种情况的错误信息应该相同
expect(response1.body.message).toBe(response2.body.message);
});
});
```text
```text
## 安全工具
### 静态分析工具
```bash
# 使用 ESLint 安全插件
npm install --save-dev eslint-plugin-security
# 使用 npm audit
npm audit
# 使用 Snyk
npx snyk test
```text
### 依赖检查
```bash
# 检查过时的依赖
npm outdated
# 检查安全漏洞
npm audit fix
# 使用 better-npm-audit
npx better-npm-audit audit
```text
## 小结
AI 代码安全的关键点:
1. **认识风险**:AI 生成的代码可能存在安全漏洞
2. **审查代码**:始终审查 AI 生成的代码
3. **明确要求**:在提示词中明确安全要求
4. **使用安全库**:使用经过验证的安全库
5. **安全测试**:生成并执行安全测试用例
6. **持续检查**:使用工具持续检查安全问题
安全是开发者的责任,不能完全依赖 AI。审查 AI 生成的代码是保证安全的关键。
---
## 参考资料
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
- [Web Security Basics](https://developer.mozilla.org/en-US/docs/Web/Security)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492