第9章:安全性和权限控制
2025/9/1大约 18 分钟
第9章:安全性和权限控制
学习目标
- 理解MCP的安全模型和威胁防护
- 实现身份验证和授权机制
- 掌握资源访问权限控制
- 学习输入验证和数据净化
- 实现安全审计和监控
9.1 MCP安全模型和威胁分析
9.1.1 安全威胁模型
MCP Server面临的主要安全威胁:
// src/security/ThreatModel.ts
export enum ThreatCategory {
AUTHENTICATION = 'authentication',
AUTHORIZATION = 'authorization',
INPUT_VALIDATION = 'input_validation',
DATA_EXPOSURE = 'data_exposure',
RESOURCE_ACCESS = 'resource_access',
DENIAL_OF_SERVICE = 'denial_of_service',
CODE_INJECTION = 'code_injection',
PRIVILEGE_ESCALATION = 'privilege_escalation',
}
export interface SecurityThreat {
id: string;
category: ThreatCategory;
severity: 'low' | 'medium' | 'high' | 'critical';
description: string;
impact: string;
mitigations: string[];
examples?: string[];
}
export const COMMON_THREATS: SecurityThreat[] = [
{
id: 'UNAUTH_ACCESS',
category: ThreatCategory.AUTHENTICATION,
severity: 'critical',
description: '未经身份验证的访问',
impact: '恶意用户可能获得未授权访问系统资源的能力',
mitigations: [
'实施强制身份验证',
'使用安全的认证协议',
'实施会话管理',
'启用账户锁定机制'
],
examples: [
'直接访问敏感工具而无需验证',
'绕过认证机制访问资源'
]
},
{
id: 'PRIVILEGE_ESC',
category: ThreatCategory.PRIVILEGE_ESCALATION,
severity: 'high',
description: '权限提升攻击',
impact: '低权限用户获得高权限操作能力',
mitigations: [
'实施最小权限原则',
'定期审计权限分配',
'使用基于角色的访问控制',
'实施权限边界检查'
]
},
{
id: 'INJECTION_ATTACK',
category: ThreatCategory.CODE_INJECTION,
severity: 'critical',
description: '代码注入攻击',
impact: '恶意代码执行可能导致系统完全控制',
mitigations: [
'严格的输入验证',
'使用参数化查询',
'实施输入净化',
'代码执行沙盒'
],
examples: [
'SQL注入攻击',
'命令注入攻击',
'Script注入攻击'
]
},
{
id: 'DATA_LEAK',
category: ThreatCategory.DATA_EXPOSURE,
severity: 'high',
description: '敏感数据泄露',
impact: '机密信息可能被未授权访问或泄露',
mitigations: [
'数据分类和标记',
'访问控制策略',
'数据加密存储',
'审计日志监控'
]
},
{
id: 'DOS_ATTACK',
category: ThreatCategory.DENIAL_OF_SERVICE,
severity: 'medium',
description: '拒绝服务攻击',
impact: '服务可用性受到影响',
mitigations: [
'请求速率限制',
'资源使用监控',
'请求大小限制',
'连接数限制'
]
}
];
export class SecurityAssessment {
private threats: Map<string, SecurityThreat> = new Map();
private assessmentResults: Map<string, SecurityAssessmentResult> = new Map();
constructor() {
COMMON_THREATS.forEach(threat => {
this.threats.set(threat.id, threat);
});
}
async assessThreat(threatId: string, context: any): Promise<SecurityAssessmentResult> {
const threat = this.threats.get(threatId);
if (!threat) {
throw new Error(`Unknown threat: ${threatId}`);
}
const result: SecurityAssessmentResult = {
threatId,
assessedAt: new Date(),
riskLevel: this.calculateRiskLevel(threat, context),
mitigationsApplied: [],
recommendations: [...threat.mitigations],
context,
};
this.assessmentResults.set(threatId, result);
return result;
}
private calculateRiskLevel(threat: SecurityThreat, context: any): 'low' | 'medium' | 'high' | 'critical' {
// 简化的风险计算逻辑
let riskLevel = threat.severity;
// 根据上下文调整风险级别
if (context.hasPublicAccess && riskLevel !== 'critical') {
riskLevel = this.increaseSeverity(riskLevel);
}
if (context.hasPrivilegedOperations && riskLevel !== 'critical') {
riskLevel = this.increaseSeverity(riskLevel);
}
return riskLevel;
}
private increaseSeverity(current: string): 'low' | 'medium' | 'high' | 'critical' {
switch (current) {
case 'low': return 'medium';
case 'medium': return 'high';
case 'high': return 'critical';
default: return 'critical';
}
}
}
export interface SecurityAssessmentResult {
threatId: string;
assessedAt: Date;
riskLevel: 'low' | 'medium' | 'high' | 'critical';
mitigationsApplied: string[];
recommendations: string[];
context: any;
}
9.1.2 安全配置和策略
// src/security/SecurityConfig.ts
export interface SecurityConfig {
authentication: {
required: boolean;
methods: AuthMethod[];
sessionTimeout: number; // milliseconds
maxLoginAttempts: number;
lockoutDuration: number; // milliseconds
};
authorization: {
model: 'rbac' | 'abac' | 'none';
defaultRole?: string;
requireExplicitPermissions: boolean;
};
inputValidation: {
enableStrictValidation: boolean;
maxPayloadSize: number; // bytes
allowedContentTypes: string[];
sanitizeInputs: boolean;
};
rateLimiting: {
enabled: boolean;
windowMs: number;
maxRequests: number;
skipSuccessfulRequests?: boolean;
};
encryption: {
algorithm: string;
keySize: number;
encryptSensitiveData: boolean;
};
audit: {
enabled: boolean;
logLevel: 'minimal' | 'standard' | 'detailed';
retentionDays: number;
};
cors: {
enabled: boolean;
allowedOrigins: string[];
allowedMethods: string[];
allowedHeaders: string[];
credentials: boolean;
};
}
export const DEFAULT_SECURITY_CONFIG: SecurityConfig = {
authentication: {
required: true,
methods: [AuthMethod.API_KEY],
sessionTimeout: 3600000, // 1 hour
maxLoginAttempts: 5,
lockoutDuration: 900000, // 15 minutes
},
authorization: {
model: 'rbac',
defaultRole: 'user',
requireExplicitPermissions: true,
},
inputValidation: {
enableStrictValidation: true,
maxPayloadSize: 1024 * 1024, // 1MB
allowedContentTypes: ['application/json'],
sanitizeInputs: true,
},
rateLimiting: {
enabled: true,
windowMs: 60000, // 1 minute
maxRequests: 100,
skipSuccessfulRequests: false,
},
encryption: {
algorithm: 'aes-256-gcm',
keySize: 32,
encryptSensitiveData: true,
},
audit: {
enabled: true,
logLevel: 'standard',
retentionDays: 30,
},
cors: {
enabled: false,
allowedOrigins: [],
allowedMethods: ['POST'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: false,
},
};
export enum AuthMethod {
API_KEY = 'api_key',
JWT = 'jwt',
OAUTH2 = 'oauth2',
BASIC = 'basic',
}
9.2 身份验证系统
9.2.1 认证接口和实现
// src/auth/Authentication.ts
export interface AuthenticationProvider {
name: string;
authenticate(credentials: any): Promise<AuthenticationResult>;
validateToken(token: string): Promise<TokenValidationResult>;
refreshToken?(refreshToken: string): Promise<RefreshTokenResult>;
}
export interface AuthenticationResult {
success: boolean;
user?: UserInfo;
token?: string;
refreshToken?: string;
expiresAt?: Date;
error?: string;
}
export interface TokenValidationResult {
valid: boolean;
user?: UserInfo;
expiresAt?: Date;
error?: string;
}
export interface RefreshTokenResult {
success: boolean;
token?: string;
refreshToken?: string;
expiresAt?: Date;
error?: string;
}
export interface UserInfo {
id: string;
username: string;
email?: string;
roles: string[];
permissions: string[];
metadata?: Record<string, any>;
}
// API Key Authentication Provider
export class ApiKeyAuthProvider implements AuthenticationProvider {
name = 'api_key';
private apiKeys = new Map<string, UserInfo>();
private hashedKeys = new Map<string, string>(); // hashed -> original
constructor(private secretKey: string) {}
async authenticate(credentials: { apiKey: string }): Promise<AuthenticationResult> {
if (!credentials.apiKey) {
return {
success: false,
error: 'API key is required',
};
}
const hashedKey = await this.hashApiKey(credentials.apiKey);
const user = this.apiKeys.get(hashedKey);
if (!user) {
return {
success: false,
error: 'Invalid API key',
};
}
return {
success: true,
user,
token: credentials.apiKey, // API key serves as token
};
}
async validateToken(token: string): Promise<TokenValidationResult> {
const hashedKey = await this.hashApiKey(token);
const user = this.apiKeys.get(hashedKey);
return {
valid: !!user,
user,
error: user ? undefined : 'Invalid token',
};
}
async addApiKey(apiKey: string, user: UserInfo): Promise<void> {
const hashedKey = await this.hashApiKey(apiKey);
this.apiKeys.set(hashedKey, user);
this.hashedKeys.set(hashedKey, apiKey);
}
async revokeApiKey(apiKey: string): Promise<boolean> {
const hashedKey = await this.hashApiKey(apiKey);
const existed = this.apiKeys.has(hashedKey);
this.apiKeys.delete(hashedKey);
this.hashedKeys.delete(hashedKey);
return existed;
}
private async hashApiKey(apiKey: string): Promise<string> {
const crypto = await import('crypto');
return crypto
.createHmac('sha256', this.secretKey)
.update(apiKey)
.digest('hex');
}
}
// JWT Authentication Provider
export class JWTAuthProvider implements AuthenticationProvider {
name = 'jwt';
constructor(
private secretKey: string,
private issuer: string = 'mcp-server',
private expirationTime: string = '1h'
) {}
async authenticate(credentials: { username: string; password: string }): Promise<AuthenticationResult> {
// 这里应该验证用户名和密码
const user = await this.validateUserCredentials(credentials.username, credentials.password);
if (!user) {
return {
success: false,
error: 'Invalid credentials',
};
}
const jwt = await import('jsonwebtoken');
const token = jwt.sign(
{
sub: user.id,
username: user.username,
roles: user.roles,
permissions: user.permissions,
},
this.secretKey,
{
issuer: this.issuer,
expiresIn: this.expirationTime,
}
);
return {
success: true,
user,
token,
expiresAt: new Date(Date.now() + 3600000), // 1 hour
};
}
async validateToken(token: string): Promise<TokenValidationResult> {
try {
const jwt = await import('jsonwebtoken');
const decoded = jwt.verify(token, this.secretKey) as any;
const user: UserInfo = {
id: decoded.sub,
username: decoded.username,
roles: decoded.roles || [],
permissions: decoded.permissions || [],
};
return {
valid: true,
user,
expiresAt: new Date(decoded.exp * 1000),
};
} catch (error) {
return {
valid: false,
error: error instanceof Error ? error.message : 'Token validation failed',
};
}
}
async refreshToken(refreshToken: string): Promise<RefreshTokenResult> {
try {
const jwt = await import('jsonwebtoken');
const decoded = jwt.verify(refreshToken, this.secretKey) as any;
// 生成新的访问令牌
const newToken = jwt.sign(
{
sub: decoded.sub,
username: decoded.username,
roles: decoded.roles,
permissions: decoded.permissions,
},
this.secretKey,
{
issuer: this.issuer,
expiresIn: this.expirationTime,
}
);
return {
success: true,
token: newToken,
refreshToken, // 保持相同的刷新令牌
expiresAt: new Date(Date.now() + 3600000),
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Refresh token validation failed',
};
}
}
private async validateUserCredentials(username: string, password: string): Promise<UserInfo | null> {
// 这里应该查询数据库或其他用户存储
// 为了示例,返回一个模拟用户
if (username === 'admin' && password === 'password123') {
return {
id: 'admin-001',
username: 'admin',
email: 'admin@example.com',
roles: ['admin'],
permissions: ['*'],
};
}
return null;
}
}
// Authentication Manager
export class AuthenticationManager {
private providers = new Map<string, AuthenticationProvider>();
private defaultProvider?: string;
private logger: Logger;
constructor(logger: Logger) {
this.logger = logger.child({}, 'auth');
}
registerProvider(provider: AuthenticationProvider): void {
this.providers.set(provider.name, provider);
if (!this.defaultProvider) {
this.defaultProvider = provider.name;
}
this.logger.info(`Authentication provider registered: ${provider.name}`);
}
setDefaultProvider(name: string): void {
if (!this.providers.has(name)) {
throw new Error(`Provider not found: ${name}`);
}
this.defaultProvider = name;
}
async authenticate(
credentials: any,
providerName?: string
): Promise<AuthenticationResult> {
const provider = this.getProvider(providerName);
try {
const result = await provider.authenticate(credentials);
await this.logger.info(
`Authentication attempt: ${result.success ? 'success' : 'failure'}`,
{
provider: provider.name,
username: credentials.username || 'unknown',
success: result.success,
}
);
return result;
} catch (error) {
await this.logger.error(
'Authentication error',
error instanceof Error ? error : new Error(String(error)),
{ provider: provider.name }
);
return {
success: false,
error: 'Authentication system error',
};
}
}
async validateToken(
token: string,
providerName?: string
): Promise<TokenValidationResult> {
const provider = this.getProvider(providerName);
try {
return await provider.validateToken(token);
} catch (error) {
await this.logger.error(
'Token validation error',
error instanceof Error ? error : new Error(String(error)),
{ provider: provider.name }
);
return {
valid: false,
error: 'Token validation system error',
};
}
}
private getProvider(name?: string): AuthenticationProvider {
const providerName = name || this.defaultProvider;
if (!providerName) {
throw new Error('No authentication provider configured');
}
const provider = this.providers.get(providerName);
if (!provider) {
throw new Error(`Provider not found: ${providerName}`);
}
return provider;
}
}
9.3 授权和权限控制
9.3.1 基于角色的访问控制(RBAC)
// src/auth/Authorization.ts
export interface Permission {
id: string;
name: string;
description: string;
resource: string;
action: string;
conditions?: PermissionCondition[];
}
export interface PermissionCondition {
type: 'time' | 'ip' | 'resource_owner' | 'custom';
operator: 'equals' | 'in' | 'not_in' | 'greater_than' | 'less_than';
value: any;
}
export interface Role {
id: string;
name: string;
description: string;
permissions: string[]; // Permission IDs
inherits?: string[]; // Parent role IDs
}
export interface AuthorizationContext {
user: UserInfo;
resource: string;
action: string;
metadata?: Record<string, any>;
timestamp: Date;
clientInfo?: {
ip?: string;
userAgent?: string;
};
}
export interface AuthorizationResult {
allowed: boolean;
reason?: string;
matchedPermissions?: Permission[];
failedConditions?: PermissionCondition[];
}
export class RBACAuthorizationProvider {
private permissions = new Map<string, Permission>();
private roles = new Map<string, Role>();
private logger: Logger;
constructor(logger: Logger) {
this.logger = logger.child({}, 'rbac');
this.setupDefaultPermissions();
this.setupDefaultRoles();
}
// 权限管理
addPermission(permission: Permission): void {
this.permissions.set(permission.id, permission);
this.logger.debug('Permission added', { permissionId: permission.id });
}
addRole(role: Role): void {
// 验证权限存在
for (const permissionId of role.permissions) {
if (!this.permissions.has(permissionId)) {
throw new Error(`Permission not found: ${permissionId}`);
}
}
// 验证继承角色存在
if (role.inherits) {
for (const parentRoleId of role.inherits) {
if (!this.roles.has(parentRoleId)) {
throw new Error(`Parent role not found: ${parentRoleId}`);
}
}
}
this.roles.set(role.id, role);
this.logger.debug('Role added', { roleId: role.id });
}
// 授权检查
async authorize(context: AuthorizationContext): Promise<AuthorizationResult> {
const userPermissions = await this.getUserPermissions(context.user);
// 检查是否有匹配的权限
const matchedPermissions: Permission[] = [];
const failedConditions: PermissionCondition[] = [];
for (const permission of userPermissions) {
if (this.matchesResourceAndAction(permission, context.resource, context.action)) {
// 检查条件
const conditionResult = await this.evaluateConditions(permission, context);
if (conditionResult.success) {
matchedPermissions.push(permission);
} else {
failedConditions.push(...(conditionResult.failedConditions || []));
}
}
}
const allowed = matchedPermissions.length > 0;
await this.logger.info(
`Authorization ${allowed ? 'granted' : 'denied'}`,
{
userId: context.user.id,
resource: context.resource,
action: context.action,
matchedPermissions: matchedPermissions.length,
reason: allowed ? 'permissions matched' : 'no matching permissions',
}
);
return {
allowed,
reason: allowed ? 'Access granted' : 'No matching permissions found',
matchedPermissions,
failedConditions: failedConditions.length > 0 ? failedConditions : undefined,
};
}
// 获取用户所有权限(包括继承的)
private async getUserPermissions(user: UserInfo): Promise<Permission[]> {
const allPermissions = new Set<Permission>();
// 直接权限
for (const permissionId of user.permissions) {
const permission = this.permissions.get(permissionId);
if (permission) {
allPermissions.add(permission);
}
}
// 角色权限
for (const roleId of user.roles) {
const rolePermissions = await this.getRolePermissions(roleId);
rolePermissions.forEach(p => allPermissions.add(p));
}
return Array.from(allPermissions);
}
// 获取角色权限(递归处理继承)
private async getRolePermissions(roleId: string, visited = new Set<string>()): Promise<Permission[]> {
if (visited.has(roleId)) {
this.logger.warn('Circular role inheritance detected', { roleId });
return [];
}
visited.add(roleId);
const role = this.roles.get(roleId);
if (!role) {
return [];
}
const permissions = new Set<Permission>();
// 直接权限
for (const permissionId of role.permissions) {
const permission = this.permissions.get(permissionId);
if (permission) {
permissions.add(permission);
}
}
// 继承权限
if (role.inherits) {
for (const parentRoleId of role.inherits) {
const parentPermissions = await this.getRolePermissions(parentRoleId, new Set(visited));
parentPermissions.forEach(p => permissions.add(p));
}
}
return Array.from(permissions);
}
private matchesResourceAndAction(permission: Permission, resource: string, action: string): boolean {
// 支持通配符匹配
const resourceMatches = permission.resource === '*' ||
permission.resource === resource ||
resource.startsWith(permission.resource.replace('*', ''));
const actionMatches = permission.action === '*' ||
permission.action === action ||
action.startsWith(permission.action.replace('*', ''));
return resourceMatches && actionMatches;
}
private async evaluateConditions(
permission: Permission,
context: AuthorizationContext
): Promise<{ success: boolean; failedConditions?: PermissionCondition[] }> {
if (!permission.conditions || permission.conditions.length === 0) {
return { success: true };
}
const failedConditions: PermissionCondition[] = [];
for (const condition of permission.conditions) {
const result = await this.evaluateCondition(condition, context);
if (!result) {
failedConditions.push(condition);
}
}
return {
success: failedConditions.length === 0,
failedConditions: failedConditions.length > 0 ? failedConditions : undefined,
};
}
private async evaluateCondition(condition: PermissionCondition, context: AuthorizationContext): Promise<boolean> {
switch (condition.type) {
case 'time':
return this.evaluateTimeCondition(condition, context);
case 'ip':
return this.evaluateIPCondition(condition, context);
case 'resource_owner':
return this.evaluateResourceOwnerCondition(condition, context);
case 'custom':
return this.evaluateCustomCondition(condition, context);
default:
this.logger.warn('Unknown condition type', { type: condition.type });
return false;
}
}
private evaluateTimeCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
const currentHour = context.timestamp.getHours();
switch (condition.operator) {
case 'greater_than':
return currentHour > condition.value;
case 'less_than':
return currentHour < condition.value;
case 'in':
return Array.isArray(condition.value) && condition.value.includes(currentHour);
default:
return false;
}
}
private evaluateIPCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
const clientIP = context.clientInfo?.ip;
if (!clientIP) return false;
switch (condition.operator) {
case 'equals':
return clientIP === condition.value;
case 'in':
return Array.isArray(condition.value) && condition.value.includes(clientIP);
case 'not_in':
return Array.isArray(condition.value) && !condition.value.includes(clientIP);
default:
return false;
}
}
private evaluateResourceOwnerCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
const resourceOwner = context.metadata?.owner;
return resourceOwner === context.user.id;
}
private evaluateCustomCondition(condition: PermissionCondition, context: AuthorizationContext): boolean {
// 这里可以实现自定义条件评估逻辑
return false;
}
private setupDefaultPermissions(): void {
// 工具权限
this.addPermission({
id: 'tools.list',
name: 'List Tools',
description: '查看可用工具列表',
resource: 'tools',
action: 'list',
});
this.addPermission({
id: 'tools.execute',
name: 'Execute Tools',
description: '执行工具',
resource: 'tools',
action: 'execute',
});
// 资源权限
this.addPermission({
id: 'resources.read',
name: 'Read Resources',
description: '读取资源',
resource: 'resources',
action: 'read',
});
this.addPermission({
id: 'resources.write',
name: 'Write Resources',
description: '写入资源',
resource: 'resources',
action: 'write',
conditions: [
{
type: 'resource_owner',
operator: 'equals',
value: true,
},
],
});
// 管理权限
this.addPermission({
id: 'admin.all',
name: 'Admin All',
description: '管理员权限',
resource: '*',
action: '*',
});
}
private setupDefaultRoles(): void {
this.addRole({
id: 'guest',
name: 'Guest',
description: '访客角色',
permissions: ['tools.list'],
});
this.addRole({
id: 'user',
name: 'User',
description: '普通用户角色',
permissions: ['tools.list', 'tools.execute', 'resources.read'],
inherits: ['guest'],
});
this.addRole({
id: 'admin',
name: 'Administrator',
description: '管理员角色',
permissions: ['admin.all'],
});
}
}
9.4 输入验证和数据净化
9.4.1 输入验证系统
// src/validation/InputValidator.ts
import { z } from 'zod';
export interface ValidationRule {
name: string;
schema: z.ZodSchema;
sanitizer?: (input: any) => any;
}
export interface ValidationResult {
valid: boolean;
data?: any;
errors?: ValidationError[];
sanitizedData?: any;
}
export interface ValidationError {
field: string;
message: string;
code: string;
value?: any;
}
export class InputValidator {
private rules = new Map<string, ValidationRule>();
private logger: Logger;
constructor(logger: Logger) {
this.logger = logger.child({}, 'validation');
this.setupDefaultRules();
}
addRule(name: string, rule: ValidationRule): void {
this.rules.set(name, rule);
this.logger.debug('Validation rule added', { name });
}
async validate(ruleName: string, input: any): Promise<ValidationResult> {
const rule = this.rules.get(ruleName);
if (!rule) {
return {
valid: false,
errors: [{
field: 'rule',
message: `Validation rule not found: ${ruleName}`,
code: 'RULE_NOT_FOUND',
}],
};
}
try {
// 首先进行数据净化
const sanitizedData = rule.sanitizer ? rule.sanitizer(input) : input;
// 然后进行验证
const validatedData = rule.schema.parse(sanitizedData);
return {
valid: true,
data: validatedData,
sanitizedData,
};
} catch (error) {
if (error instanceof z.ZodError) {
const validationErrors: ValidationError[] = error.errors.map(e => ({
field: e.path.join('.'),
message: e.message,
code: e.code,
value: e.input,
}));
await this.logger.warn('Validation failed', {
rule: ruleName,
errors: validationErrors.length,
input: this.sanitizeLogInput(input),
});
return {
valid: false,
errors: validationErrors,
};
}
await this.logger.error(
'Validation error',
error instanceof Error ? error : new Error(String(error)),
{ rule: ruleName }
);
return {
valid: false,
errors: [{
field: 'validation',
message: 'Validation system error',
code: 'SYSTEM_ERROR',
}],
};
}
}
private setupDefaultRules(): void {
// MCP请求验证
this.addRule('mcp-request', {
name: 'MCP Request',
schema: z.object({
jsonrpc: z.string().refine(v => v === '2.0'),
id: z.union([z.string(), z.number()]).optional(),
method: z.string().min(1).max(100),
params: z.record(z.unknown()).optional(),
}),
sanitizer: (input) => ({
...input,
method: typeof input?.method === 'string' ? input.method.trim() : input?.method,
}),
});
// 工具执行参数验证
this.addRule('tool-execution', {
name: 'Tool Execution',
schema: z.object({
name: z.string().min(1).max(100).regex(/^[a-zA-Z0-9_-]+$/),
arguments: z.record(z.unknown()).optional(),
}),
sanitizer: (input) => ({
...input,
name: typeof input?.name === 'string' ? input.name.trim() : input?.name,
}),
});
// 资源URI验证
this.addRule('resource-uri', {
name: 'Resource URI',
schema: z.string().min(1).max(2048).refine(uri => {
try {
new URL(uri);
return true;
} catch {
return uri.match(/^[a-zA-Z][a-zA-Z0-9+.-]*:.+$/);
}
}, 'Must be a valid URI'),
sanitizer: (input) => typeof input === 'string' ? input.trim() : input,
});
// 文件路径验证
this.addRule('file-path', {
name: 'File Path',
schema: z.string().min(1).max(4096).refine(path => {
// 防止路径遍历攻击
const normalizedPath = path.replace(/\\/g, '/');
return !normalizedPath.includes('../') &&
!normalizedPath.includes('./') &&
!normalizedPath.startsWith('/') &&
!normalizedPath.includes('//');
}, 'Invalid file path'),
sanitizer: (input) => {
if (typeof input !== 'string') return input;
// 规范化路径分隔符并移除危险字符
return input.replace(/\\/g, '/').replace(/[<>:"|?*]/g, '');
},
});
}
private sanitizeLogInput(input: any): any {
// 避免在日志中记录敏感信息
if (typeof input === 'object' && input !== null) {
const sanitized = { ...input };
const sensitiveFields = ['password', 'token', 'apiKey', 'secret'];
for (const field of sensitiveFields) {
if (field in sanitized) {
sanitized[field] = '[REDACTED]';
}
}
return sanitized;
}
return input;
}
}
// 数据净化工具
export class DataSanitizer {
static sanitizeHtml(input: string): string {
// 简单的HTML净化,实际应用中应使用专门的库如DOMPurify
return input
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/');
}
static sanitizeSQL(input: string): string {
// SQL注入防护
return input.replace(/['";\\]/g, '\\$&');
}
static sanitizeCommandLine(input: string): string {
// 命令行注入防护
return input.replace(/[;&|`$(){}[\]<>*?~]/g, '\\$&');
}
static sanitizeFileName(input: string): string {
// 文件名净化
return input.replace(/[^a-zA-Z0-9._-]/g, '_').substring(0, 255);
}
static limitString(input: string, maxLength: number = 1000): string {
return input.length > maxLength ? input.substring(0, maxLength) + '...' : input;
}
static removeNullBytes(input: string): string {
return input.replace(/\0/g, '');
}
}
9.5 速率限制和DDoS防护
9.5.1 请求速率限制
// src/security/RateLimiter.ts
export interface RateLimitConfig {
windowMs: number; // 时间窗口(毫秒)
maxRequests: number; // 最大请求数
skipSuccessfulRequests?: boolean; // 是否跳过成功请求
skipFailedRequests?: boolean; // 是否跳过失败请求
keyGenerator?: (context: any) => string; // 键生成器
}
export interface RateLimitResult {
allowed: boolean;
remaining: number;
resetTime: Date;
retryAfter?: number; // 秒
}
export class RateLimiter {
private requests = new Map<string, RequestRecord[]>();
private logger: Logger;
constructor(
private config: RateLimitConfig,
logger: Logger
) {
this.logger = logger.child({}, 'rate-limiter');
// 定期清理过期记录
setInterval(() => {
this.cleanExpiredRecords();
}, Math.min(this.config.windowMs, 60000)); // 最多每分钟清理一次
}
async checkLimit(context: any): Promise<RateLimitResult> {
const key = this.config.keyGenerator ? this.config.keyGenerator(context) : 'default';
const now = Date.now();
const windowStart = now - this.config.windowMs;
// 获取或创建请求记录
let records = this.requests.get(key) || [];
// 清理过期记录
records = records.filter(record => record.timestamp > windowStart);
// 计算剩余配额
const remaining = Math.max(0, this.config.maxRequests - records.length);
const resetTime = new Date(now + this.config.windowMs);
const result: RateLimitResult = {
allowed: remaining > 0,
remaining: remaining > 0 ? remaining - 1 : 0,
resetTime,
};
if (!result.allowed) {
// 计算重试时间
const oldestRecord = records[0];
if (oldestRecord) {
result.retryAfter = Math.ceil((oldestRecord.timestamp + this.config.windowMs - now) / 1000);
}
await this.logger.warn('Rate limit exceeded', {
key,
requests: records.length,
limit: this.config.maxRequests,
windowMs: this.config.windowMs,
});
}
// 如果允许请求,记录本次请求
if (result.allowed) {
records.push({
timestamp: now,
success: undefined, // 将在请求完成后更新
});
this.requests.set(key, records);
}
return result;
}
markRequestComplete(context: any, success: boolean): void {
if (
(success && this.config.skipSuccessfulRequests) ||
(!success && this.config.skipFailedRequests)
) {
const key = this.config.keyGenerator ? this.config.keyGenerator(context) : 'default';
const records = this.requests.get(key);
if (records && records.length > 0) {
// 移除最后一个记录
records.pop();
if (records.length === 0) {
this.requests.delete(key);
}
}
}
}
private cleanExpiredRecords(): void {
const now = Date.now();
const windowStart = now - this.config.windowMs;
for (const [key, records] of this.requests) {
const validRecords = records.filter(record => record.timestamp > windowStart);
if (validRecords.length === 0) {
this.requests.delete(key);
} else if (validRecords.length < records.length) {
this.requests.set(key, validRecords);
}
}
}
getStats(): { totalKeys: number; totalRequests: number } {
let totalRequests = 0;
for (const records of this.requests.values()) {
totalRequests += records.length;
}
return {
totalKeys: this.requests.size,
totalRequests,
};
}
reset(key?: string): void {
if (key) {
this.requests.delete(key);
this.logger.info('Rate limit reset for key', { key });
} else {
this.requests.clear();
this.logger.info('All rate limits reset');
}
}
}
interface RequestRecord {
timestamp: number;
success?: boolean;
}
// 多层速率限制器
export class MultiTierRateLimiter {
private limiters = new Map<string, RateLimiter>();
private logger: Logger;
constructor(logger: Logger) {
this.logger = logger.child({}, 'multi-tier-limiter');
}
addTier(name: string, config: RateLimitConfig): void {
this.limiters.set(name, new RateLimiter(config, this.logger));
this.logger.info('Rate limit tier added', { name, config });
}
async checkAllTiers(context: any): Promise<{ allowed: boolean; tier?: string; result?: RateLimitResult }> {
for (const [tierName, limiter] of this.limiters) {
const result = await limiter.checkLimit(context);
if (!result.allowed) {
return {
allowed: false,
tier: tierName,
result,
};
}
}
return { allowed: true };
}
markComplete(context: any, success: boolean): void {
for (const limiter of this.limiters.values()) {
limiter.markRequestComplete(context, success);
}
}
}
// 自适应速率限制器
export class AdaptiveRateLimiter extends RateLimiter {
private successRate = 1.0;
private errorRate = 0.0;
private adaptiveMultiplier = 1.0;
private minMultiplier = 0.1;
private maxMultiplier = 2.0;
private adaptationWindow = 60000; // 1分钟
constructor(config: RateLimitConfig, logger: Logger) {
super(config, logger);
// 定期调整速率限制
setInterval(() => {
this.adjustRateLimit();
}, this.adaptationWindow);
}
async checkLimit(context: any): Promise<RateLimitResult> {
const baseResult = await super.checkLimit(context);
// 应用自适应调整
const adjustedMaxRequests = Math.floor(this.config.maxRequests * this.adaptiveMultiplier);
const adjustedRemaining = Math.floor(baseResult.remaining * this.adaptiveMultiplier);
return {
...baseResult,
allowed: adjustedRemaining > 0,
remaining: Math.max(0, adjustedRemaining),
};
}
recordResult(success: boolean): void {
// 更新成功率统计
const alpha = 0.1; // 指数移动平均系数
if (success) {
this.successRate = alpha + (1 - alpha) * this.successRate;
this.errorRate = (1 - alpha) * this.errorRate;
} else {
this.errorRate = alpha + (1 - alpha) * this.errorRate;
this.successRate = (1 - alpha) * this.successRate;
}
}
private adjustRateLimit(): void {
const previousMultiplier = this.adaptiveMultiplier;
// 根据错误率调整速率限制
if (this.errorRate > 0.1) {
// 错误率高,降低速率限制
this.adaptiveMultiplier *= 0.8;
} else if (this.errorRate < 0.01) {
// 错误率低,提高速率限制
this.adaptiveMultiplier *= 1.1;
}
// 限制调整范围
this.adaptiveMultiplier = Math.max(this.minMultiplier,
Math.min(this.maxMultiplier, this.adaptiveMultiplier));
if (Math.abs(this.adaptiveMultiplier - previousMultiplier) > 0.01) {
this.logger.info('Rate limit adjusted', {
previousMultiplier,
newMultiplier: this.adaptiveMultiplier,
successRate: this.successRate,
errorRate: this.errorRate,
});
}
}
}
9.6 安全审计和监控
9.6.1 安全事件监控
// src/security/SecurityMonitor.ts
export enum SecurityEventType {
AUTHENTICATION_FAILURE = 'auth_failure',
AUTHORIZATION_DENIED = 'auth_denied',
SUSPICIOUS_ACTIVITY = 'suspicious_activity',
RATE_LIMIT_EXCEEDED = 'rate_limit_exceeded',
INPUT_VALIDATION_FAILED = 'validation_failed',
PRIVILEGE_ESCALATION = 'privilege_escalation',
DATA_ACCESS_VIOLATION = 'data_violation',
SYSTEM_INTRUSION = 'intrusion',
}
export interface SecurityEvent {
id: string;
type: SecurityEventType;
severity: 'low' | 'medium' | 'high' | 'critical';
timestamp: Date;
userId?: string;
clientInfo?: {
ip?: string;
userAgent?: string;
location?: string;
};
resource?: string;
action?: string;
details: Record<string, any>;
metadata?: Record<string, any>;
}
export interface SecurityAlert {
id: string;
event: SecurityEvent;
threshold: SecurityThreshold;
count: number;
firstOccurrence: Date;
lastOccurrence: Date;
status: 'active' | 'resolved' | 'suppressed';
}
export interface SecurityThreshold {
eventType: SecurityEventType;
count: number;
windowMs: number;
severity: 'low' | 'medium' | 'high' | 'critical';
actions: SecurityAction[];
}
export enum SecurityAction {
LOG_ALERT = 'log_alert',
SEND_EMAIL = 'send_email',
BLOCK_USER = 'block_user',
BLOCK_IP = 'block_ip',
RATE_LIMIT = 'rate_limit',
REQUIRE_MFA = 'require_mfa',
}
export class SecurityMonitor {
private events: SecurityEvent[] = [];
private alerts = new Map<string, SecurityAlert>();
private thresholds: SecurityThreshold[] = [];
private eventCounters = new Map<string, { count: number; windowStart: number }>();
private logger: Logger;
private maxEvents = 10000;
constructor(logger: Logger) {
this.logger = logger.child({}, 'security-monitor');
this.setupDefaultThresholds();
// 定期清理过期事件
setInterval(() => {
this.cleanupOldEvents();
}, 300000); // 每5分钟
}
async recordEvent(event: Omit<SecurityEvent, 'id' | 'timestamp'>): Promise<void> {
const securityEvent: SecurityEvent = {
...event,
id: this.generateEventId(),
timestamp: new Date(),
};
// 记录事件
this.events.push(securityEvent);
// 限制事件数量
if (this.events.length > this.maxEvents) {
this.events.shift();
}
// 记录日志
await this.logger.warn(
`Security event: ${event.type}`,
{
eventId: securityEvent.id,
type: event.type,
severity: event.severity,
userId: event.userId,
resource: event.resource,
action: event.action,
details: event.details,
}
);
// 检查是否触发阈值
await this.checkThresholds(securityEvent);
}
private async checkThresholds(event: SecurityEvent): Promise<void> {
for (const threshold of this.thresholds) {
if (threshold.eventType === event.type) {
await this.evaluateThreshold(threshold, event);
}
}
}
private async evaluateThreshold(threshold: SecurityThreshold, event: SecurityEvent): Promise<void> {
const key = `${threshold.eventType}:${event.userId || 'anonymous'}:${event.clientInfo?.ip || 'unknown'}`;
const now = Date.now();
const windowStart = now - threshold.windowMs;
// 清理过期计数
const counter = this.eventCounters.get(key);
if (!counter || counter.windowStart < windowStart) {
this.eventCounters.set(key, { count: 1, windowStart: now });
return;
}
// 增加计数
counter.count++;
// 检查是否超过阈值
if (counter.count >= threshold.count) {
await this.triggerAlert(threshold, event, counter.count);
}
}
private async triggerAlert(threshold: SecurityThreshold, event: SecurityEvent, count: number): Promise<void> {
const alertId = this.generateAlertId();
const alert: SecurityAlert = {
id: alertId,
event,
threshold,
count,
firstOccurrence: new Date(Date.now() - threshold.windowMs),
lastOccurrence: event.timestamp,
status: 'active',
};
this.alerts.set(alertId, alert);
await this.logger.error(
`Security alert triggered: ${threshold.eventType}`,
{
alertId,
eventType: threshold.eventType,
count,
threshold: threshold.count,
windowMs: threshold.windowMs,
severity: threshold.severity,
}
);
// 执行安全动作
await this.executeSecurityActions(threshold, event);
}
private async executeSecurityActions(threshold: SecurityThreshold, event: SecurityEvent): Promise<void> {
for (const action of threshold.actions) {
try {
await this.executeSecurityAction(action, threshold, event);
} catch (error) {
await this.logger.error(
'Security action execution failed',
error instanceof Error ? error : new Error(String(error)),
{ action, eventType: threshold.eventType }
);
}
}
}
private async executeSecurityAction(action: SecurityAction, threshold: SecurityThreshold, event: SecurityEvent): Promise<void> {
switch (action) {
case SecurityAction.LOG_ALERT:
await this.logger.error(
`SECURITY ALERT: ${threshold.eventType} threshold exceeded`,
{
severity: threshold.severity,
eventId: event.id,
userId: event.userId,
ip: event.clientInfo?.ip,
}
);
break;
case SecurityAction.BLOCK_USER:
if (event.userId) {
// 实际实现中应该调用用户管理系统
await this.logger.warn('User blocking requested', { userId: event.userId });
}
break;
case SecurityAction.BLOCK_IP:
if (event.clientInfo?.ip) {
// 实际实现中应该调用防火墙或网络层
await this.logger.warn('IP blocking requested', { ip: event.clientInfo.ip });
}
break;
case SecurityAction.SEND_EMAIL:
// 实际实现中应该发送邮件通知
await this.logger.info('Email notification requested', { eventType: threshold.eventType });
break;
default:
await this.logger.warn('Unknown security action', { action });
}
}
getEvents(filter?: {
type?: SecurityEventType;
severity?: string;
userId?: string;
since?: Date;
limit?: number;
}): SecurityEvent[] {
let filtered = this.events;
if (filter) {
if (filter.type) {
filtered = filtered.filter(e => e.type === filter.type);
}
if (filter.severity) {
filtered = filtered.filter(e => e.severity === filter.severity);
}
if (filter.userId) {
filtered = filtered.filter(e => e.userId === filter.userId);
}
if (filter.since) {
filtered = filtered.filter(e => e.timestamp >= filter.since!);
}
}
// 按时间倒序排列
filtered.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
// 应用限制
if (filter?.limit) {
filtered = filtered.slice(0, filter.limit);
}
return filtered;
}
getActiveAlerts(): SecurityAlert[] {
return Array.from(this.alerts.values())
.filter(alert => alert.status === 'active')
.sort((a, b) => b.lastOccurrence.getTime() - a.lastOccurrence.getTime());
}
resolveAlert(alertId: string): boolean {
const alert = this.alerts.get(alertId);
if (alert) {
alert.status = 'resolved';
return true;
}
return false;
}
private setupDefaultThresholds(): void {
this.thresholds = [
{
eventType: SecurityEventType.AUTHENTICATION_FAILURE,
count: 5,
windowMs: 300000, // 5分钟
severity: 'medium',
actions: [SecurityAction.LOG_ALERT, SecurityAction.RATE_LIMIT],
},
{
eventType: SecurityEventType.AUTHORIZATION_DENIED,
count: 10,
windowMs: 600000, // 10分钟
severity: 'medium',
actions: [SecurityAction.LOG_ALERT],
},
{
eventType: SecurityEventType.RATE_LIMIT_EXCEEDED,
count: 3,
windowMs: 60000, // 1分钟
severity: 'low',
actions: [SecurityAction.LOG_ALERT],
},
{
eventType: SecurityEventType.PRIVILEGE_ESCALATION,
count: 1,
windowMs: 3600000, // 1小时
severity: 'critical',
actions: [SecurityAction.LOG_ALERT, SecurityAction.SEND_EMAIL, SecurityAction.BLOCK_USER],
},
];
}
private generateEventId(): string {
return `event_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private generateAlertId(): string {
return `alert_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
private cleanupOldEvents(): void {
const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1000); // 24小时前
this.events = this.events.filter(event => event.timestamp > cutoff);
// 清理过期的计数器
const now = Date.now();
for (const [key, counter] of this.eventCounters) {
if (counter.windowStart < now - 3600000) { // 1小时前
this.eventCounters.delete(key);
}
}
}
}
9.7 集成示例:安全的MCP Server
// src/SecureMCPServer.ts
export class SecureMCPServer extends EnhancedMCPServer {
private authManager: AuthenticationManager;
private rbacProvider: RBACAuthorizationProvider;
private inputValidator: InputValidator;
private rateLimiter: MultiTierRateLimiter;
private securityMonitor: SecurityMonitor;
constructor(config: ServerConfig & { security: SecurityConfig }) {
super(config);
this.setupSecurity(config.security);
}
private setupSecurity(securityConfig: SecurityConfig): void {
// 认证管理
this.authManager = new AuthenticationManager(this.logger);
if (securityConfig.authentication.methods.includes(AuthMethod.API_KEY)) {
const apiKeyProvider = new ApiKeyAuthProvider(process.env.API_KEY_SECRET || 'default-secret');
this.authManager.registerProvider(apiKeyProvider);
}
if (securityConfig.authentication.methods.includes(AuthMethod.JWT)) {
const jwtProvider = new JWTAuthProvider(process.env.JWT_SECRET || 'default-secret');
this.authManager.registerProvider(jwtProvider);
}
// 授权管理
this.rbacProvider = new RBACAuthorizationProvider(this.logger);
// 输入验证
this.inputValidator = new InputValidator(this.logger);
// 速率限制
this.rateLimiter = new MultiTierRateLimiter(this.logger);
this.setupRateLimiting(securityConfig.rateLimiting);
// 安全监控
this.securityMonitor = new SecurityMonitor(this.logger);
}
private setupRateLimiting(config: any): void {
if (!config.enabled) return;
// 全局速率限制
this.rateLimiter.addTier('global', {
windowMs: config.windowMs,
maxRequests: config.maxRequests,
keyGenerator: () => 'global',
});
// 用户级速率限制
this.rateLimiter.addTier('user', {
windowMs: config.windowMs,
maxRequests: Math.floor(config.maxRequests / 2),
keyGenerator: (context) => `user:${context.userId || 'anonymous'}`,
});
// IP级速率限制
this.rateLimiter.addTier('ip', {
windowMs: config.windowMs,
maxRequests: Math.floor(config.maxRequests * 2),
keyGenerator: (context) => `ip:${context.clientIP || 'unknown'}`,
});
}
// 增强的请求处理方法
async handleSecureRequest(request: Request, context: {
clientIP?: string;
userAgent?: string;
authHeader?: string;
}): Promise<Response> {
const requestId = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const startTime = new Date();
try {
// 1. 输入验证
const validationResult = await this.inputValidator.validate('mcp-request', request);
if (!validationResult.valid) {
await this.securityMonitor.recordEvent({
type: SecurityEventType.INPUT_VALIDATION_FAILED,
severity: 'medium',
clientInfo: { ip: context.clientIP, userAgent: context.userAgent },
details: { errors: validationResult.errors },
});
return {
jsonrpc: '2.0',
id: request.id,
error: MCPErrorBuilder.invalidParams('Input validation failed', validationResult.errors),
};
}
// 2. 身份验证
let user: UserInfo | undefined;
if (context.authHeader) {
const authResult = await this.authManager.validateToken(context.authHeader);
if (!authResult.valid) {
await this.securityMonitor.recordEvent({
type: SecurityEventType.AUTHENTICATION_FAILURE,
severity: 'medium',
clientInfo: { ip: context.clientIP, userAgent: context.userAgent },
details: { error: authResult.error },
});
return {
jsonrpc: '2.0',
id: request.id,
error: {
code: MCPErrorCode.AUTHENTICATION_FAILED,
message: 'Authentication failed',
},
};
}
user = authResult.user;
}
// 3. 速率限制检查
const rateLimitContext = {
userId: user?.id,
clientIP: context.clientIP,
};
const rateLimitResult = await this.rateLimiter.checkAllTiers(rateLimitContext);
if (!rateLimitResult.allowed) {
await this.securityMonitor.recordEvent({
type: SecurityEventType.RATE_LIMIT_EXCEEDED,
severity: 'low',
userId: user?.id,
clientInfo: { ip: context.clientIP },
details: { tier: rateLimitResult.tier },
});
return {
jsonrpc: '2.0',
id: request.id,
error: {
code: MCPErrorCode.RATE_LIMIT_EXCEEDED,
message: 'Rate limit exceeded',
data: {
retryAfter: rateLimitResult.result?.retryAfter,
resetTime: rateLimitResult.result?.resetTime,
},
},
};
}
// 4. 授权检查(如果需要)
if (user && this.requiresAuthorization(request.method)) {
const authzContext: AuthorizationContext = {
user,
resource: this.getResourceFromMethod(request.method),
action: this.getActionFromMethod(request.method),
timestamp: startTime,
clientInfo: { ip: context.clientIP, userAgent: context.userAgent },
metadata: request.params,
};
const authzResult = await this.rbacProvider.authorize(authzContext);
if (!authzResult.allowed) {
await this.securityMonitor.recordEvent({
type: SecurityEventType.AUTHORIZATION_DENIED,
severity: 'medium',
userId: user.id,
resource: authzContext.resource,
action: authzContext.action,
clientInfo: { ip: context.clientIP },
details: { reason: authzResult.reason },
});
return {
jsonrpc: '2.0',
id: request.id,
error: {
code: MCPErrorCode.AUTHORIZATION_FAILED,
message: 'Authorization denied',
data: { reason: authzResult.reason },
},
};
}
}
// 5. 处理请求
const response = await this.handleRequest(request);
// 6. 标记速率限制完成
this.rateLimiter.markComplete(rateLimitContext, !response.error);
return response;
} catch (error) {
// 记录系统错误
await this.securityMonitor.recordEvent({
type: SecurityEventType.SYSTEM_INTRUSION,
severity: 'high',
userId: user?.id,
clientInfo: { ip: context.clientIP },
details: { error: error instanceof Error ? error.message : String(error) },
});
this.rateLimiter.markComplete({ userId: user?.id, clientIP: context.clientIP }, false);
return {
jsonrpc: '2.0',
id: request.id,
error: {
code: MCPErrorCode.INTERNAL_ERROR,
message: 'Internal server error',
},
};
}
}
private requiresAuthorization(method: string): boolean {
const publicMethods = ['initialize', 'initialized', 'ping'];
return !publicMethods.includes(method);
}
private getResourceFromMethod(method: string): string {
if (method.startsWith('tools/')) return 'tools';
if (method.startsWith('resources/')) return 'resources';
if (method.startsWith('prompts/')) return 'prompts';
return 'server';
}
private getActionFromMethod(method: string): string {
if (method.includes('list')) return 'list';
if (method.includes('call') || method.includes('execute')) return 'execute';
if (method.includes('read')) return 'read';
if (method.includes('write')) return 'write';
return 'access';
}
// 安全报告接口
async getSecurityReport(): Promise<any> {
const events = this.securityMonitor.getEvents({ limit: 100 });
const alerts = this.securityMonitor.getActiveAlerts();
const rateLimitStats = this.rateLimiter.getStats();
return {
events: events.map(e => ({
...e,
details: this.sanitizeSecurityEventDetails(e.details),
})),
alerts: alerts.length,
rateLimitStats,
summary: {
totalEvents: events.length,
criticalEvents: events.filter(e => e.severity === 'critical').length,
highSeverityEvents: events.filter(e => e.severity === 'high').length,
activeAlerts: alerts.length,
},
};
}
private sanitizeSecurityEventDetails(details: Record<string, any>): Record<string, any> {
const sanitized = { ...details };
const sensitiveFields = ['password', 'token', 'secret', 'key'];
for (const field of sensitiveFields) {
if (field in sanitized) {
sanitized[field] = '[REDACTED]';
}
}
return sanitized;
}
}
本章总结
第9章深入学习了MCP Server的安全性和权限控制:
核心知识点
- 安全威胁模型:建立了完整的威胁分析和风险评估体系
- 身份验证系统:实现了多种认证方式和认证管理器
- RBAC授权系统:构建了基于角色的访问控制机制
- 输入验证:建立了严格的输入验证和数据净化系统
- 速率限制:实现了多层次的速率限制和自适应调整
- 安全监控:构建了全面的安全事件监控和告警系统
实践要点
- 实施分层的安全防护机制
- 遵循最小权限原则
- 建立完整的安全事件记录和监控
- 实现自适应的安全策略调整
- 提供详细的安全审计和报告功能
- 区分不同类型的安全威胁和响应策略
通过本章学习,掌握了构建安全可靠的MCP Server所需的完整安全体系,为服务在生产环境中的安全运行提供了强有力的保障。