InitalCommit

This commit is contained in:
2026-02-17 16:00:34 +01:00
commit ce89fccdb5
20 changed files with 6296 additions and 0 deletions

164
MCP_SECURITY.md Normal file
View File

@@ -0,0 +1,164 @@
# 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)}...`);
```