Communitygithub.com

Perl セキュリティ

Perlアプリケーションのセキュリティを包括的にカバー。汚染モード、入力検証、安全なプロセス実行、DBIパラメータ化クエリ、Webセキュリティ(XSS/SQLi/CSRF)、perlcriticセキュリティポリシーを含む。Perlの入力処理、プロセス実行、DBIクエリ、Web向けコードのレビュー時に使用。

Perl セキュリティ とは?

このスキルは、Perlアプリケーションにおけるセキュリティリスクを体系的に特定・防止するための包括的なガイドラインを提供します。主に、汚染モード(-T)による入力元の追跡と明示的な検証・解除、正規表現による許可リスト方式の入力検証、3引数openやFile::Tempを用いた安全なファイル操作、list形式のsystemやIPC::Run3による安全なプロセス実行、DBIプレースホルダを使用したSQLインジェクション防止、HTML::Entitiesやテンプレートの自動エスケープを活用したXSS対策、そしてCSRFトークンやセキュリティヘッダーの設定など、多層的な防御策をコード例とともに示しています。また、perlcriticを用いたセキュリティポリシーの自動チェックや、依存モジュールの管理、一時ファイルやパストラバーサル対策、ReDoS防止のための正規表現の安全な書き方についても詳しく解説しており、セキュリティレビューやコード監査の際に特に有用です。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/perl-security

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Perl セキュリティパターン

Perlアプリケーションにおける、入力検証、インジェクション防止、安全なコーディング手法を網羅した包括的なセキュリティガイドライン。

アクティベーション条件

  • Perlアプリケーションでユーザー入力を扱う場合
  • Perl Webアプリケーション(CGI、Mojolicious、Dancer2、Catalyst)を構築する場合
  • Perlコードのセキュリティ脆弱性をレビューする場合
  • ユーザー指定のパスでファイル操作を行う場合
  • Perlからシステムコマンドを実行する場合
  • DBIデータベースクエリを作成する場合

動作の仕組み

まず、汚染を認識した入力境界から開始し、外側に向かって処理を進めます。つまり、入力を検証・汚染解除し、ファイルシステムとプロセス実行を制約し、すべてのDBIクエリでパラメータ化クエリを使用します。以下の例は、このスキルが、ユーザー入力、シェル、またはネットワークに触れるPerlコードをリリースする前に適用すべき安全なデフォルトを示しています。

汚染モード

Perlの汚染モード(-T)は、外部ソースからのデータを追跡し、明示的な検証なしに安全でない操作で使用されるのを防ぎます。

汚染モードの有効化

#!/usr/bin/perl -T
use v5.36;

# 汚染: プログラム外部からの全てのもの
my $input    = $ARGV[0];        # 汚染
my $env_path = $ENV{PATH};      # 汚染
my $form     = <STDIN>;         # 汚染
my $query    = $ENV{QUERY_STRING}; # 汚染

# PATHを早期にサニタイズ(汚染モードで必須)
$ENV{PATH} = '/usr/local/bin:/usr/bin:/bin';
delete @ENV{qw(IFS CDPATH ENV BASH_ENV)};

汚染解除パターン

use v5.36;

# Good: 特定の正規表現で検証し、汚染解除
sub untaint_username($input) {
    if ($input =~ /^([a-zA-Z0-9_]{3,30})$/) {
        return $1;  # $1は汚染解除済み
    }
    die "ユーザー名が無効です: 3〜30文字の英数字である必要があります\n";
}

# Good: ファイルパスを検証し汚染解除
sub untaint_filename($input) {
    if ($input =~ m{^([a-zA-Z0-9._-]+)$}) {
        return $1;
    }
    die "ファイル名が無効です: 安全でない文字が含まれています\n";
}

# Bad: 過度に寛容な汚染解除(目的を無効化)
sub bad_untaint($input) {
    $input =~ /^(.*)$/s;
    return $1;  # 何でも受け入れる — 無意味
}

入力検証

ブロックリストより許可リスト

use v5.36;

# Good: 許可リスト — 許可されるものを正確に定義
sub validate_sort_field($field) {
    my %allowed = map { $_ => 1 } qw(name email created_at updated_at);
    die "ソートフィールドが無効です: $field\n" unless $allowed{$field};
    return $field;
}

# Good: 特定のパターンで検証
sub validate_email($email) {
    if ($email =~ /^([a-zA-Z0-9._%+-]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/) {
        return $1;
    }
    die "メールアドレスが無効です\n";
}

sub validate_integer($input) {
    if ($input =~ /^(-?\d{1,10})$/) {
        return $1 + 0;  # 数値に変換
    }
    die "整数が無効です\n";
}

# Bad: ブロックリスト — 常に不完全
sub bad_validate($input) {
    die "無効" if $input =~ /[<>"';&|]/;  # エンコードされた攻撃を見逃す
    return $input;
}

長さ制約

use v5.36;

sub validate_comment($text) {
    die "コメントは必須です\n"        unless length($text) > 0;
    die "コメントが10000文字を超えています\n" if length($text) > 10_000;
    return $text;
}

安全な正規表現

ReDoS 対策

壊滅的なバックトラッキングは、重複するパターンにネストされた量指定子がある場合に発生します。

use v5.36;

# Bad: ReDoSに対して脆弱(指数関数的なバックトラッキング)
my $bad_re = qr/^(a+)+$/;           # ネストされた量指定子
my $bad_re2 = qr/^([a-zA-Z]+)*$/;   # クラスに対するネストされた量指定子
my $bad_re3 = qr/^(.*?,){10,}$/;    # 繰り返される貪欲/非貪欲の組み合わせ

# Good: ネストなしで書き直す
my $good_re = qr/^a+$/;             # 単一の量指定子
my $good_re2 = qr/^[a-zA-Z]+$/;     # クラスに対する単一の量指定子

# Good: 占有量指定子またはアトミックグループを使用してバックトラッキングを防止
my $safe_re = qr/^[a-zA-Z]++$/;             # 占有 (5.10以降)
my $safe_re2 = qr/^(?>a+)$/;                # アトミックグループ

# Good: 信頼できないパターンにはタイムアウトを適用
use POSIX qw(alarm);
sub safe_match($string, $pattern, $timeout = 2) {
    my $matched;
    eval {
        local $SIG{ALRM} = sub { die "正規表現タイムアウト\n" };
        alarm($timeout);
        $matched = $string =~ $pattern;
        alarm(0);
    };
    alarm(0);
    die $@ if $@;
    return $matched;
}

安全なファイル操作

3引数open

use v5.36;

# Good: 3引数open、レキシカルファイルハンドル、戻り値チェック
sub read_file($path) {
    open my $fh, '<:encoding(UTF-8)', $path
        or die "'$path' を開けません: $!\n";
    local $/;
    my $content = <$fh>;
    close $fh;
    return $content;
}

# Bad: ユーザーデータを使用した2引数open(コマンドインジェクション)
sub bad_read($path) {
    open my $fh, $path;        # $path = "|rm -rf /" の場合、コマンド実行!
    open my $fh, "< $path";   # シェルメタ文字インジェクション
}

TOCTOU 防止とパストラバーサル

use v5.36;
use Fcntl qw(:DEFAULT :flock);
use File::Spec;
use Cwd qw(realpath);

# アトミックなファイル作成
sub create_file_safe($path) {
    sysopen(my $fh, $path, O_WRONLY | O_CREAT | O_EXCL, 0600)
        or die "'$path' を作成できません: $!\n";
    return $fh;
}

# パスが許可されたディレクトリ内に留まることを検証
sub safe_path($base_dir, $user_path) {
    my $real = realpath(File::Spec->catfile($base_dir, $user_path))
        // die "パスが存在しません\n";
    my $base_real = realpath($base_dir)
        // die "ベースディレクトリが存在しません\n";
    die "パストラバーサルをブロックしました\n" unless $real =~ /^\Q$base_real\E(?:\/|\z)/;
    return $real;
}

一時ファイルには File::Temp(tempfile(UNLINK => 1))、レースコンディション防止には flock(LOCK_EX) を使用します。

安全なプロセス実行

list形式のsystemとexec

use v5.36;

# Good: list形式 — シェルによる解釈なし
sub run_command(@cmd) {
    system(@cmd) == 0
        or die "コマンドが失敗しました: @cmd\n";
}

run_command('grep', '-r', $user_pattern, '/var/log/app/');

# Good: IPC::Run3で安全に出力を取得
use IPC::Run3;
sub capture_output(@cmd) {
    my ($stdout, $stderr);
    run3(\@cmd, \undef, \$stdout, \$stderr);
    if ($?) {
        die "コマンドが失敗しました (exit $?): $stderr\n";
    }
    return $stdout;
}

# Bad: 文字列形式 — シェルインジェクション!
sub bad_search($pattern) {
    system("grep -r '$pattern' /var/log/app/");  # $pattern = "'; rm -rf / #" の場合
}

# Bad: 変数展開を含むバッククォート
my $output = `ls $user_dir`;   # シェルインジェクションのリスク

また、外部コマンドからのstdout/stderrを安全に取得するために Capture::Tiny を使用することもできます。

SQLインジェクション防止

DBIプレースホルダ

use v5.36;
use DBI;

my $dbh = DBI->connect($dsn, $user, $pass, {
    RaiseError => 1,
    PrintError => 0,
    AutoCommit => 1,
});

# Good: パラメータ化クエリ — 常にプレースホルダを使用
sub find_user($dbh, $email) {
    my $sth = $dbh->prepare('SELECT * FROM users WHERE email = ?');
    $sth->execute($email);
    return $sth->fetchrow_hashref;
}

sub search_users($dbh, $name, $status) {
    my $sth = $dbh->prepare(
        'SELECT * FROM users WHERE name LIKE ? AND status = ? ORDER BY name'
    );
    $sth->execute("%$name%", $status);
    return $sth->fetchall_arrayref({});
}

# Bad: SQL内の文字列展開(SQLi脆弱性!)
sub bad_find($dbh, $email) {
    my $sth = $dbh->prepare("SELECT * FROM users WHERE email = '$email'");
    # $email = "' OR 1=1 --" の場合、全てのユーザーを返す
    $sth->execute;
    return $sth->fetchrow_hashref;
}

動的カラム許可リスト

use v5.36;

# Good: 許可リストに対してカラム名を検証
sub order_by($dbh, $column, $direction) {
    my %allowed_cols = map { $_ => 1 } qw(name email created_at);
    my %allowed_dirs = map { $_ => 1 } qw(ASC DESC);

    die "カラムが無効です: $column\n"    unless $allowed_cols{$column};
    die "方向が無効です: $direction\n" unless $allowed_dirs{uc $direction};

    my $sth = $dbh->prepare("SELECT * FROM users ORDER BY $column $direction");
    $sth->execute;
    return $sth->fetchall_arrayref({});
}

# Bad: ユーザー選択のカラムを直接展開
sub bad_order($dbh, $column) {
    $dbh->prepare("SELECT * FROM users ORDER BY $column");  # SQLi!
}

DBIx::Class (ORM 安全性)

use v5.36;

# DBIx::Classは安全なパラメータ化クエリを生成
my @users = $schema->resultset('User')->search({
    status => 'active',
    email  => { -like => '%@example.com' },
}, {
    order_by => { -asc => 'name' },
    rows     => 50,
});

Webセキュリティ

XSS防止

use v5.36;
use HTML::Entities qw(encode_entities);
use URI::Escape qw(uri_escape_utf8);

# Good: HTMLコンテキスト用に出力をエンコード
sub safe_html($user_input) {
    return encode_entities($user_input);
}

# Good: URLコンテキスト用にエンコード
sub safe_url_param($value) {
    return uri_escape_utf8($value);
}

# Good: JSONコンテキスト用にエンコード
use JSON::MaybeXS qw(encode_json);
sub safe_json($data) {
    return encode_json($data);  # エスケープを処理
}

# テンプレートの自動エスケープ (Mojolicious)
# <%= $user_input %>   — 自動エスケープ(安全)
# <%== $raw_html %>    — 生出力(危険、信頼できるコンテンツにのみ使用)

# テンプレートの自動エスケープ (Template Toolkit)
# [% user_input | html %]  — 明示的なHTMLエンコード

# Bad: HTML内での生出力
sub bad_html($input) {
    print "<div>$input</div>";  # $input に <script> が含まれるとXSS
}

CSRF対策

use v5.36;
use Crypt::URandom qw(urandom);
use MIME::Base64 qw(encode_base64url);

sub generate_csrf_token() {
    return encode_base64url(urandom(32));
}

トークンの検証には、必ず定数時間比較を使用します。ほとんどのWebフレームワーク(Mojolicious、Dancer2、Catalyst)は組み込みのCSRF対策を提供しているため、自作の解決策よりもそれらを優先してください。

セッションとヘッダーセキュリティ

use v5.36;

# Mojolicious セッション + ヘッダー
$app->secrets(['定期的にローテーションされる長いランダムシークレット']);
$app->sessions->secure(1);          # HTTPSのみ
$app->sessions->samesite('Lax');

$app->hook(after_dispatch => sub ($c) {
    $c->res->headers->header('X-Content-Type-Options' => 'nosniff');
    $c->res->headers->header('X-Frame-Options'        => 'DENY');
    $c->res->headers->header('Content-Security-Policy' => "default-src 'self'");
    $c->res->headers->header('Strict-Transport-Security' => 'max-age=31536000; includeSubDomains');
});

出力エンコーディング

常にコンテキストに応じて出力をエンコードします。HTMLには HTML::Entities::encode_entities()、URLには URI::Escape::uri_escape_utf8()、JSONには JSON::MaybeXS::encode_json() を使用します。

CPANモジュールのセキュリティ

  • バージョンを固定 cpanfileで: requires 'DBI', '== 1.643';
  • メンテナンスされているモジュールを優先: MetaCPANで最近のリリースを確認
  • 依存関係を最小限に: 各依存関係は攻撃対象となります

セキュリティツール

perlcritic セキュリティポリシー

# .perlcriticrc — セキュリティ重視の設定
severity = 3
theme = security + core

# 3引数openを要求
[InputOutput::RequireThreeArgOpen]
severity = 5

# チェック付きシステムコールを要求
[InputOutput::RequireCheckedSyscalls]
functions = :builtins
severity = 4

# 文字列evalを禁止
[BuiltinFunctions::ProhibitStringyEval]
severity = 5

# バッククォート演算子を禁止
[InputOutput::ProhibitBacktickOperators]
severity = 4

# CGIでの汚染チェックを要求
[Modules::RequireTaintChecking]
severity = 5

# 2引数openを禁止
[InputOutput::ProhibitTwoArgOpen]
severity = 5

# 裸のワードファイルハンドルを禁止
[InputOutput::ProhibitBarewordFileHandles]
severity = 5

perlcriticの実行

# ファイルをチェック
perlcritic --severity 3 --theme security lib/MyApp/Handler.pm

# プロジェクト全体をチェック
perlcritic --severity 3 --theme security lib/

# CI統合
perlcritic --severity 4 --theme security --quiet lib/ || exit 1

クイックセキュリティチェックリスト

チェック項目確認内容
汚染モードCGI/Webスクリプトでの -T フラグ
入力検証許可リストパターン、長さ制限
ファイル操作3引数open、パストラバーサルチェック
プロセス実行list形式のsystem、シェル展開なし
SQLクエリDBIプレースホルダ、決して展開しない
HTML出力encode_entities()、テンプレート自動エスケープ
CSRFトークン状態変更リクエストで生成・検証
セッション設定Secure、HttpOnly、SameSiteクッキー
HTTPヘッダーCSP、X-Frame-Options、HSTS
依存関係バージョン固定、監査済みモジュール
正規表現の安全性ネストされた量指定子なし、アンカー付きパターン
エラーメッセージスタックトレースやパスがユーザーに漏れないこと

アンチパターン

# 1. ユーザーデータを使用した2引数open(コマンドインジェクション)
open my $fh, $user_input;               # 重大な脆弱性

# 2. 文字列形式のsystem(シェルインジェクション)
system("convert $user_file output.png"); # 重大な脆弱性

# 3. SQL文字列展開
$dbh->do("DELETE FROM users WHERE id = $id");  # SQLi

# 4. ユーザー入力によるeval(コードインジェクション)
eval $user_code;                         # リモートコード実行

# 5. サニタイズなしで $ENV を信頼
my $path = $ENV{UPLOAD_DIR};             # 操作される可能性あり
system("ls $path");                      # 二重脆弱性

# 6. 検証なしでの汚染解除
($input) = $input =~ /(.*)/s;           # 怠惰な汚染解除 — 目的を無効化

# 7. HTML内での生ユーザーデータ
print "<div>ようこそ、$username さん!</div>";  # XSS

# 8. 検証されていないリダイレクト
print $cgi->redirect($user_url);         # オープンリダイレクト

覚えておいてください: Perlの柔軟性は強力ですが、規律が必要です。Web向けコードには汚染モードを使用し、すべての入力を許可リストで検証し、すべてのクエリにDBIプレースホルダを使用し、すべての出力をそのコンテキストに応じてエンコードしてください。多層防御 — 決して単一の層に依存しないでください。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

関連スキル