Agent Skills by ALSEL
Anthropic Claudeセキュリティ⭐ リポ 1品質スコア 53/100

clerk-data-handling

Clerkを使用してユーザーデータ、プライバシー、GDPR対応を管理できます。データのエクスポート、ユーザー削除、プライバシーコンプライアンス機能の実装が必要な場合に使用します。「clerk user data」「clerk GDPR」「clerk privacy」「clerk data export」「clerk delete user」といったフレーズで実行できます。

description の原文を見る

Handle user data, privacy, and GDPR compliance with Clerk. Use when implementing data export, user deletion, or privacy compliance features. Trigger with phrases like "clerk user data", "clerk GDPR", "clerk privacy", "clerk data export", "clerk delete user".

SKILL.md 本文

Clerk データハンドリング

概要

ユーザーデータを管理し、プライバシー機能を実装し、規制への準拠を確保します。

前提条件

  • Clerk統合が機能している
  • GDPR/CCPA要件の理解
  • ユーザー関連データを含むデータベース

手順

ステップ1: ユーザーデータエクスポート

// lib/data-export.ts
import { clerkClient } from '@clerk/nextjs/server'
import { db } from './db'

interface UserDataExport {
  clerk: ClerkUserData
  application: ApplicationUserData
  exportedAt: string
}

interface ClerkUserData {
  id: string
  email: string | undefined
  firstName: string | null
  lastName: string | null
  createdAt: Date
  lastSignIn: Date | null
  metadata: Record<string, any>
}

interface ApplicationUserData {
  profile: any
  orders: any[]
  preferences: any
  activityLog: any[]
}

export async function exportUserData(userId: string): Promise<UserDataExport> {
  const client = await clerkClient()

  // Clerk ユーザーデータを取得
  const clerkUser = await client.users.getUser(userId)

  // アプリケーションデータを取得
  const [profile, orders, preferences, activityLog] = await Promise.all([
    db.userProfile.findUnique({ where: { clerkId: userId } }),
    db.order.findMany({ where: { userId }, orderBy: { createdAt: 'desc' } }),
    db.userPreference.findMany({ where: { userId } }),
    db.activityLog.findMany({
      where: { userId },
      orderBy: { timestamp: 'desc' },
      take: 1000
    })
  ])

  return {
    clerk: {
      id: clerkUser.id,
      email: clerkUser.primaryEmailAddress?.emailAddress,
      firstName: clerkUser.firstName,
      lastName: clerkUser.lastName,
      createdAt: new Date(clerkUser.createdAt),
      lastSignIn: clerkUser.lastSignInAt ? new Date(clerkUser.lastSignInAt) : null,
      metadata: {
        public: clerkUser.publicMetadata,
        // 注意: privateMetadata は慎重に扱う必要があります
      }
    },
    application: {
      profile: sanitizeForExport(profile),
      orders: orders.map(sanitizeForExport),
      preferences: preferences.map(sanitizeForExport),
      activityLog: activityLog.map(sanitizeForExport)
    },
    exportedAt: new Date().toISOString()
  }
}

function sanitizeForExport(data: any): any {
  if (!data) return null

  // 内部フィールドを削除
  const { id, createdAt, updatedAt, ...rest } = data
  return rest
}

ステップ2: ユーザー削除(忘れられる権利)

// lib/user-deletion.ts
import { clerkClient } from '@clerk/nextjs/server'
import { db } from './db'

interface DeletionResult {
  success: boolean
  deletedFrom: string[]
  errors: string[]
}

export async function deleteUserCompletely(userId: string): Promise<DeletionResult> {
  const result: DeletionResult = {
    success: true,
    deletedFrom: [],
    errors: []
  }

  // ステップ1: アプリケーションデータベースから削除
  try {
    await db.$transaction([
      // 関連レコードを先に削除(外部キー制約)
      db.activityLog.deleteMany({ where: { userId } }),
      db.order.deleteMany({ where: { userId } }),
      db.userPreference.deleteMany({ where: { userId } }),
      db.userProfile.delete({ where: { clerkId: userId } })
    ])
    result.deletedFrom.push('application_database')
  } catch (error: any) {
    result.errors.push(`Database deletion failed: ${error.message}`)
    result.success = false
  }

  // ステップ2: Clerk から削除
  try {
    const client = await clerkClient()
    await client.users.deleteUser(userId)
    result.deletedFrom.push('clerk')
  } catch (error: any) {
    result.errors.push(`Clerk deletion failed: ${error.message}`)
    result.success = false
  }

  // ステップ3: 外部サービスから削除
  try {
    await deleteFromExternalServices(userId)
    result.deletedFrom.push('external_services')
  } catch (error: any) {
    result.errors.push(`External service deletion failed: ${error.message}`)
  }

  // 監査用に削除イベントをログ
  await logDeletionEvent(userId, result)

  return result
}

async function deleteFromExternalServices(userId: string) {
  // 分析サービスから削除
  // メールサービスから削除
  // 決済プロバイダから削除
  // など
}

async function logDeletionEvent(userId: string, result: DeletionResult) {
  // 削除の監査ログを保持(匿名化)
  await db.deletionLog.create({
    data: {
      anonymizedId: hashUserId(userId),
      deletedAt: new Date(),
      success: result.success,
      errors: result.errors
    }
  })
}

ステップ3: データ保持ポリシー

// lib/data-retention.ts
import { db } from './db'
import { clerkClient } from '@clerk/nextjs/server'

interface RetentionPolicy {
  activityLogs: number // 日数
  sessions: number // 日数
  inactiveUsers: number // 日数
}

const RETENTION_POLICY: RetentionPolicy = {
  activityLogs: 90,
  sessions: 30,
  inactiveUsers: 365
}

export async function enforceRetentionPolicy() {
  const now = new Date()

  // 古いアクティビティログをクリーンアップ
  const activityCutoff = new Date(
    now.getTime() - RETENTION_POLICY.activityLogs * 24 * 60 * 60 * 1000
  )

  const deletedLogs = await db.activityLog.deleteMany({
    where: {
      timestamp: { lt: activityCutoff }
    }
  })

  console.log(`Deleted ${deletedLogs.count} old activity logs`)

  // 非アクティブなユーザーを通知用に特定
  const inactiveCutoff = new Date(
    now.getTime() - RETENTION_POLICY.inactiveUsers * 24 * 60 * 60 * 1000
  )

  const inactiveUsers = await db.userProfile.findMany({
    where: {
      lastActiveAt: { lt: inactiveCutoff },
      notifiedAboutInactivity: false
    }
  })

  // 削除前に非アクティブなユーザーに通知
  for (const user of inactiveUsers) {
    await notifyInactiveUser(user.clerkId)
    await db.userProfile.update({
      where: { id: user.id },
      data: { notifiedAboutInactivity: true }
    })
  }

  console.log(`Notified ${inactiveUsers.length} inactive users`)
}

ステップ4: 同意管理

// lib/consent.ts
import { currentUser } from '@clerk/nextjs/server'

interface ConsentRecord {
  marketing: boolean
  analytics: boolean
  thirdParty: boolean
  updatedAt: Date
}

export async function getConsent(userId: string): Promise<ConsentRecord | null> {
  const user = await currentUser()

  if (!user) return null

  return {
    marketing: user.publicMetadata?.consent?.marketing ?? false,
    analytics: user.publicMetadata?.consent?.analytics ?? false,
    thirdParty: user.publicMetadata?.consent?.thirdParty ?? false,
    updatedAt: new Date(user.publicMetadata?.consent?.updatedAt || user.createdAt)
  }
}

export async function updateConsent(
  userId: string,
  consent: Partial<ConsentRecord>
) {
  const client = await clerkClient()

  const user = await client.users.getUser(userId)
  const currentConsent = user.publicMetadata?.consent || {}

  await client.users.updateUser(userId, {
    publicMetadata: {
      ...user.publicMetadata,
      consent: {
        ...currentConsent,
        ...consent,
        updatedAt: new Date().toISOString()
      }
    }
  })

  // 監査用に同意変更をログ
  await logConsentChange(userId, consent)
}

ステップ5: GDPR API エンドポイント

// app/api/user/data/route.ts
import { auth } from '@clerk/nextjs/server'
import { exportUserData } from '@/lib/data-export'

// データエクスポート(GDPR 第20条)
export async function GET() {
  const { userId } = await auth()

  if (!userId) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const userData = await exportUserData(userId)

  return new Response(JSON.stringify(userData, null, 2), {
    headers: {
      'Content-Type': 'application/json',
      'Content-Disposition': `attachment; filename="user-data-${userId}.json"`
    }
  })
}

// app/api/user/delete/route.ts
import { deleteUserCompletely } from '@/lib/user-deletion'

// データ削除(GDPR 第17条)
export async function DELETE() {
  const { userId } = await auth()

  if (!userId) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  // 確認が必要
  const confirmed = request.headers.get('X-Confirm-Delete') === 'true'
  if (!confirmed) {
    return Response.json(
      { error: 'Confirmation required', requiresHeader: 'X-Confirm-Delete: true' },
      { status: 400 }
    )
  }

  const result = await deleteUserCompletely(userId)

  if (result.success) {
    return Response.json({ message: 'Account deleted successfully' })
  } else {
    return Response.json(
      { error: 'Partial deletion', details: result },
      { status: 500 }
    )
  }
}

ステップ6: 監査ログ

// lib/audit-log.ts
interface AuditEvent {
  type: 'data_access' | 'data_export' | 'data_deletion' | 'consent_change'
  userId: string
  performedBy: string
  details: Record<string, any>
  timestamp: Date
}

export async function logAuditEvent(event: Omit<AuditEvent, 'timestamp'>) {
  await db.auditLog.create({
    data: {
      ...event,
      timestamp: new Date()
    }
  })

  // コンプライアンスのため、外部サービスにもログを記録
  if (process.env.AUDIT_LOG_ENDPOINT) {
    await fetch(process.env.AUDIT_LOG_ENDPOINT, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ ...event, timestamp: new Date() })
    })
  }
}

プライバシーチェックリスト

  • データエクスポート機能(GDPR 第20条)
  • データ削除機能(GDPR 第17条)
  • 同意管理
  • データ保持ポリシー
  • 監査ログ
  • プライバシーポリシーの更新
  • クッキー同意の実装
  • データ処理契約

出力

  • データエクスポート機能
  • ユーザー削除機能
  • 同意管理
  • 監査ログ

エラーハンドリング

シナリオ対応
部分的な削除失敗したサービスを再試行し、手動レビュー用にログ
エクスポートタイムアウトエクスポートをキューに入れ、完了時にメール送信
同意の同期失敗指数バックオフで再試行

リソース

次のステップ

clerk-enterprise-rbac に進み、エンタープライズ SSO と RBAC について学習してください。

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
Brmbobo
リポジトリ
Brmbobo/Web2podcast
ライセンス
MIT
最終更新
2026/1/26

Source: https://github.com/Brmbobo/Web2podcast / ライセンス: MIT

関連スキル

Anthropic Claudeセキュリティ⭐ リポ 8,981

secure-code-guardian

認証・認可の実装、ユーザー入力の保護、OWASP Top 10の脆弱性対策が必要な場合に使用します。bcrypt/argon2によるパスワードハッシング、パラメータ化ステートメントによるSQLインジェクション対策、CORS/CSPヘッダーの設定、Zodによる入力検証、JWTトークンの構築などのカスタムセキュリティ実装に対応します。認証、認可、入力検証、暗号化、OWASP Top 10対策、セッション管理、セキュリティ強化全般で活用できます。ただし、構築済みのOAuth/SSO統合や単独のセキュリティ監査が必要な場合は、より特化したスキルの検討をお勧めします。

by Jeffallan
汎用セキュリティ⭐ リポ 1,982

claude-authenticity

APIエンドポイントが本物のClaudeによって支えられているか(ラッパーやプロキシ、偽装ではないか)を、claude-verifyプロジェクトを模した9つの重み付きルールベースチェックで検証できます。また、Claudeの正体を上書きしているプロバイダーから注入されたシステムプロンプトも抽出します。完全に自己完結しており、httpx以外の追加パッケージは不要です。Claude APIキーまたはエンドポイントを検証したい場合、サードパーティのClaudeサービスが本物か確認したい場合、APIプロバイダーのClaude正当性を監査したい場合、複数モデルを並行してテストしたい場合、またはプロバイダーが注入したシステムプロンプトを特定したい場合に使用できます。

by LeoYeAI
Anthropic Claudeセキュリティ⭐ リポ 2,159

anth-security-basics

Anthropic Claude APIのセキュリティベストプラクティスを適用し、キー管理、入力値の検証、プロンプトインジェクション対策を実施します。APIキーの保護、Claudeに送信する前のユーザー入力検証、コンテンツセーフティガードレールの実装が必要な場合に活用できます。「anthropic security」「claude api key security」「secure anthropic」「prompt injection defense」といったフレーズでトリガーされます。

by jeremylongshore
汎用セキュリティ⭐ リポ 699

x-ray

x-ray.mdプレ監査レポートを生成します。概要、強化された脅威モデル(プロトコルタイプのプロファイリング、Gitの重み付け攻撃面分析、時間軸リスク分析、コンポーザビリティ依存関係マッピング)、不変条件、統合、ドキュメント品質、テスト分析、開発者・Gitの履歴をカバーしています。「x-ray」「audit readiness」「readiness report」「pre-audit report」「prep this protocol」「protocol prep」「summarize this protocol」のキーワードで実行されます。

by pashov
汎用セキュリティ⭐ リポ 677

semgrep

Semgrepスタティック分析スキャンを実行し、カスタム検出ルールを作成します。Semgrepでのコードスキャン、セキュリティ脆弱性の検出、カスタムYAMLルールの作成、または特定のバグパターンの検出が必要な場合に使用します。重要:ユーザーが「バグをスキャンしたい」「コード品質を確認したい」「脆弱性を見つけたい」「スタティック分析」「セキュリティlint」「コード監査」または「コーディング標準を適用したい」と尋ねた場合も、Semgrepという名称を明記していなくても、このスキルを使用してください。Semgrepは30以上の言語に対応したパターンベースのコードスキャンに最適なツールです。

by wimpysworld
汎用セキュリティ⭐ リポ 591

ghost-bits-cast-attack

Java「ゴーストビッツ」/キャストアタック プレイブック(Black Hat Asia 2026)。16ビット文字が8ビットバイトに暗黙的に縮小されるJavaサービスへの攻撃時に使用します。WAF/IDSを回避して、SQLインジェクション、デシリアライゼーション型RCE、ファイルアップロード(Webシェル)、パストトラバーサル、CRLF インジェクション、リクエストスマグリング、SMTPインジェクションを実行できます。Tomcat、Spring、Jetty、Undertow、Vert.x、Jackson、Fastjson、Apache Commons BCEL、Apache HttpClient、Angus Mail、JDK HttpServer、Lettuce、Jodd、XMLWriterに影響し、WAFバイパスにより多くの「パッチ済み」CVEを再度有効化します。

by yaklang
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: Brmbobo · Brmbobo/Web2podcast · ライセンス: MIT