《白帽子讲 Web 安全》之代理和 CDN 安全

引言

在当今数字化飞速发展的时代,网络已然成为社会运转的神经中枢,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 应用安全稳定运行。

喜欢的就点点赞和评论关注呗

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值