0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MCPによるデータベースAI操作のセキュリティ設計:権限分離と読み取り専用制御の実装例

0
Posted at

はじめに

Model Context Protocol (MCP) を活用することで、LLM等のAIエージェントからデータベースへの直接的な情報検索や操作が可能になります。しかし、AIにデータベースアクセス権限を付与する設計を誤ると、意図しないデータの更新・削除や、機密情報の漏洩といった重大なインシデントに繋がるリスクがあります。

本記事では、MCPを用いてAIからデータベースを安全に操作するためのセキュリティ設計アプローチと、具体的な実装例、および確認用チェックリストについて解説します。

読者が抱える課題

  • AIにDBアクセス権限を与えたいが、安全な境界線の引き方が分からない
  • SQLインジェクションやプロンプトインジェクションによるデータ破壊・漏洩が心配である
  • 実務で運用できるアクセス制御や監査の仕組みを導入したい

この記事で分かること

  • MCPとDB連携におけるセキュリティリスクの整理
  • 最小権限原則に基づくデータベースロールとMCPサーバーの設計
  • Read-Only(読み取り専用)環境およびクエリ検証の実装パターン
  • 導入時に確認すべきセキュリティチェックリスト

MCP×DB操作における主なセキュリティリスク

  1. 過剰な権限の付与 (Excessive Privilege)
    AIエージェントに書き込み・削除権限(UPDATE, DELETE, DROP等)を付与している場合、悪意あるプロンプトや誤動作によってデータが破損する危険性があります。
  2. プロンプトインジェクションによる制限回避
    ユーザーの入力によってシステムプロンプトの制約が突破され、未許可のテーブルやカラムへアクセスされるリスクがあります。
  3. センシティブデータの意図しない取得
    個人情報(PII)や暗号化されていない資格情報が、AIの文脈(Context)に取り込まれて外部へ出力される可能性があります。

セキュリティ設計の基本原則

実務でMCP DBサーバーを構築する際は、以下の多層防御アプローチを推奨します。

層 対策内容 具体的な手段
DBアカウント層 最小権限の原則 読み取り専用ユーザーの作成、スキーマ単位の制限
MCPサーバー層 クエリの静的解析・検証 SQLパーサーによる prohibited ステートメントの遮断
データマスク層 センシティブ情報の非表示 SQLの VIEW や関数によるPIIのマスキング
監査ログ層 操作履歴の記録 発行された全クエリと実行コンテキストのログ保存

具体的な実装例(Python + PostgreSQL)

以下は、PythonのMCP SDKを利用して、安全にPostgreSQLへ接続する読み取り専用MCPツールを構築するコード例です。

注意: 本コードは実装の概念を示す例です。実際に利用する際は、利用環境のネットワーク構成や認証方式に合わせて適宜修正を行ってください。また、最新のMCP SDK仕様を公式ドキュメントで確認してください。

import os
import re
import psycopg2
from psycopg2.extras import RealDictCursor
from mcp.server.fastmcp import FastMCP

# MCPサーバーの初期化(独自実装例)
mcp = FastMCP("Secure-DB-Query-Server")

# 接続情報の取得(環境変数から読み込み)
DB_HOST = os.environ.get("DB_HOST", "localhost")
DB_NAME = os.environ.get("DB_NAME", "app_db")
DB_USER = os.environ.get("DB_READONLY_USER", "readonly_agent")
DB_PASSWORD = os.environ.get("DB_READONLY_PASSWORD")

def get_db_connection():
    return psycopg2.connect(
        host=DB_HOST,
        dbname=DB_NAME,
        user=DB_USER,
        password=DB_PASSWORD,
        options="-c default_transaction_read_only=on"  # セッションレベルでRead-Onlyを強制
    )

def is_safe_query(query: str) -> bool:
    """
    簡易的なSQL検証ルーチン(独自実装例)
    読み取り以外のキーワードや複数文の実行(セミコロン)を検知します。
    """
    # 複数クエリの実行を防ぐ
    if ";" in query.strip().rstrip(";"):
        return False
    
    # 許可するステートメントはSELECTのみ
    clean_query = query.strip().upper()
    if not clean_query.startswith("SELECT"):
        return False
        
    # 金止キーワードパターン
    forbidden_patterns = [r"\bINSERT\b", r"\bUPDATE\b", r"\bDELETE\b", r"\bDROP\b", r"\bALTER\b", r"\bTRUNCATE\b"]
    for pattern in forbidden_patterns:
        if re.search(pattern, clean_query):
            return False
            
    return True

@mcp.tool()
def execute_readonly_query(sql_query: str) -> str:
    """
    データベースに対して読み取り専用クエリを実行し、結果を返します。
    SELECT文のみが実行可能です。
    """
    # 1. クエリの安全性を検証
    if not is_safe_query(sql_query):
        return "Error: 安全でないクエリまたは許可されていない操作が検知されました。SELECT文のみ使用可能です。"

    # 2. データベース操作の実行
    try:
        with get_db_connection() as conn:
            with conn.cursor(cursor_factory=RealDictCursor) as cursor:
                cursor.execute(sql_query)
                rows = cursor.fetchall()
                return str(rows)
    except Exception as e:
        # 機密情報が例外に含まれる可能性があるため、実運用ではログ出力と適切なエラー丸めを行う
        return f"Query execution error: {str(e)}"

if __name__ == "__main__":
    mcp.run()

データベース側のロール設計例(PostgreSQL)

アプリケーション側だけでなく、データベース側でも物理的に権限を制限することが必須です。

-- 1. AI用読み取り専用ロールの作成
CREATE ROLE readonly_agent WITH LOGIN PASSWORD 'SecurePasswordExample';

-- 2. 該当データベースへの接続権限付与
GRANT CONNECT ON DATABASE app_db TO readonly_agent;

-- 3. schemaへの使用権限付与
GRANT USAGE ON SCHEMA public TO readonly_agent;

-- 4. 特定テーブルへのSELECT権限のみを付与(機密情報テーブルは除外)
GRANT SELECT ON public.products, public.orders TO readonly_agent;

-- ※ 個人情報が含まれるusersテーブル等にはSELECT権限を与えない、またはビューを作成して一部カラムのみ公開する
CREATE VIEW public.safe_users AS 
  SELECT id, created_at, last_login_at FROM public.users;
GRANT SELECT ON public.safe_users TO readonly_agent;

導入時・運用時のセキュリティチェックリスト

実務でMCP DBサーバーをデプロイする前に、以下の項目を確認してください。

  • DBアクセス権限: MCPサーバーが使用するDBアカウントは SELECT 権限のみに絞られているか?
  • 接続制御: データベース接続オプションやセッション設定で Read-Only モードが強制されているか?
  • テーブル単位の制限: 機密情報(パスワードハッシュ、クレジットカード情報、個人識別情報)を含むテーブルへのアクセスが明示的に拒否されているか?
  • クエリ検証: MCPツール側で複数文実行(; による複数実行)や DDL/DML の静的チェックが行われているか?
  • タイムアウト設定: 長時間実行されるクエリによるDB負荷(DoS)を防ぐため、実行タイムアウト(statement_timeout 等)が設定されているか?
  • 監査ログ: MCPツールを経由して実行されたすべてのクエリ、実行日時、および実行結果の件数がログに記録されているか?
  • 環境変数の管理: DB接続パスワードなどの認証情報がコードにハードコードされず、適切なシークレット管理システムから渡されているか?

まとめ

MCPを用いてAIからデータベースを操作する際は、「AI側の制御」だけに頼るのではなく、「DBアカウントの権限分離」「MCPサーバーでの入力検証」「セッション設定での読み取り強制」という複数のレイヤーで制約を設けることが肝要です。

本記事で紹介した実装パターンやチェックリストを活用し、安全なAI DB連携基盤の構築を行ってください。導入時には最新のMCP SDK仕様および利用するDBMSのセキュリティ推奨設定をあわせて確認することをお勧めします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?