当你使用Telegram机器人Webhook模式时,Telegram官方服务器会把用户消息以HTTPS POST请求推送到你的服务器。如果这个接口完全暴露在公网上,任何人都可以伪造请求向你的服务器发送数据,不仅会消耗服务器资源,还可能造成数据泄露甚至被恶意利用。因此,为Webhook服务器配置IP白名单,仅允许Telegram官方IP段访问,是每一位Bot开发者必须掌握的基础安全技能。
为什么需要为Webhook服务器配置IP白名单?
Webhook本质上是一个公开的URL,攻击者只要发现这个地址,就可以不断发送垃圾请求,导致服务器负载飙升,甚至触发Telegram API的限流策略。更严重的是,如果Bot处理逻辑存在漏洞,伪造请求可能被当作真实指令执行,造成不可挽回的损失。配置IP白名单后,非Telegram来源的请求会在到达应用之前被拒绝,从源头上杜绝了威胁。
另外,Telegram官方建议开发者对Webhook端点进行IP过滤,这是官方认证推荐的安全实践。通过白名单,你还可以结合反向代理、CDN等基础设施,进一步加固防线。
认识Telegram官方IP段
Telegram官方维护了一份IP段列表,包含所有用于发送Webhook请求的服务器地址。你可以通过以下地址获取最新数据:
https://core.telegram.org/resources/cidr.txt 该文件包含IPv4和IPv6的CIDR格式列表。由于Telegram的IP段会随着基础设施调整而变化,建议设置定时任务(每日或每周)自动更新,避免因IP变动导致Webhook失效。
下面是一个获取并格式化IP段的示例脚本(Linux环境):
curl -s https://core.telegram.org/resources/cidr.txt -o telegram_cidr.txt 执行后,你可以查看文件内容,其中的每一行就是一个CIDR地址段,例如 91.108.4.0/22 或 2001:b28::/32 等。
方法一:使用iptables配置IP白名单
对于大多数Linux服务器,iptables是最直接有效的防火墙工具。假设你的Webhook监听在443端口,我们可以通过以下命令只允许Telegram IP段访问:
# 先清除已有规则(请谨慎操作)
iptables -F
# 允许Telegram IP段访问443端口
while read cidr; do
iptables -A INPUT -p tcp --dport 443 -s $cidr -j ACCEPT
done < telegram_cidr.txt
# 拒绝其他所有对443端口的访问
iptables -A INPUT -p tcp --dport 443 -j DROP
# 保存规则(Debian/Ubuntu)
apt install iptables-persistent -y
netfilter-persistent save 注意:如果你使用IPv6,需要执行同样的操作,但使用ip6tables命令,并确保读取文件中的IPv6段。
另外,如果你还运行了其他服务(如SSH),切勿清除所有INPUT规则,以免把自己锁在门外。建议将白名单规则追加到现有规则集,而不是直接清空。
方法二:使用UFW(Uncomplicated Firewall)配置
UFW是Ubuntu上常用的iptables前端,配置更加简单直观。使用UFW,你无需处理复杂的字符串操作,直接逐条添加规则即可:
# 允许Telegram IP段访问443端口
while read cidr; do
ufw allow from $cidr to any port 443 proto tcp
done < telegram_cidr.txt
# 显式拒绝其他请求(可选,但建议将默认行为设置为拒绝)
ufw deny 443/tcp
# 启用防火墙(如果尚未启用)
ufw enable
# 查看状态
ufw status 如需支持IPv6,请确保在/etc/default/ufw中设置了IPV6=yes,然后重复上述命令(UFW会自动应用IPv6规则)。
方法三:在Nginx层通过allow/deny限制访问
如果你的Webhook服务运行在Nginx反向代理之后,更优雅的方案是在Nginx中对特定location做访问控制。这样无需修改系统防火墙,尤其适合一台服务器上运行多个服务的情况。
编辑Nginx配置文件(如/etc/nginx/sites-available/bot.conf),在server或location块中添加:
location /webhook {
# 允许Telegram IP段
allow 91.108.4.0/22;
allow 91.108.56.0/22;
# 其他地址全部拒绝
deny all;
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
} 你需要将telegram_cidr.txt中的地址段逐一复制到配置中,或者使用include文件:
# 在nginx配置目录下创建telegram_ips.conf
# 内容每行:allow 192.168.0.0/16;
location /webhook {
include /etc/nginx/telegram_ips.conf;
deny all;
...
} 这样的好处是,更新IP时只需修改conf文件并reload Nginx,无需重启服务。
方法四:在应用代码中校验源IP(以Python为例)
即使有防火墙和Nginx过滤,在应用层再增加一道校验更为稳妥,尤其当你的服务可能被其他途径访问时(比如内网穿透或负载均衡器)。以常用的Flask框架为例:
import ipaddress
from flask import Flask, request, jsonify
app = Flask(__name__)
# 从文件中读取Telegram IP段
TELEGRAM_NETS = [ipaddress.ip_network(line.strip()) for line in open('telegram_cidr.txt')]
@app.route('/webhook', methods=['POST'])
def webhook():
client_ip = request.remote_addr
if not any(ipaddress.ip_address(client_ip) in network for network in TELEGRAM_NETS):
return jsonify({'error': 'Forbidden'}), 403
# 处理你的业务逻辑
return jsonify({'ok': True})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8081) 如果服务器前面有Nginx或负载均衡,你需要从X-Forwarded-For头获取真实IP,并确保代理层正确传递该头,同时只信任来自代理的请求。
测试与验证
完成配置后,执行以下测试确保一切正常:
- 模拟非Telegram IP访问:使用
curl从你的本地电脑或其他服务器发送POST请求,应返回403或连接超时,而不是业务响应。 - 真实Bot消息测试:向你的机器人发送一条消息,观察服务器日志,确认能收到更新并正确处理。
- 检查防火墙日志:通过
tail -f /var/log/syslog或journalctl -u查看是否有大量被拒绝的骚扰请求。
如果真实消息无法到达,首先检查是否遗漏了某些IP段,或者IP列表更新不及时。可以通过whois或在线工具查发起请求的源IP,然后与CIDR文件对照。
常见问题与注意事项
1. Telegram的IP段会变化吗?
会。Telegram的数据中心扩缩容会带来IP变更。建议每天定时下载最新CIDR文件,并在防火墙或Nginx中自动重载。
2. 配置白名单后,为什么收不到Telegram的Webhook请求?
常见原因包括:未覆盖全部IP段、防火墙规则未生效、Nginx配置未reload、或者Telegram临时使用了新IP段。可以暂时放宽到整段测试,或者查看Telegram Bot API返回的last_error_message。
3. 是否必须配置IP白名单?
并非强制,但官方强烈建议。尤其在生产环境,白名单是防止恶意请求的第一道防线。
4. 我使用了Cloudflare等CDN,应该怎么配置?
如果CDN在Nginx前面,你需要在Nginx中信任CDN的IP,然后再对Telegram IP做限制,或者直接在CDN层配置访问规则。更简单的方案是在应用层校验CF-Connecting-IP头(Cloudflare特有)。
总结
为Telegram机器人Webhook服务器配置IP白名单是保障安全的关键步骤。通过本文介绍的iptables、UFW、Nginx和应用层四种方法,你可以根据服务器架构选择最合适的方案。记住,安全永远不是一成不变的,定期更新IP列表、监控异常访问,才能让你的机器人长期稳定运行。
无论你是个人开发者还是企业用户,从今天开始为你的Webhook加上白名单,为你的Bot代码穿上“防弹衣”。