Communitygithub.com

Perlセキュリティ

Perlアプリケーションにおけるテイントモード、入力検証、安全なプロセス実行、DBIパラメータ化クエリ、Webセキュリティ(XSS/SQLi/CSRF)、perlcriticセキュリティポリシーを網羅した包括的なセキュリティパターン集。

Perlセキュリティ とは?

これはPerlアプリケーションのための包括的なセキュリティパターン集であり、入力バリデーション、インジェクション防止、安全なコーディング手法をカバーします。テイントモードの有効化と適切なアンテイントパターン、許可リストによる入力検証、ReDoS対策を含む安全な正規表現、3引数openやTOCTOU防止を含む安全なファイル操作、リスト形式systemやIPC::Run3を使用した安全なプロセス実行、DBIプレースホルダーを使用したSQLインジェクション防止、HTML/URL/JSONのコンテキストに応じた出力エンコーディング、CSRFトークン生成、セッションとHTTPヘッダーのセキュリティ設定など、Perl開発者が直面する主要なセキュリティ問題に対する具体的で実践的な対策が豊富なコード例とともに提供されています。また、perlcriticを用いたセキュリティポリシーの自動チェック設定や、クイックチェックリスト、アンチパターンのリストも含まれており、コードレビューやCI/CDパイプラインに統合して使用できます。CGI、Mojolicious、Dancer2、CatalystなどのPerl Webフレームワークを使用するアプリケーションや、ユーザー入力、ファイル操作、システムコマンド、データベースクエリを扱うあらゆるPerlコードに適用可能です。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/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;

# 良い: 特定の正規表現で検証してアンテイント
sub untaint_username($input) {
    if ($input =~ /^([a-zA-Z0-9_]{3,30})$/) {
        return $1;  # $1はアンテイントされている
    }
    die "Invalid username: must be 3-30 alphanumeric characters\n";
}

# 良い: ファイルパスを検証してアンテイント
sub untaint_filename($input) {
    if ($input =~ m{^([a-zA-Z0-9._-]+)$}) {
        return $1;
    }
    die "Invalid filename: contains unsafe characters\n";
}

# 悪い: 過度に寛容なアンテイント(目的を無効にする)
sub bad_untaint($input) {
    $input =~ /^(.*)$/s;
    return $1;  # 何でも受け入れる — 無意味
}

入力検証

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

use v5.36;

# 良い: 許可リスト — 正確に許可するものを定義
sub validate_sort_field($field) {
    my %allowed = map { $_ => 1 } qw(name email created_at updated_at);
    die "Invalid sort field: $field\n" unless $allowed{$field};
    return $field;
}

# 良い: 特定のパターンで検証
sub validate_email($email) {
    if ($email =~ /^([a-zA-Z0-9._%+-]+\@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/) {
        return $1;
    }
    die "Invalid email address\n";
}

sub validate_integer($input) {
    if ($input =~ /^(-?\d{1,10})$/) {
        return $1 + 0;  # 数値に強制変換
    }
    die "Invalid integer\n";
}

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

長さ制約

use v5.36;

sub validate_comment($text) {
    die "Comment is required\n"        unless length($text) > 0;
    die "Comment exceeds 10000 chars\n" if length($text) > 10_000;
    return $text;
}

安全な正規表現

ReDoS対策

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

use v5.36;

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

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

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

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

安全なファイル操作

3引数open

use v5.36;

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

# 悪い: ユーザーデータでの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 "Cannot create '$path': $!\n";
    return $fh;
}

# パスが許可されたディレクトリ内に留まることを検証
sub safe_path($base_dir, $user_path) {
    my $real = realpath(File::Spec->catfile($base_dir, $user_path))
        // die "Path does not exist\n";
    my $base_real = realpath($base_dir)
        // die "Base dir does not exist\n";
    die "Path traversal blocked\n" unless $real =~ /^\Q$base_real\E(?:\/|\z)/;
    return $real;
}

一時ファイルにはFile::Temp(tempfile(UNLINK => 1))を使用し、競合状態を防ぐためにflock(LOCK_EX)を使用します。

安全なプロセス実行

リスト形式のsystemとexec

use v5.36;

# 良い: リスト形式 — シェル展開なし
sub run_command(@cmd) {
    system(@cmd) == 0
        or die "Command failed: @cmd\n";
}

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

# 良い: IPC::Run3で安全に出力をキャプチャ
use IPC::Run3;
sub capture_output(@cmd) {
    my ($stdout, $stderr);
    run3(\@cmd, \undef, \$stdout, \$stderr);
    if ($?) {
        die "Command failed (exit $?): $stderr\n";
    }
    return $stdout;
}

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

# 悪い: 補間のあるバッククォート
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,
});

# 良い: パラメータ化クエリ — 常にプレースホルダーを使用
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({});
}

# 悪い: 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;

# 良い: 許可リストに対してカラム名を検証
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 "Invalid column: $column\n"    unless $allowed_cols{$column};
    die "Invalid direction: $direction\n" unless $allowed_dirs{uc $direction};

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

# 悪い: ユーザー選択のカラムを直接補間
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);

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

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

# 良い: 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エンコーディング

# 悪い: 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(['long-random-secret-rotated-regularly']);
$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、パストラバーサルチェック
プロセス実行リスト形式system、シェル補間なし
SQLクエリDBIプレースホルダー、決して補間しない
HTML出力encode_entities()、テンプレート自動エスケープ
CSRFトークン生成済み、状態変更リクエストで検証
セッション設定Secure、HttpOnly、SameSite Cookie
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>Welcome, $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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

関連スキル