165 lines
4.4 KiB
Markdown
165 lines
4.4 KiB
Markdown
# MCP Read-Only Security Guide
|
|
|
|
## Current Security Measures
|
|
|
|
The `mssql-mcp-readonly.js` file implements multiple layers of read-only enforcement:
|
|
|
|
### 1. Query Validation (Application Layer)
|
|
- ✅ Only SELECT queries allowed
|
|
- ✅ Blocks INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, TRUNCATE
|
|
- ✅ Blocks EXEC/EXECUTE (prevents stored procedure execution)
|
|
- ✅ Blocks SP_/XP_ (prevents system stored procedures)
|
|
- ✅ Blocks MERGE, GRANT, REVOKE, DENY
|
|
- ✅ Prevents query chaining with semicolons
|
|
|
|
### 2. Recommended: Database User Permissions (Database Layer)
|
|
|
|
For **maximum security**, create a read-only database user:
|
|
|
|
```sql
|
|
-- Create a read-only user
|
|
CREATE LOGIN mcp_readonly WITH PASSWORD = 'YourSecurePassword123!';
|
|
USE Infra;
|
|
CREATE USER mcp_readonly FOR LOGIN mcp_readonly;
|
|
|
|
-- Grant only SELECT permission
|
|
GRANT SELECT ON SCHEMA::dbo TO mcp_readonly;
|
|
|
|
-- Or grant SELECT on specific tables only:
|
|
GRANT SELECT ON dbo.SDS_Teile TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_CA TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_CS TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_LC TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_ME TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_MK TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_MS TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_WT TO mcp_readonly;
|
|
GRANT SELECT ON dbo.SDS_Teile_EL TO mcp_readonly;
|
|
|
|
-- Explicitly deny write permissions (extra safety)
|
|
DENY INSERT, UPDATE, DELETE, ALTER ON SCHEMA::dbo TO mcp_readonly;
|
|
```
|
|
|
|
### 3. Update MCP Configuration
|
|
|
|
After creating the read-only user, update `~/.cursor/mcp.json`:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"mssql-mcp-readonly": {
|
|
"command": "node ",
|
|
"args": ["/home/sdsadmin/infraviewer/mssql-mcp-readonly.js"],
|
|
"env": {
|
|
"MSSQL_SERVER": "192.168.120.88",
|
|
"MSSQL_PORT": "1433",
|
|
"MSSQL_USER": "mcp_readonly",
|
|
"MSSQL_PASSWORD": "YourSecurePassword123!",
|
|
"MSSQL_DATABASE": "Infra",
|
|
"MSSQL_ENCRYPT": "true",
|
|
"MSSQL_TRUST_SERVER_CERTIFICATE": "true"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Security Layers
|
|
|
|
| Layer | Protection | Bypassed if... |
|
|
|-------|-----------|----------------|
|
|
| **Application Validation** | Keyword blocking | Code has bugs |
|
|
| **Database Permissions** | SQL Server enforced | Wrong credentials used |
|
|
| **Both Combined** | Double protection | Nearly impossible ✅ |
|
|
|
|
## Testing Read-Only Access
|
|
|
|
### Test 1: Valid SELECT (should work)
|
|
```sql
|
|
SELECT TOP 10 * FROM SDS_Teile
|
|
```
|
|
|
|
### Test 2: Invalid INSERT (should fail)
|
|
```sql
|
|
INSERT INTO SDS_Teile (Teil) VALUES ('TEST')
|
|
```
|
|
**Expected:** Error: "Forbidden keyword detected: INSERT"
|
|
|
|
### Test 3: Query Chaining (should fail)
|
|
```sql
|
|
SELECT 1; DROP TABLE SDS_Teile
|
|
```
|
|
**Expected:** Error: "Multiple statements not allowed"
|
|
|
|
### Test 4: Stored Procedure (should fail)
|
|
```sql
|
|
EXEC sp_helpdb
|
|
```
|
|
**Expected:** Error: "Forbidden keyword detected: EXEC"
|
|
|
|
## Current vs Recommended Setup
|
|
|
|
### Current Setup (Application Layer Only)
|
|
```
|
|
[AI] → [mssql-mcp-readonly.js] → [SQL Server]
|
|
↑ Validates queries ↑ Full permissions
|
|
```
|
|
**Risk:** If validation code has a bug, data could be modified
|
|
|
|
### Recommended Setup (Defense in Depth)
|
|
```
|
|
[AI] → [mssql-mcp-readonly.js] → [SQL Server with read-only user]
|
|
↑ Validates queries ↑ SELECT-only permissions
|
|
```
|
|
**Benefit:** Even if validation fails, SQL Server will block write operations
|
|
|
|
## Monitoring
|
|
|
|
Check MCP server logs for blocked attempts:
|
|
```bash
|
|
# If running as systemd service
|
|
journalctl -u mcp-readonly -f
|
|
|
|
# If running manually
|
|
tail -f /var/log/mcp-readonly.log
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. ✅ Use dedicated read-only database user
|
|
2. ✅ Keep validation keywords up to date
|
|
3. ✅ Monitor for failed query attempts
|
|
4. ✅ Regularly audit database permissions
|
|
5. ✅ Use strong passwords for database users
|
|
6. ✅ Enable SQL Server audit logging
|
|
7. ✅ Limit network access to database server
|
|
8. ✅ Keep mssql package updated (`npm update mssql`)
|
|
|
|
## Additional Hardening
|
|
|
|
### 1. Add Query Size Limits
|
|
Prevent resource exhaustion:
|
|
```javascript
|
|
function validateQuery(query) {
|
|
if (query.length > 10000) {
|
|
throw new Error("Query too long!");
|
|
}
|
|
// ... rest of validation
|
|
}
|
|
```
|
|
|
|
### 2. Add Rate Limiting
|
|
Prevent abuse:
|
|
```javascript
|
|
const rateLimit = require('express-rate-limit');
|
|
// Limit to 100 queries per minute
|
|
```
|
|
|
|
### 3. Add Query Logging
|
|
Track all queries:
|
|
```javascript
|
|
console.log(`[${new Date().toISOString()}] Query: ${query.substring(0, 100)}...`);
|
|
```
|
|
|
|
|