mcpField
S
security

security

github.com/oliver-kriskaセキュリティ57151 回インストール1 週間前に更新
リポジトリ

security について

Elixir と Phoenix の開発者向けセキュリティリファレンスです。入力検証、認可、エスケープ、シークレット管理、インジェクション対策をまとめ、LiveView イベントの確認方法も扱います。

主な機能

  1. 01changeset による境界での入力検証
  2. 02パラメーター化 Ecto クエリのパターン
  3. 03LiveView イベントの認可
  4. 04安全なエスケープと Atom の扱い
  5. 05ランタイムでのシークレット管理

活用シーン

  1. 01ユーザー入力処理の確認
  2. 02LiveView イベントハンドラーの保護
  3. 03SQL インジェクションと Atom 枯渇の防止
  4. 04シークレット保存と HTML エスケープの確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/oliver-kriska/claude-elixir-phoenix --skill security

インストール後、Claude Code で/securityを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
advanced-patterns.md
authentication.md
authorization.md
input-validation.md
oauth-linking.md
rate-limiting.md
security-headers.md

詳細

Elixir/Phoenix セキュリティリファレンス

Ash プロジェクト:AshAuthentication には独自のストラテジー/トークンのパターンがあります。ash-framework スキルを使用してください。以下の CSRF、XSS、シークレット管理のパターンも引き続き適用されます。

Elixir/Phoenix のセキュリティパターンに関するクイックリファレンスです。

絶対に守るべき原則 — 例外なく遵守すること

  1. 境界で検証する — クライアントからの入力を決して信頼しないでください。すべてのデータを変更セット経由で処理します
  2. ユーザー入力を文字列に埋め込まない — Ecto の ^ 演算子を使用し、文字列補間は決して使用しないでください
  3. ユーザー入力に String.to_atom を使わない — アトム枯渇による DoS が発生します。to_existing_atom/1 を使用してください
  4. すべての箇所で認可する — コンテキストで確認し、LiveView のイベントでも再検証します
  5. デフォルトでエスケープする — 信頼できないコンテンツに raw/1 を決して使用しないでください
  6. シークレットをコードに含めない — すべてのシークレットを環境変数から runtime.exs に設定します
  7. LIVEVIEW のイベントパラメーターは信頼できない — ユーザーは DevTools でフォーム、フック、すべての phx-value-* を改変できます。処理を行う前に、サーバー側の状態に基づいて検証し、認可してください

クイックパターン

タイミングセーフな認証
def authenticate(email, password) do
  user = Repo.get_by(User, email: email)

  cond do
    user && Argon2.verify_pass(password, user.hashed_password) ->
      {:ok, user}
    user ->
      {:error, :invalid_credentials}
    true ->
      Argon2.no_user_verify()  # Timing attack prevention
      {:error, :invalid_credentials}
  end
end
LiveView の認可(重大)
# `id` is client input even when it came from phx-value-id.
# RE-AUTHORIZE IN EVERY EVENT HANDLER
def handle_event("delete", %{"id" => id}, socket) do
  post = Blog.get_post!(id)

  # Don't trust that mount authorized this action!
  with :ok <- Bodyguard.permit(Blog, :delete_post, socket.assigns.current_user, post) do
    Blog.delete_post(post)
    {:noreply, stream_delete(socket, :posts, post)}
  else
    _ -> {:noreply, put_flash(socket, :error, "Unauthorized")}
  end
end

レンダリングされた LiveView イベントでは、HTML や WebSocket のペイロードに ID が含まれる場合があります。 それ自体が自動的に脆弱性となるわけではありません。ID は公開識別子として扱い、アクセス権の証明として 決して使用しないでください。識別子自体を公開してはならない場合に限り、不透明な参照を使用し、 その場合も必ずサーバー側で認可してください。

SQL インジェクションの防止
# ✅ SAFE: Parameterized queries
from(u in User, where: u.name == ^user_input)

# ❌ VULNERABLE: String interpolation
from(u in User, where: fragment("name = '#{user_input}'"))

クイック判断ガイド

何を検証するか?
  • すべてのユーザー入力 → Ecto の変更セット
  • ファイルアップロード → 拡張子+マジックバイト+サイズ
  • パス → パストラバーサル対策に Path.safe_relative/2
  • アトム → String.to_existing_atom/1 のみ
何をエスケープするか?
  • HTML 出力 → デフォルトで自動エスケープされます(<%= %>)
  • ユーザー HTML → スクラバー付きの HtmlSanitizeEx
  • 決して使用しない → 信頼できないコンテンツに対する raw/1

アンチパターン

誤り正しい方法
"SELECT * FROM users WHERE name = '#{name}'"from(u in User, where: u.name == ^name)
String.to_atom(user_input)String.to_existing_atom(user_input)
<%= raw @user_comment %><%= @user_comment %>
設定ファイルにハードコードされたシークレット環境変数から runtime.exs に設定
mount でのみ認証する各 handle_event で再認証する
phx-value-* や非表示の ID を信頼するサーバー側の状態を読み込み、認可する

参考資料

詳しいパターンについては、以下を参照してください。

  • ${CLAUDE_SKILL_DIR}/references/authentication.md - phx.gen.auth、MFA、セッション
  • ${CLAUDE_SKILL_DIR}/references/authorization.md - Bodyguard、スコープ、LiveView の認可
  • ${CLAUDE_SKILL_DIR}/references/input-validation.md - 変更セット、ファイルアップロード、パス
  • ${CLAUDE_SKILL_DIR}/references/security-headers.md - CSP、CSRF、レート制限、ヘッダー
  • ${CLAUDE_SKILL_DIR}/references/oauth-linking.md - OAuth アカウントの連携、トークン管理
  • ${CLAUDE_SKILL_DIR}/references/rate-limiting.md - 複合キー戦略、Hammer のパターン
  • ${CLAUDE_SKILL_DIR}/references/advanced-patterns.md - SSRF の防止、シークレット管理、サプライチェーン

コメント