You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl测试中拦截外部URL HTTP请求的标准实现方式是什么?

问题场景

给定以下Perl代码,解析XML时会触发外部实体(XXE)调用嵌入的URL:

use 5.020;
use XML::LibXML ();

XML::LibXML->load_xml( string => <<'EOF' );
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://webhook.site/<unique-token>">]>
<foo>&xxe;</foo>
EOF

我希望编写测试用例,当解析XML字符串触发外部URL调用时让测试失败。思路是拦截指定URL的请求,以此判断测试是否通过,测试框架用Test2::V0,代码框架如下:

use 5.020;
use Test2::V0;

ok makes_no_http_requests {
    # 上述XML解析代码
}, 'should not make any HTTP requests';

done_testing;

sub makes_no_http_requests {
    # 如何实现?
}

请问在Perl中是否有标准的实现方式?


实现方案

有两种核心思路可以解决这个问题,优先推荐从根源阻止XXE的方式,其次是拦截HTTP请求做测试验证:

1. 直接禁用XML外部实体(最根本的解决方案)

XML::LibXML本身提供了安全配置项,可以从根源上禁止外部实体的加载和网络请求,这比拦截HTTP请求更高效,也是防御XXE漏洞的标准做法。

你可以创建解析器时设置以下参数:

use 5.020;
use XML::LibXML ();

my $parser = XML::LibXML->new(
    no_network => 1,        # 禁止发起网络请求
    expand_entities => 0,   # 禁止展开外部实体
    load_ext_dtd => 0,      # 禁止加载外部DTD文件
);

$parser->load_xml( string => <<'EOF' );
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://webhook.site/<unique-token>">]>
<foo>&xxe;</foo>
EOF

对应的测试用例可以直接验证解析过程不会触发网络请求,或者验证解析器的安全参数是否正确配置。

2. 拦截HTTP请求(用于测试现有代码安全性)

如果需要测试现有代码是否存在XXE风险,可以通过Mock HTTP客户端的方式拦截所有请求,具体有两种实现:

方法一:用Test::LWP::UserAgent替换全局HTTP客户端

XML::LibXML底层通常依赖LWP处理网络请求,用这个模块可以替换默认的用户代理,拦截并阻止所有请求:

use 5.020;
use Test2::V0;
use Test::LWP::UserAgent;
use XML::LibXML ();

sub makes_no_http_requests {
    my $code = shift;

    # 创建Mock客户端,任何请求都会触发报错
    my $mock_ua = Test::LWP::UserAgent->new;
    $mock_ua->map_response(qr/.*/, sub { die "意外发起HTTP请求" });

    # 临时替换全局LWP构造函数,执行代码后自动恢复
    my $original_ua = LWP::UserAgent->new;
    local *LWP::UserAgent::new = sub { $mock_ua };

    eval { $code->(); };
    return !$@;
}

ok makes_no_http_requests {
    XML::LibXML->load_xml( string => <<'EOF' );
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://webhook.site/<unique-token>">]>
<foo>&xxe;</foo>
EOF
}, '解析XML时不应发起HTTP请求';

done_testing;

方法二:重写XML::LibXML的外部实体处理回调

XML::LibXML允许自定义外部实体的处理逻辑,你可以在回调中直接抛出错误,阻止请求执行:

use 5.020;
use Test2::V0;
use XML::LibXML ();

sub makes_no_http_requests {
    my $code = shift;

    my $parser = XML::LibXML->new;
    # 设置外部实体处理回调,一旦触发就报错
    $parser->set_ext_ent_handler(sub {
        die "尝试访问外部实体: $_[1]";
    });

    # 临时替换XML::LibXML的load_xml方法,使用自定义解析器
    local *XML::LibXML::load_xml = sub {
        $parser->load_xml(@_);
    };

    eval { $code->(); };
    return !$@;
}

ok makes_no_http_requests {
    XML::LibXML->load_xml( string => <<'EOF' );
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://webhook.site/<unique-token>">]>
<foo>&xxe;</foo>
EOF
}, '解析XML时不应发起HTTP请求';

done_testing;

内容的提问来源于stack exchange,提问作者j1n3l0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:53:27