mistral-security-basics
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMistral AI Security Basics
Mistral AI 安全基础
Overview
概述
Security best practices for Mistral AI API keys and access control.
Mistral AI API密钥与访问控制的安全最佳实践。
Prerequisites
前提条件
- Mistral AI SDK installed
- Understanding of environment variables
- Access to Mistral AI console
- 已安装Mistral AI SDK
- 了解环境变量
- 有权访问Mistral AI控制台
Instructions
操作步骤
Step 1: Configure Environment Variables
步骤1:配置环境变量
bash
undefinedbash
undefined.env (NEVER commit to git)
.env (绝对不要提交到git)
MISTRAL_API_KEY=your-api-key-here
MISTRAL_API_KEY=your-api-key-here
.gitignore - Add these lines
.gitignore - 添加以下内容
.env
.env.local
.env.*.local
*.pem
*.key
secrets/
**Validate .gitignore:**
```bash.env
.env.local
.env.*.local
*.pem
*.key
secrets/
**验证.gitignore配置:**
```bashCheck if .env would be committed
检查.env是否会被提交
git check-ignore .env || echo "WARNING: .env is not ignored!"
git check-ignore .env || echo "警告:.env未被忽略!"
Check for exposed secrets in history
检查历史记录中是否有暴露的密钥
git log -p --all -S 'MISTRAL_API_KEY' -- '.ts' '.js' '.py' '.env'
undefinedgit log -p --all -S 'MISTRAL_API_KEY' -- '.ts' '.js' '.py' '.env'
undefinedStep 2: Secure Key Loading
步骤2:安全加载密钥
typescript
// src/config/mistral.ts
import { z } from 'zod';
const envSchema = z.object({
MISTRAL_API_KEY: z.string().min(20, 'Invalid API key format'),
NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),
});
export function loadMistralConfig() {
const result = envSchema.safeParse(process.env);
if (!result.success) {
console.error('Environment validation failed:', result.error.format());
throw new Error('Missing or invalid MISTRAL_API_KEY');
}
return result.data;
}
// Usage
const config = loadMistralConfig();
const client = new Mistral({ apiKey: config.MISTRAL_API_KEY });typescript
// src/config/mistral.ts
import { z } from 'zod';
const envSchema = z.object({
MISTRAL_API_KEY: z.string().min(20, 'Invalid API key format'),
NODE_ENV: z.enum(['development', 'staging', 'production']).default('development'),
});
export function loadMistralConfig() {
const result = envSchema.safeParse(process.env);
if (!result.success) {
console.error('Environment validation failed:', result.error.format());
throw new Error('Missing or invalid MISTRAL_API_KEY');
}
return result.data;
}
// 使用示例
const config = loadMistralConfig();
const client = new Mistral({ apiKey: config.MISTRAL_API_KEY });Step 3: Key Rotation Procedure
步骤3:密钥轮换流程
bash
undefinedbash
undefined1. Generate new key in Mistral console
1. 在Mistral控制台生成新密钥
2. Test new key before rotation
2. 轮换前测试新密钥
MISTRAL_API_KEY_NEW="new-key-here"
curl -H "Authorization: Bearer ${MISTRAL_API_KEY_NEW}"
https://api.mistral.ai/v1/models
https://api.mistral.ai/v1/models
MISTRAL_API_KEY_NEW="new-key-here"
curl -H "Authorization: Bearer ${MISTRAL_API_KEY_NEW}"
https://api.mistral.ai/v1/models
https://api.mistral.ai/v1/models
3. Update environment variable / secrets manager
3. 更新环境变量/密钥管理器
export MISTRAL_API_KEY="${MISTRAL_API_KEY_NEW}"
export MISTRAL_API_KEY="${MISTRAL_API_KEY_NEW}"
4. Deploy with new key
4. 使用新密钥部署
5. Revoke old key in Mistral console
5. 在Mistral控制台吊销旧密钥
undefinedundefinedStep 4: Environment-Specific Keys
步骤4:环境专属密钥
| Environment | Key Type | Permissions |
|---|---|---|
| Development | Dev key | All models, low limits |
| Staging | Staging key | All models, medium limits |
| Production | Production key | Required models only |
typescript
// src/config/environments.ts
interface MistralEnvConfig {
apiKey: string;
allowedModels: string[];
maxTokensPerRequest: number;
}
const configs: Record<string, MistralEnvConfig> = {
development: {
apiKey: process.env.MISTRAL_API_KEY_DEV!,
allowedModels: ['mistral-small-latest', 'mistral-large-latest'],
maxTokensPerRequest: 1000,
},
production: {
apiKey: process.env.MISTRAL_API_KEY_PROD!,
allowedModels: ['mistral-small-latest'],
maxTokensPerRequest: 4000,
},
};
export function getEnvConfig(): MistralEnvConfig {
const env = process.env.NODE_ENV || 'development';
return configs[env] || configs.development;
}| 环境 | 密钥类型 | 权限 |
|---|---|---|
| 开发环境 | 开发密钥 | 所有模型,限额较低 |
| 预发布环境 | 预发布密钥 | 所有模型,限额中等 |
| 生产环境 | 生产密钥 | 仅允许必要模型 |
typescript
// src/config/environments.ts
interface MistralEnvConfig {
apiKey: string;
allowedModels: string[];
maxTokensPerRequest: number;
}
const configs: Record<string, MistralEnvConfig> = {
development: {
apiKey: process.env.MISTRAL_API_KEY_DEV!,
allowedModels: ['mistral-small-latest', 'mistral-large-latest'],
maxTokensPerRequest: 1000,
},
production: {
apiKey: process.env.MISTRAL_API_KEY_PROD!,
allowedModels: ['mistral-small-latest'],
maxTokensPerRequest: 4000,
},
};
export function getEnvConfig(): MistralEnvConfig {
const env = process.env.NODE_ENV || 'development';
return configs[env] || configs.development;
}Step 5: Request Validation & Sanitization
步骤5:请求验证与清理
typescript
import { z } from 'zod';
const messageSchema = z.object({
role: z.enum(['system', 'user', 'assistant']),
content: z.string().max(100000), // Prevent huge payloads
});
const chatRequestSchema = z.object({
model: z.enum(['mistral-small-latest', 'mistral-large-latest']),
messages: z.array(messageSchema).min(1).max(100),
temperature: z.number().min(0).max(1).optional(),
maxTokens: z.number().min(1).max(4000).optional(),
});
function validateChatRequest(input: unknown) {
return chatRequestSchema.parse(input);
}
// Usage in API endpoint
app.post('/api/chat', async (req, res) => {
try {
const validated = validateChatRequest(req.body);
const response = await client.chat.complete(validated);
res.json(response);
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({ error: 'Invalid request', details: error.errors });
} else {
res.status(500).json({ error: 'Internal error' });
}
}
});typescript
import { z } from 'zod';
const messageSchema = z.object({
role: z.enum(['system', 'user', 'assistant']),
content: z.string().max(100000), // 阻止超大负载
});
const chatRequestSchema = z.object({
model: z.enum(['mistral-small-latest', 'mistral-large-latest']),
messages: z.array(messageSchema).min(1).max(100),
temperature: z.number().min(0).max(1).optional(),
maxTokens: z.number().min(1).max(4000).optional(),
});
function validateChatRequest(input: unknown) {
return chatRequestSchema.parse(input);
}
// 在API端点中使用
app.post('/api/chat', async (req, res) => {
try {
const validated = validateChatRequest(req.body);
const response = await client.chat.complete(validated);
res.json(response);
} catch (error) {
if (error instanceof z.ZodError) {
res.status(400).json({ error: '无效请求', details: error.errors });
} else {
res.status(500).json({ error: '内部错误' });
}
}
});Step 6: Audit Logging
步骤6:审计日志
typescript
interface AuditEntry {
timestamp: Date;
action: string;
userId?: string;
model: string;
tokensUsed?: number;
success: boolean;
errorCode?: string;
ipAddress?: string;
}
async function auditLog(entry: Omit<AuditEntry, 'timestamp'>): Promise<void> {
const log: AuditEntry = { ...entry, timestamp: new Date() };
// Log to your audit system
console.log('[AUDIT]', JSON.stringify(log));
// Optional: send to logging service
// await loggingService.record(log);
}
// Usage
async function chatWithAudit(
userId: string,
messages: Message[],
ipAddress?: string
): Promise<string> {
const start = Date.now();
try {
const response = await client.chat.complete({
model: 'mistral-small-latest',
messages,
});
await auditLog({
action: 'chat.complete',
userId,
model: 'mistral-small-latest',
tokensUsed: response.usage?.totalTokens,
success: true,
ipAddress,
});
return response.choices?.[0]?.message?.content ?? '';
} catch (error: any) {
await auditLog({
action: 'chat.complete',
userId,
model: 'mistral-small-latest',
success: false,
errorCode: error.status?.toString(),
ipAddress,
});
throw error;
}
}typescript
interface AuditEntry {
timestamp: Date;
action: string;
userId?: string;
model: string;
tokensUsed?: number;
success: boolean;
errorCode?: string;
ipAddress?: string;
}
async function auditLog(entry: Omit<AuditEntry, 'timestamp'>): Promise<void> {
const log: AuditEntry = { ...entry, timestamp: new Date() };
// 记录到审计系统
console.log('[AUDIT]', JSON.stringify(log));
// 可选:发送到日志服务
// await loggingService.record(log);
}
// 使用示例
async function chatWithAudit(
userId: string,
messages: Message[],
ipAddress?: string
): Promise<string> {
const start = Date.now();
try {
const response = await client.chat.complete({
model: 'mistral-small-latest',
messages,
});
await auditLog({
action: 'chat.complete',
userId,
model: 'mistral-small-latest',
tokensUsed: response.usage?.totalTokens,
success: true,
ipAddress,
});
return response.choices?.[0]?.message?.content ?? '';
} catch (error: any) {
await auditLog({
action: 'chat.complete',
userId,
model: 'mistral-small-latest',
success: false,
errorCode: error.status?.toString(),
ipAddress,
});
throw error;
}
}Security Checklist
安全检查清单
- API key stored in environment variable (not code)
- files in
.env.gitignore - Different keys for dev/staging/prod
- Input validation on all requests
- Output sanitization before display
- Audit logging enabled
- Rate limiting implemented
- Error messages don't expose internals
- HTTPS enforced for all endpoints
- Regular key rotation scheduled
- API密钥存储在环境变量中(而非代码里)
- 将.env文件添加到.gitignore
- 开发/预发布/生产环境使用不同密钥
- 对所有请求进行输入验证
- 输出内容在展示前进行清理
- 已启用审计日志
- 已实施速率限制
- 错误信息不暴露内部细节
- 所有端点强制使用HTTPS
- 已计划定期密钥轮换
Output
输出结果
- Secure API key storage
- Environment-specific access controls
- Input validation
- Audit logging enabled
- 安全的API密钥存储
- 环境专属访问控制
- 输入验证
- 已启用审计日志
Error Handling
错误处理
| Security Issue | Detection | Mitigation |
|---|---|---|
| Exposed API key | Git scanning, log review | Rotate immediately, revoke old key |
| Injection attacks | Input validation | Zod schemas, sanitization |
| Missing audit trail | Log review | Implement comprehensive logging |
| Excessive permissions | Access review | Limit models per environment |
| 安全问题 | 检测方式 | 缓解措施 |
|---|---|---|
| API密钥泄露 | Git扫描、日志审查 | 立即轮换密钥,吊销旧密钥 |
| 注入攻击 | 输入验证 | 使用Zod schema、内容清理 |
| 缺失审计轨迹 | 日志审查 | 实施全面的日志记录 |
| 权限过大 | 权限审查 | 按环境限制可访问的模型 |
Examples
示例
Secrets Manager Integration (AWS)
密钥管理器集成(AWS)
typescript
import { SecretsManager } from '@aws-sdk/client-secrets-manager';
const sm = new SecretsManager({ region: 'us-east-1' });
async function getMistralApiKey(): Promise<string> {
const secret = await sm.getSecretValue({
SecretId: 'mistral/api-key',
});
return secret.SecretString!;
}typescript
import { SecretsManager } from '@aws-sdk/client-secrets-manager';
const sm = new SecretsManager({ region: 'us-east-1' });
async function getMistralApiKey(): Promise<string> {
const secret = await sm.getSecretValue({
SecretId: 'mistral/api-key',
});
return secret.SecretString!;
}Secrets Manager Integration (GCP)
密钥管理器集成(GCP)
typescript
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
const client = new SecretManagerServiceClient();
async function getMistralApiKey(): Promise<string> {
const [version] = await client.accessSecretVersion({
name: 'projects/my-project/secrets/mistral-api-key/versions/latest',
});
return version.payload?.data?.toString()!;
}typescript
import { SecretManagerServiceClient } from '@google-cloud/secret-manager';
const client = new SecretManagerServiceClient();
async function getMistralApiKey(): Promise<string> {
const [version] = await client.accessSecretVersion({
name: 'projects/my-project/secrets/mistral-api-key/versions/latest',
});
return version.payload?.data?.toString()!;
}Content Filtering
内容过滤
typescript
const BLOCKED_PATTERNS = [
/\b(password|secret|key)\s*[:=]/i,
/\b\d{16}\b/, // Credit card numbers
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z]{2,}\b/i, // Emails
];
function containsSensitiveData(text: string): boolean {
return BLOCKED_PATTERNS.some(pattern => pattern.test(text));
}
async function safeChatComplete(messages: Message[]): Promise<string> {
// Check input for sensitive data
for (const msg of messages) {
if (containsSensitiveData(msg.content)) {
throw new Error('Message contains potentially sensitive data');
}
}
return client.chat.complete({ model: 'mistral-small-latest', messages });
}typescript
const BLOCKED_PATTERNS = [
/\b(password|secret|key)\s*[:=]/i,
/\b\d{16}\b/, // 信用卡号码
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z]{2,}\b/i, // 邮箱地址
];
function containsSensitiveData(text: string): boolean {
return BLOCKED_PATTERNS.some(pattern => pattern.test(text));
}
async function safeChatComplete(messages: Message[]): Promise<string> {
// 检查输入是否包含敏感数据
for (const msg of messages) {
if (containsSensitiveData(msg.content)) {
throw new Error('消息包含潜在敏感数据');
}
}
return client.chat.complete({ model: 'mistral-small-latest', messages });
}Resources
参考资源
Next Steps
后续步骤
For production deployment, see .
mistral-prod-checklist如需生产部署,请参考。
mistral-prod-checklist