腾讯云七层CLB重定向完全解析:配置、安全、实践优化及常见错误

2024-06-25 10:56:36 浏览数 (1)

一、前言

随着云计算技术的飞速发展,负载均衡作为云计算服务的重要组成部分,已经成为企业和个人用户实现高可用、高性能、高扩展性Web应用的关键技术。腾讯云七层负载均衡(CLB)作为腾讯云提供的核心负载均衡服务之一,以其灵活、高效的特性,受到了广大用户的青睐。

在Web应用的实际部署和运维过程中,我们经常会遇到各种重定向需求,如HTTP到HTTPS的安全升级、不同路径的资源分发以及基于用户状态的个性化服务提供等。为了满足这些需求,我们需要对CLB的重定向机制有深入的了解,并掌握相应的配置技巧。同时,随着网络安全意识的不断提高,我们还需要关注CLB可能带来的安全隐患,并采取有效的措施加以防范。

本文旨在全面介绍腾讯云七层CLB的重定向功能及其在实际应用中的各种场景。我们将从基础知识入手,逐步深入到高级配置和优化策略,力求为读者提供一个系统、全面的CLB重定向指南。此外,我们还将结合具体的案例和错误示例,分析CLB在实际应用中可能遇到的问题及解决方法,帮助读者更好地理解和应用CLB的重定向功能。

二、重定向状态码

详情可参照HTTP / 1.1标准(RFC 7231)。

状态码

含义

301

永久重定向。当一个资源永久性地移动到了新的URL时,服务器会返回301状态码。这意味着客户端应当更新其书签和引用,因为将来再次访问旧URL时将不再有效。搜索引擎也会更新其索引,将旧URL替换为新URL,有助于SEO优化。

302

临时重定向,当一个资源暂时移动到了新的URL时,服务器会返回302状态码。此时客户端在未来某个时刻再次访问旧URL时,可能会找到原始资源。因此,客户端不需要更新书签和引用,但搜索引擎可能不会立即更新其索引,这可能对SEO产生一定影响。

307

307状态码明确指出客户端应当使用相同的请求方法(如GET、POST等)重定向到新URL,而不是像301/302状态码那样默认将请求方法更改为GET。这使得307状态码在处理POST请求等复杂请求时更加明确和安全。

注意,301、302跳转,跳转后的协议为GET,无法保留跳转前的协议,比如客户端发的是HTTP POST http://rokasyangdemo.com,LB做了302跳转后,请求变为了HTTP GET http://rokasyangdemo.com/demo/,如果需要保留跳转前的访问协议,应该使用307跳转。

三、自动重定向

简单理解为HTTPS的强制跳转。系统自动为已存在的HTTPS:443监听器创建 HTTP 监听器进行转发,默认使用 80 端口。创建成功后可以通过HTTP:80地址自动跳转为HTTPS:443地址进行访问。

1.前提和限制

前提

  • 已经创建了80监听器和443监听器,且80对应HTTP,443对应HTTPS,不支持其它指定端口。

限制

重定向配置包含协议/端口、域名和路径的配置,为避免回环请注意以下限制信息:

  • 原访问的路径和重定向的访问路径一致,则不允许配置。
  • 原访问的路径若已经配置了重定向策略(包含原访问路径和重定向访问路径),则不允许再次配置。
  • 如果重定向访问路径配置的是其他重定向策略的原访问路径,则不允许配置。

同时,要跳转的80监听器,里面不需要绑定任何RS,因为实际不提供服务,在443监听器绑定RS即可,80监听器的HTTP请求到达LB七层网关STGW后,将会跳转到443监听器,由443监听器对应路径下的RS提供服务:

2.示例及同等效果的nginx配置

控制台配置:

配置后可以看到,自动重定向会将客户端携带的完整路径,传递给重定向后的HTTPS:

将HTTP强制跳转到HTTPS,类似于nginx的return:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;

    return 301 https://$host$request_uri;
}

或者rewrite重写:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;

    location / {
        rewrite ^(.*)$ https://$host$1 permanent;
    }
}

四、手动重定向

这类重定向比较灵活,可以手动指定从哪个监听器的URL跳转到哪个监听器的URL,也支持在同一个监听器的不同URL规则之间进行跳转。

比如,从80监听器的/,跳转到80监听器的/demo路径:

1.保留URL和不保留URL

1)保留URL

还是以上面的自动重定向配置为例,当勾选保留URL时,将会把客户端携带的URL路径,附加到重定向后的URL后面:

这个路径看起来很怪,理论上访问/keepurl应该跳转为/demo/keepurl对不对?因为80监听器的写的是/demo路径而非/demo/路径。如果我们将80监听器的/demo修改为/demo/

重定向规则也对应跳转到/demo/

此时重定向保留URL,则符合我们预期:

类似nginx配置:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;

    location / {
        rewrite ^(.*)$ http://domain.com/demo$1 redirect;
        # 或者 return 302 http://domian.com/demo$request_uri;
    }
}

2)不保留URL

还是以80监听器的/跳转到80监听器/demo监听器为例:

不保留URL时,则正常跳转到/demo路径,不携带跳转前的URL:

对应nginx配置则可以是:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;

    location / {
        rewrite ^(.*)$ http://domain.com/demo redirect;
        # 或者 return 302 http://domian.com/demo
    }
}

2.不同监听器不同域名之间的跳转

比如从80监听器的domain.com跳转到443监听器的newdomain.com

这里将3个URL(//demo/test)都重定向到了新域名,保留或不保留URL不再做重复赘述,参照上面的案例。这里以不保留URL为例:

类比同等效果的nginx配置:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;
    location / {
        return 301 https://newdomain.com/;
    }

    location /demo {
        return 301 https://newdomain.com/demo;
    }

    location /test {
        return 301 https://newdomain.com/test;
    }
}

3.不同监听器的同一域名跳转

比如从80监听器的domain.com跳转到443监听器的domain.com,以保留URL为例:

是不是和前面的自动重定向类似?有相同之处但也有不同之处,相同之处是它们都能从http重定向到https,但手动重定向可选不保留URL的能力,自动重定向默认都会保留URL,手动重定向的能力覆盖自动重定向,或者说自动重定向的效果属于手动重定向的子集

这段重定向配置类比等同效果的nginx配置:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;

    return 302 https://$host$request_uri;
}

或者:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;

    location / {
        rewrite ^(.*)$ https://$host$1 redirect;
    }
}

4.同一监听器的不同域名跳转

比如将443监听器的domain.com重定向给443监听器的newdomain.com,并且保留URL:

类比同等效果的nginx配置:

代码语言:nginx复制
server {
    listen 443 ssl;
    server_name domain.com;
    location / {
                return 302 https://newdomain.com$request_uri;
        }
}

5.同一监听器的同一域名但不同URL的跳转

譬如将80监听器的domain.com的路径/,跳转给/demo/,并且保留URL:

同等效果的nginx配置:

代码语言:nginx复制
server {
    listen 80;
    server_name domain.com;
    location / {
                return 302 https://$host/demo$request_uri;
        }
}

五、默认域名、根URL带来的安全问题及解决方案

1.默认域名带来的安全问题

七层CLB有默认域名的概念,当客户端携带的HTTP头部里的HOST字段不匹配监听器下的任何域名时,则最终会匹配转发给域名。

比如80监听器,默认域名为domain.com

此时当我在客户端执行一条curl请求,请求的是LB VIP,HOST默认用的是VIP,不涉及任何域名:

在RS抓包看,STGW转发给RS时,携带的HOST也是VIP:

STGW将请求成功透传给了默认域名domain.com,根路径下的RS。这会带来一些安全问题,如果面向的是所有外网客户端,外网客户端只需要发起七层HTTP探测,LB收到请求后就会转发给默认域名下的RS,RS会收到并处理请求,也就是说来者不拒,在一些安全要求较高的业务场景,这是我们不想看到的。

2.解决方案

  • 要么在RS业务层拒绝这类非法请求,只允许通过特定域名访问进来,其它域名不允许;
  • 要么在LB就代答这类非法请求,这类请求不要转发给RS处理,占用不必要的RS性能。

1)RS业务层

首先看第一个方案,在RS拒绝这类非法请求,只允许携带特定域名HOST访问,RS以nginx web业务举例:

代码语言:nginx复制
server {
    listen 80 default_server;
    server_name "";

    return 444;
}
server {
    listen 80;
    server_name domain.com;
    ...略
}

第一个server模块,我们监听80端口,server_name为空,第二个server模块,指定我们的正常业务域名。这两套组合拳下来,当客户端携带的HOST非domain.com时,服务端则无响应并关闭连接。

在RS上测试:

第一个红圈应为没有携带domain.com作为HOST,收到了空响应,第二个红圈为正常响应。

此时在客户端测试到LB:

客户端收到了STGW返回了502状态码,为什么不是"Empty reply from server"?因为STGW将客户端的GET请求转发给RS后,RS没有返回正常数据,STGW向客户端代答了502状态码,在RS的抓包现象如下:

RS收到客户端的GET请求,HOST为LB VIP,nginx判定HOST非domain.com,进而匹配server_name为空的情况,因此不响应任何数据,而是FIN,ACK申请挥手。

让nginx返回403也可以:

代码语言:nginx复制
server {
    listen 80 default_server;
    server_name "";

    return 403;
}
server {
    listen 80;
    server_name domain.com;
    ...略
}

此时客户端收到的是RS 403状态码,而非STGW的502,但没必要浪费不必要的业务流量,能不返回就不返回,能让LB阻断就让LB阻断。

2)七层CLB层

因此就有了第二个方案:在LB就代答这类非法请求,这类请求不要转发给RS处理,占用不必要的RS性能。

在80监听器下新建一个域名规则,域名随便写,可以写LB的IP或者任意IP或域名,只要不是我们的业务域名即可,并且下面不要绑定任何RS后端服务:

业务域名我们设置为newdomain.com,并且非默认。

此时我们通过VIP的方式,访问LB 80监听器:

LB收到请求后匹配默认域名,但域名下没有任何RS服务,STGW代答了200状态码,返回内容长度为0。

当HOST指定为newdomain.com时,才会匹配我们的业务域名,RS正常响应数据,其它非法域名均由STGW代答200状态码,不返回任何数据:

3.根URL带来的安全问题

想象一种场景,客户端在使用诸如gobuster之类的扫描器,想扫描服务端存在的文件或资源,此时LB监听器如果有/路径,且绑定了RS业务,那么客户端的每一次扫描,LB都会转发给RS,RS最终返回了一些敏感文件数据。

此时我们要做的就是避免使用/路径,用层级目录或者长目录作为替代,防止每一次恶意扫描,RS都要响应数据,浪费不必要的业务资源,并且带来极大的数据安全隐患。

4.解决方案

1)根路径不绑定RS

没有精确匹配到其它路径时,作为兜底,至少会匹配根路径,而当根路径不绑定RS,STGW会代答200:

2)删除根路径

当根路径不存在时,客户端请求到服务端的路径,如果不匹配任何一个,则STGW会代答404:

STGW代答200OK和代答404消耗的字节数:

可以清晰看到,404的消耗会比200 OK占用大,并且扫描软件最终都是判断200 OK状态码为正常,因此200 OK代答行为甚至可以混淆客户端的恶意扫描对于结果的判断,因此更建议第一种方案。

六、一些错误示例

1.重定向死循环/重定向次数过多

很常见的错误之一,重定向死循环,浏览器最终会报重定向次数过多。

来看看为什么会报错,首先我们做了一层HTTP跳转HTTPS的自动重定向:

访问HTTP,最终跳转到443监听器的rokasyangtest.com,这一层没什么问题:

443监听器后面绑定的RS为HTTP服务,端口为80。

紧接着,443监听器下的/监听器后面绑定的RS服务对应服务端口,也做了一层重定向:

代码语言:nginx复制
server {
        listen 80;
        server_name rokasyangtest.com;

        rewrite ^(.*)$ https://$host$1 redirect;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
}

将http重定向到https,这就是问题所在。

整个重定向过程如下:

解决方案很简单,要么将LB绑定的RS服务,从HTTP 80修改为HTTPS 443,要么将取消RS的HTTP重定向。很显然,后者更合理,CLB --> RS这段没必要使用HTTPS,这一段已经是云上VPC内网了,client -> LB为HTTPS即可,LB-->RS再来一层HTTPS,会增加不必要的开销,整体访问耗时也会上升。

取消掉nginx的80监听器的跳转:

代码语言:nginx复制
server {
        listen 80;
        server_name rokasyangtest.com;

        #rewrite ^(.*)$ https://$host$1 redirect;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
}

访问https最终正常拿到业务响应。

2.协议不匹配的情况

1)前端协议使用错误

用HTTP协议访问HTTPS监听器

意料之中,STGW会返回400错误。

用HTTPS协议访问HTTP监听器

SSL协议错误或版本错误。

2)后端协议使用错误

后端协议用HTTPS,实际RS业务为HTTP,我们将后端协议修改为https,但是绑定的RS服务和端口依然是HTTP:

首先健康检查会转为异常:

在RS抓包可以发现,RS处理不了这类请求,返回400 Bad Request:

此时来看客户端收到了什么返回:

STGW代答的502状态码,但实际RS并没有产生,STGW没有拿到RS的正常返回数据,此情况下向客户端代答了502。

七、总结

到此为止,深入浅出讲完了七层CLB重定向的所有情况以及等同效果的Nginx配置,并且涵盖了默认域名、根URL带来的安全隐患和相应的解决方案,同时也分析了LB的一些错误示例,如重定向次数过多、协议不匹配等场景。

如果想进一步讨论CLB的性能优化和监控方面的内容。首先,为了提高CLB的性能,我们可以采取以下措施:

  • 优化后端服务:确保后端服务能够快速响应请求,减少CLB的等待时间。
  • 合理分配资源:根据业务需求和流量特点,合理分配CLB的计算和网络资源。
  • 使用长连接:LB到RS使用长连接,减少CLB与后端服务之间的连接建立和关闭次数,提升响应速率并减少连接开销。

其次,为了更好地监控CLB的运行状况,我们可以利用腾讯云提供的监控工具,如云监控、告警服务等。通过实时监控CLB的各项指标,如请求量、响应时间、错误率等,我们可以及时发现潜在问题并采取相应的处理措施。此外,设置合理的告警规则可以帮助我们在出现异常情况时第一时间得到通知,从而确保业务的稳定运行。

总之,腾讯云七层CLB作为一种高效、灵活的负载均衡解决方案,能够满足各种复杂场景下的需求。通过深入了解其重定向机制、安全隐患及优化策略等方面的内容,我们可以更好地运用CLB为业务发展提供有力支持。在未来的实践中,我们将继续关注CLB的发展动态,分享更多关于其应用和优化的实践经验。

0 人点赞