引言
在当今数字化飞速发展的时代,网络已然成为社会运转的神经中枢,Web 应用更是如繁星般遍布各个领域。然而,繁荣背后,网络安全威胁如影随形,HTTP 代理与 CDN 作为 Web 架构中的关键组件,虽为提升网络性能与安全立下汗马功劳,却也深陷安全困境。吴翰清于《白帽子讲 Web 安全》中,对这一领域抽丝剥茧,深入剖析,为我们揭开了 HTTP 代理与 CDN 安全的神秘面纱。接下来,让我们一同梳理其中的关键知识点,借助代码示例,探寻守护网络安全的有效策略。
一、HTTP 代理类型
正向代理
正向代理由客户端主动指定代理服务器,客户端向代理服务器发起请求并明确目标网站,随后代理服务器代替客户端去访问目标网站。从目标网站的视角来看,它无法得知真实访问者的信息,所有请求皆源于代理服务器,客户端的身份得以隐藏。在安全管控严格的企业环境中,正向代理大有用武之地。企业可借助正向代理为员工访问外部网站提供安全防护,例如在代理服务器上部署恶意域名拦截机制,当员工尝试访问恶意域名时,代理服务器立即阻断请求,避免员工陷入钓鱼网站或恶意软件传播陷阱。同时,还能对员工下载的文件进行病毒扫描,确保企业网络安全。
import requests
# 配置代理服务器地址和端口
proxies = {
'http': 'http://your_proxy_server:port',
'https': 'https://your_proxy_server:port'
}
try:
# 发送请求,通过代理访问目标网站
response = requests.get('http://example.com', proxies=proxies)
print(response.text)
except requests.exceptions.RequestException as e:
print(f"请求出错: {e}")
为防止正向代理服务器被滥用,可设置认证机制。比如使用Flask框架搭建一个带基本认证的正向代理服务器(简化示例,实际应用需更完善的认证逻辑):
from flask import Flask, request, redirect, Response
from requests.auth import HTTPBasicAuth
import requests
app = Flask(__name__)
@app.route('/proxy', methods=['GET', 'POST'])
def proxy():
auth = request.authorization
if not auth or not check_auth(auth.username, auth.password):
# 认证失败返回401状态码
return Response('认证失败', 401, {'WWW-Authenticate': 'Basic realm="Login Required"'})
target_url = request.args.get('url')
if not target_url:
return '未指定目标URL', 400
try:
response = requests.request(
method=request.method,
url=target_url,
headers=request.headers,
data=request.get_data(),
cookies=request.cookies,
allow_redirects=False
)
headers = [(k, v) for k, v in response.headers.items() if k != 'Transfer-Encoding']
new_response = redirect(response.url, code=response.status_code)
for header in headers:
new_response.headers[header[0]] = header[1]
return new_response
except requests.exceptions.RequestException as e:
return f"代理请求出错: {e}", 500
def check_auth(username, password):
# 简单示例,实际需从数据库等存储校验用户名和密码
return username == 'authorized_user' and password == 'authorized_password'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
然而,网络中存在一些匿名正向代理,它们可能被攻击者利用,隐藏攻击者的真实 IP 地址,进而实施恶意行为,如发起 DDoS 攻击、进行网络爬虫窃取数据等,给网络安全带来隐患。
反向代理
反向代理站在服务端的立场,负责响应 HTTP 请求,同时巧妙地隐藏了真实 Web 服务器的信息,常部署于企业内部网络。CDN(内容分发网络)和云 WAF(Web 应用防火墙)本质上可视为反向代理的具体应用。反向代理具备多种实用功能。在负载均衡方面,以 Nginx 为例,可通过如下配置实现:
http {
upstream backend_servers {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
server {
listen 80;
location / {
proxy_pass http://backend_servers;
}
}
}
上述配置中,upstream定义了后端服务器集群,server块中的proxy_pass将客户端请求转发到后端服务器,实现负载均衡,避免单个服务器负载过重。反向代理还可实现 SSL 卸载功能,将 SSL 加密和解密工作从后端服务器转移到自身,减轻后端服务器压力,提升数据传输效率。它还能充当 WAF,对 HTTP 请求进行安全检测,阻挡常见的 Web 攻击,如 SQL 注入、XSS 攻击等。此外,反向代理可缓存静态内容,加快页面加载速度,改善用户体验。
但反向代理并非无懈可击,不同服务器对路径标准化处理方式的差异,可能导致目录穿越漏洞。例如,在使用 Node.js 的http-proxy-middleware库搭建反向代理时,若对路径处理不当:
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/proxy', createProxyMiddleware({
target: 'http://backend_server',
changeOrigin: true,
// 这里未对路径进行严格校验,可能存在目录穿越风险
pathRewrite: {
'^/proxy': ''
}
}));
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
攻击者可能利用此漏洞,通过构造特殊请求路径,如添加 “../” 等字符,突破访问限制,访问服务器敏感文件或目录。
二、获取真实 IP 地址
当网络请求经过代理服务器后,Web 服务器获取到的是代理服务器的 IP,这给依赖客户端 IP 的安全功能带来挑战。为解决这一问题,HTTP 头 X - Forwarded - For 发挥作用。代理服务器在转发请求时,会将客户端的源 IP 追加到 X - Forwarded - For 头中,Web 服务器通过解析该头信息,即可获取客户端真实 IP。在 Node.js 的 Express 框架中获取 X - Forwarded - For 头中的真实 IP 代码如下:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
const realIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
res.send(`客户端真实IP: ${realIP}`);
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Forwarded 头是 X - Forwarded - For 的标准化版本,功能更完善。此外,PROXY Protocol 协议能标识源和目的 IP 地址及端口,且支持多种协议,在复杂网络环境中可提供更全面网络连接信息,助力网络管理员追踪和管理网络流量。
三、安全问题及攻击类型
1.缓存投毒
网站常借助反向代理服务器缓存静态资源以提升访问速度,但这一机制易被攻击者利用,引发缓存投毒问题。攻击者精心构造恶意请求,使缓存服务器缓存恶意内容,当其他用户请求相同资源时,缓存服务器直接返回恶意内容,XSS 攻击是常见手段。假设使用 Python 的Flask - Caching库搭建缓存服务器,若未严格校验请求,可能遭受缓存投毒攻击:
from flask import Flask, request
from flask_caching import Cache
app = Flask(__name__)
cache = Cache(app, config={'CACHE_TYPE':'simple'})
@app.route('/static_resource')
def get_static_resource():
resource_url = request.args.get('url')
if not resource_url:
return '未指定资源URL', 400
if cache.get(resource_url):
return cache.get(resource_url)
else:
# 这里假设从外部获取资源,实际可能从文件系统或其他存储获取
response = requests.get(resource_url)
if response.status_code == 200:
cache.set(resource_url, response.content)
return response.content
else:
return '获取资源失败', 500
为防范缓存投毒,需加固缓存服务器,及时更新软件版本,修复已知漏洞,设置严格访问权限。同时,严格校验 Web 应用中易被利用的 HTTP 头,如 “Cache - Control”“Expires” 等,确保其值合理,防止缓存服务器错误缓存恶意内容。
2.请求夹带攻击
HTTP/1.1 协议支持管线化,允许客户端在未收到前一请求响应时发送下一个请求,提高网络传输效率,但也为请求夹带攻击创造条件。该攻击通常发生在 HTTP 反向代理场景,当前后端对 HTTP 请求边界解析不一致时,攻击者有机可乘。HTTP 协议中标识请求长度的 Content - Length 和 Transfer - Encoding 同时使用会产生冲突,不同服务器对二者支持情况不同,衍生出 CL - TE、TE - TE 等类型夹带攻击。例如,使用 Python 的http.client库构造一个可能引发 CL - TE 攻击的请求示例(仅演示攻击原理,实际攻击更复杂):
import http.client
conn = http.client.HTTPConnection('example.com')
headers = {
'Content - Length': '10',
'Transfer - Encoding': 'chunked',
'Content - Type': 'application/x-www-form-urlencoded'
}
body = 'normal_data&malicious_data'
conn.request('POST', '/', body, headers)
response = conn.getresponse()
print(response.read())
为防御请求夹带攻击,服务器可采取措施,如拒绝同时包含 Transfer - Encoding 和 Content - Length 字段的请求,在 Node.js 的 Express 框架中,可通过中间件实现:
const express = require('express');
const app = express();
app.use((req, res, next) => {
if (req.headers['transfer - encoding'] && req.headers['content - length']) {
return res.status(400).send('不允许同时包含Transfer - Encoding和Content - Length字段');
}
// 这里还可添加更多HTTP头校验逻辑
next();
});
app.get('/', (req, res) => {
res.send('正常响应');
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
同时,拒绝畸形 HTTP 头的请求,升级服务器软件版本,修复请求边界解析漏洞,提升服务器处理请求能力。
3.RangeAMP 攻击
RangeAMP 攻击利用 CDN 特性,通过在 HTTP 请求中指定 Range 头实现放大攻击。不同 CDN 对 Range 请求策略不同,主要有懒惰型、删除型、扩展型。攻击者抓住部分 CDN 策略漏洞,以小 Range 请求触发大流量,形成小字节范围(SBR)攻击。在多级 CDN 场景中,攻击者还可能发起重叠字节范围(OBR)攻击。使用 Python 的requests库构造 Range 请求示例如下:
import requests
headers = {
'Range': 'bytes=0 - 10'
}
response = requests.get('http://cdn.example.com/large_file', headers=headers)
print(response.text)
4.域前置(Domain Fronting)
在 TLS 协议中,SNI 扩展用于在握手阶段告知服务器要访问的域名。CDN 托管多个域名时,攻击者利用此特性构造请求,表面访问正规网站,实际访问恶意网站,即域前置攻击。此攻击方式极为隐蔽,难以检测和防御。尽管部分厂商已禁止相关行为,但在国内复杂网络环境下,域前置攻击仍有存在空间。随着 TLS 1.3 加密 SNI,网络攻击检测面临更大挑战,安全检测设备难以直接解析加密后的 SNI 信息,识别请求真实目标域名难度加大,给网络安全防护带来新难题。
小结
现代应用架构复杂,HTTP 代理广泛应用于提升安全和访问质量。但开发者在利用代理时,必须高度关注其自身安全性。上述总结的安全问题仅是常见部分,随着 HTTP 协议持续发展演进,新的安全问题将不断涌现。网络安全从业者需持续学习研究,加强对代理服务器的安全配置与管理,严格校验请求和响应信息,及时更新软件版本修复漏洞,以应对不断变化的网络安全挑战,保障 Web 应用安全稳定运行。
喜欢的就点点赞和评论关注呗