强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Memcached 完全指南 / 第 11 章:安全加固

第 11 章:安全加固

11.1 安全威胁概览

Memcached 默认无认证、无加密、无访问控制,这使其成为常见的攻击目标。

主要威胁

威胁说明严重程度
未授权访问默认无认证,任何人可读写★★★★★
DDoS 放大攻击UDP 反射放大 51,000 倍★★★★★
数据泄露缓存中的敏感数据被窃取★★★★
缓存投毒恶意写入虚假缓存数据★★★★
缓存雪崩flush_all 导致大量回源★★★

UDP 反射放大攻击原理

Memcached UDP 反射放大攻击:

1. 攻击者伪造源 IP 为受害者 IP
2. 向 Memcached UDP 端口发送小型请求(约 15 字节)
3. Memcached 返回大量数据(约 750KB)到受害者 IP
4. 放大倍数: 750KB / 15B ≈ 51,200 倍!

预防措施:
- 禁用 UDP: -U 0
- 不暴露公网
- 防火墙规则

11.2 网络隔离(最重要)

绑定内网地址

# 只监听本机(开发环境)
memcached -l 127.0.0.1

# 只监听内网(生产环境)
memcached -l 10.0.1.10

# 禁用 UDP(防 DDoS 放大)
memcached -U 0

# 绑定 Unix Socket(最安全)
memcached -s /var/run/memcached/memcached.sock -a 0770

防火墙规则

# iptables:只允许应用服务器访问
sudo iptables -A INPUT -p tcp --dport 11211 -s 10.0.1.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 11211 -j DROP

# 禁止 UDP(防止 DDoS 放大)
sudo iptables -A INPUT -p udp --dport 11211 -j DROP

# firewalld (CentOS)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" port port="11211" protocol="tcp" accept'
sudo firewall-cmd --reload

# nftables (现代 Linux)
sudo nft add rule inet filter input ip saddr 10.0.1.0/24 tcp dport 11211 accept
sudo nft add rule inet filter input tcp dport 11211 drop
sudo nft add rule inet filter input udp dport 11211 drop

网络架构

推荐的网络架构:

Internet
    │
    ▼
┌──────────┐
│ 防火墙   │
└────┬─────┘
     │
     ▼
┌──────────┐     ┌────────────────────┐
│ Web 层   │────▶│ 应用层网络 (10.0.1) │
│ (DMZ)    │     │                    │
└──────────┘     │  ┌──────────────┐  │
                 │  │ Memcached 集群│  │
                 │  │ (内网隔离)    │  │
                 │  └──────────────┘  │
                 │                    │
                 │  ┌──────────────┐  │
                 │  │ 数据库       │  │
                 │  └──────────────┘  │
                 └────────────────────┘

11.3 SASL 认证

SASL(Simple Authentication and Security Layer)是 Memcached 支持的认证机制。

编译启用 SASL

# 需要从源码编译
sudo apt-get install -y libsasl2-dev

cd /tmp/memcached-1.6.31
./configure --enable-sasl
make -j$(nproc)
sudo make install

启动 SASL

# 创建 SASL 配置文件
cat > /etc/sasl2/memcached.conf <<EOF
mech_list: plain
log_level: 5
sasldb_path: /etc/sasl2/memcached-sasldb2
EOF

# 创建用户
sudo saslpasswd2 -a memcached -c admin -f /etc/sasl2/memcached-sasldb2
# 输入密码

# 启动 Memcached(启用 SASL)
memcached -S -m 128 -p 11211

使用 SASL 认证

# 使用 sasl 手动认证(二进制协议)
# 需要编写客户端程序
import bmemcached

# 使用带 SASL 认证的客户端
mc = bmemcached.Client(
    ['localhost:11211'],
    username='admin',
    password='secret_password'
)

mc.set('key', 'value')
print(mc.get('key'))  # value
<?php
$mc = new Memcached();
$mc->setSaslAuthData('admin', 'secret_password');
$mc->addServer('localhost', 11211);
$mc->set('key', 'value');
echo $mc->get('key');

SASL 的局限性

局限说明
性能开销每次连接需要认证握手
只支持二进制协议文本协议不支持 SASL
无 ACL只有认证,没有授权(所有人看到所有数据)
密码管理需要 saslpasswd2 工具管理

11.4 TLS 加密

Memcached 1.6.3+ 支持 TLS 传输加密。

编译启用 TLS

sudo apt-get install -y libssl-dev

cd /tmp/memcached-1.6.31
./configure --enable-tls
make -j$(nproc)
sudo make install

配置 TLS

# 生成证书(测试用)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
    -days 365 -nodes -subj "/CN=memcached"

# 启动 TLS
memcached \
    --enable-tls \
    --tls-cert cert.pem \
    --tls-key key.pem \
    --tls-protl 1.2 \
    -m 128 \
    -p 11212

# 带客户端证书验证(双向 TLS)
memcached \
    --enable-tls \
    --tls-cert cert.pem \
    --tls-key key.pem \
    --tls-ca-cert ca.pem \
    --tls-verify-mode 3 \
    -m 128
TLS 参数说明
--enable-tls启用 TLS
--tls-cert服务端证书
--tls-key服务端私钥
--tls-ca-certCA 证书(用于验证客户端)
--tls-verify-mode验证模式(1=服务端验证客户端, 2=客户端验证服务端, 3=双向)
--tls-protl最低 TLS 版本(1.2 推荐)
--tls-ciphers允许的加密套件
--shutdown-queryTLS 关闭行为

11.5 访问控制策略

应用层代理

使用代理层实现细粒度访问控制:

Client → Proxy (认证 + 路由 + 过滤) → Memcached

推荐代理:
- mc-router
- mcrouter (Facebook)
- twemproxy (Twitter)
- Codis

mc-router 示例

# 安装 mc-router
docker pull grumpycoders/mc-router:latest

# 配置路由规则
cat > routes.json <<EOF
{
    "routes": {
        "user:*": "mc-user:11211",
        "session:*": "mc-session:11211",
        "*": "mc-default:11211"
    }
}
EOF

# 启动 mc-router
docker run -d --name mc-router \
    -p 11211:11211 \
    -v $(pwd)/routes.json:/config/routes.json \
    grumpycoders/mc-router:latest \
    --config /config/routes.json

应用层 Key 前缀隔离

class IsolatedMemcachedClient:
    """带命名空间隔离的客户端"""

    def __init__(self, mc, namespace):
        self.mc = mc
        self.namespace = namespace

    def _key(self, key):
        return f"{self.namespace}:{key}"

    def get(self, key):
        return self.mc.get(self._key(key))

    def set(self, key, value, ttl=0):
        return self.mc.set(self._key(key), value, time=ttl)

    def delete(self, key):
        return self.mc.delete(self._key(key))

# 使用
user_mc = IsolatedMemcachedClient(mc, "app1:user")
session_mc = IsolatedMemcachedClient(mc, "app1:session")

user_mc.set("1001", data)      # 实际 Key: app1:user:1001
session_mc.set("abc", session) # 实际 Key: app1:session:abc

11.6 安全检查清单

部署前安全检查

#!/bin/bash
# Memcached 安全检查脚本

echo "=== Memcached 安全检查 ==="

# 1. 检查监听地址
LISTEN=$(echo "stats settings" | nc localhost 11211 | grep interface)
echo "监听地址: $LISTEN"
if echo "$LISTEN" | grep -q "0.0.0.0"; then
    echo "⚠️  警告: 监听所有接口,建议限制为内网 IP"
fi

# 2. 检查 UDP 端口
UDP_PORT=$(echo "stats settings" | nc localhost 11211 | grep udpport)
echo "UDP 端口: $UDP_PORT"
if [ "$UDP_PORT" != "0" ] && [ -n "$UDP_PORT" ]; then
    echo "⚠️  警告: UDP 端口已开启,可能导致 DDoS 放大攻击"
fi

# 3. 检查最大连接数
MAX_CONN=$(echo "stats settings" | nc localhost 11211 | grep maxconns)
echo "最大连接数: $MAX_CONN"

# 4. 检查 SASL
echo "stats settings" | nc localhost 11211 | grep sasl
echo "SASL 认证: $(echo "stats settings" | nc localhost 11211 | grep sasl)"

# 5. 检查 TLS
echo "stats settings" | nc localhost 11211 | grep tls

# 6. 检查外部连接
echo "当前外部连接:"
ss -tn | grep :11211 | grep -v 127.0.0.1 | wc -l

echo "=== 检查完成 ==="

扩展阅读

小结

要点内容
第一要务绑定内网地址 -l 10.x.x.x,禁用 UDP -U 0
防火墙只允许应用服务器 IP 访问 11211 端口
SASL启用认证(需二进制协议),适合内网多租户
TLS1.6.3+ 支持传输加密,适合跨机房通信
代理层mc-router / mcrouter 实现路由和访问控制