Communitygithub.com

Perl 安全规范

涵盖污点模式、输入验证、安全进程执行、DBI 参数化查询、Web 安全(XSS/SQLi/CSRF)以及 perlcritic 安全策略的全面 Perl 安全指南。在审查 Perl 输入处理、进程执行、DBI 查询或 Web 端代码时使用。

Perl 安全规范 是什么?

此技能为 Perl 应用提供全面的安全编码模式与指南,重点涵盖污点模式、输入验证、防注入、安全文件与进程操作、SQL 注入防护以及 Web 安全。它面向处理用户输入、构建 Web 应用、审查安全漏洞或执行数据库及系统调用的开发人员。技能详细解释了如何启用污点模式 ( -T ) 并通过正则表达式安全地取消污点数据,如何利用白名单验证而非黑名单来加固输入,以及如何通过三参数 open、基于列表的 system 调用和 DBI 占位符避免命令与 SQL 注入。此外,它还涉及 ReDoS 防护、TOCTOU 预防、CSRF 令牌生成,以及使用 HTML::Entities 等模块进行输出编码。最后,技能提供了一个 perlcritic 配置示例用于自动化安全检查,并附带一个安全清单和常见反模式列表,帮助开发人员避免常见陷阱。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/perl-security

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Perl 安全模式

涵盖输入验证、注入防护和安全编码实践的 Perl 应用程序综合安全指南。

何时激活

  • 在 Perl 应用程序中处理用户输入时
  • 构建 Perl Web 应用程序(CGI、Mojolicious、Dancer2、Catalyst)时
  • 审查 Perl 代码中的安全漏洞时
  • 使用用户提供的路径执行文件操作时
  • 从 Perl 执行系统命令时
  • 编写 DBI 数据库查询时

工作方式

从污点感知的输入边界开始,然后向外扩展:验证和取消污点数据,保持文件系统和进程执行的约束,并在所有地方使用参数化的 DBI 查询。下面的示例展示了在发布触碰用户输入、shell 或网络的 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 "无效的用户名:必须是 3-30 个字母数字字符\n";
}

# 好:验证并取消文件路径的污点
sub untaint_filename($input) {
    if ($input =~ m{^([a-zA-Z0-9._-]+)$}) {
        return $1;
    }
    die "无效的文件名:包含不安全字符\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 "无效的排序字段:$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 "无效的邮箱地址\n";
}

sub validate_integer($input) {
    if ($input =~ /^(-?\d{1,10})$/) {
        return $1 + 0;  # 转换为数字
    }
    die "无效的整数\n";
}

# 坏:黑名单——总是有遗漏
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;

# 坏:易受 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 "正则表达式超时\n" };
        alarm($timeout);
        $matched = $string =~ $pattern;
        alarm(0);
    };
    alarm(0);
    die $@ if $@;
    return $matched;
}

安全文件操作

三参数 Open

use v5.36;

# 好:三参数 open,词法文件句柄,检查返回值
sub read_file($path) {
    open my $fh, '<:encoding(UTF-8)', $path
        or die "无法打开 '$path':$!\n";
    local $/;
    my $content = <$fh>;
    close $fh;
    return $content;
}

# 坏:使用用户数据的二参数 open(命令注入)
sub bad_read($path) {
    open my $fh, $path;        # 如果 $path = "|rm -rf /",则会执行命令!
    open my $fh, "< $path";   # Shell 元字符注入
}

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) 来防止竞态条件。

安全进程执行

列表形式的 system 和 exec

use v5.36;

# 好:列表形式——无 shell 插值
sub run_command(@cmd) {
    system(@cmd) == 0
        or die "命令失败:@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 "命令失败 (exit $?):$stderr\n";
    }
    return $stdout;
}

# 坏:字符串形式——shell 注入!
sub bad_search($pattern) {
    system("grep -r '$pattern' /var/log/app/");  # 如果 $pattern = "'; rm -rf / #"
}

# 坏:带插值的反引号
my $output = `ls $user_dir`;   # Shell 注入风险

同时可使用 Capture::Tiny 安全地捕获外部命令的 stdout/stderr。

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 "无效的列:$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({});
}

# 坏:直接插值用户选择的列
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

# 要求三参数 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

# 禁止二参数 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 标志
输入验证白名单模式,长度限制
文件操作三参数 open,路径遍历检查
进程执行列表形式 system,无 shell 插值
SQL 查询DBI 占位符,绝不插值
HTML 输出encode_entities(),模板自动转义
CSRF 令牌生成,在状态变更请求上验证
会话配置Secure、HttpOnly、SameSite Cookie
HTTP 头部CSP、X-Frame-Options、HSTS
依赖固定版本,审计过的模块
正则表达式安全无嵌套量词,锚定模式
错误消息不向用户泄露堆栈跟踪或路径

反模式

# 1. 使用用户数据的二参数 open(命令注入)
open my $fh, $user_input;               # 严重漏洞

# 2. 字符串形式 system(shell 注入)
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.

相关技能