IPVS之安全防御

2023-12-19 10:08
文章标签 安全 防御 ipvs

本文主要是介绍IPVS之安全防御,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

初始化

IPVS在初始化时,使用内核delayed work机制启动一个处理任务。每1秒钟(DEFENSE_TIMER_PERIOD)执行一次。

/* Timer for checking the defense */
#define DEFENSE_TIMER_PERIOD    1*HZstatic int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
{atomic_set(&ipvs->dropentry, 0);ipvs->sysctl_amemthresh = 1024;/* Schedule defense work */INIT_DELAYED_WORK(&ipvs->defense_work, defense_work_handler);schedule_delayed_work(&ipvs->defense_work, DEFENSE_TIMER_PERIOD);

防御处理

static void defense_work_handler(struct work_struct *work)
{
struct netns_ipvs *ipvs =
container_of(work, struct netns_ipvs, defense_work.work);

update_defense_level(ipvs);
if (atomic_read(&ipvs->dropentry))ip_vs_random_dropentry(ipvs);
schedule_delayed_work(&ipvs->defense_work, DEFENSE_TIMER_PERIOD);

}

PROC控制文件

可用内存阈值amemthresh

PROC文件:/proc/sys/net/ipv4/vs/amemthresh 用于设置可用内存的阈值,默认值为1024,单位是页面。如果系统可用内存值低于此阈值,IPVS系统即认为已无内存可用,其将尝试释放部分自身所占用的内存空间。

$ cat /proc/sys/net/ipv4/vs/amemthresh
1024
表项丢弃策略

PROC文件:/proc/sys/net/ipv4/vs/drop_entry用于设置处于无可用内存时IPVS丢弃表项的策略。默认值为0,表明关闭表项丢弃策略。将此值设置为3,表示总是开启此丢弃策略。值1和2为动态模式,当值设置为1时,一旦检测到内存不足,将进行表项丢弃,并将此值更改为2;否则,内存充足,不进行丢弃处理。当此值设置为2时,一旦检测到内存不足,同样将进行表项丢弃操作,反之如果内存充足,停止丢弃操作,并将drop_entry的值设置为1。

由以上描述可知,对于PROC文件drop_entry设置为1,2的情况,在内存不足时,drop_entry的值为2,当内存充足时,其值为1。

$ cat /proc/sys/net/ipv4/vs/drop_entry 
0
报文丢弃策略

PROC文件:/proc/sys/net/ipv4/vs/drop_packet用于设置处于可用内存不足时IPVS的报文丢弃策略,默认值为0,表明关闭报文丢弃策略。drop_packet的作用于上一节drop_entry类似,值1和2也是动态模式,值3表示总是开启报文丢弃策略。

对于PROC文件drop_packet设置为1,2的情况,在内存不足时,drop_packet的值为2,当内存充足时,其值为1。

$ cat /proc/sys/net/ipv4/vs/drop_packet 
0

和报文丢包丢弃相关的一个PROC文件为:/proc/sys/net/ipv4/vs/am_droprate,其定义了在drop_packet值为3时,所使用的的丢包率,默认为10,即丢弃十分之一的报文。

$ cat /proc/sys/net/ipv4/vs/am_droprate
10

当drop_packet的值为1或者2时,丢包率由以下公式计算而来:

rate = amemthresh / (amemthresh - available_memory)
安全TCP策略

PROC文件:/proc/sys/net/ipv4/vs/secure_tcp用于设置TCP使用一个不同的状态变迁表,对于NAT转发模式而言,可将TCP的Established状态延迟到三次握手完成之后。默认值为零,表明关闭secure_tcp功能。secure_tcp值的设置与上两节的drop_entry和drop_packet意义类似。值1和2也是动态模式,值3表示总是开启安全TCP策略。

对于PROC文件secure_tcp设置为1,2的情况,在内存不足时,secure_tcp的值为2,当内存充足时,其值为1。

$ cat /proc/sys/net/ipv4/vs/secure_tcp 
0

更新防御等级

函数update_defense_level负责防御等级的更新处理,其由delayed work每隔1秒钟调度一次。

可用内存计算

首先使用si_meminfo获得系统的空闲内存页面数量freeram和缓存页面数量bufferram,两者之和作为系统当前可用内存值(以页面为单位),此值如果小于PROC系统文件amemthresh指定的值,即认为内存已经不足。amemthresh默认值为1024。

static void update_defense_level(struct netns_ipvs *ipvs)
{struct sysinfo i;static int old_secure_tcp = 0;int to_change = -1;/* we only count free and buffered memory (in pages) */si_meminfo(&i);availmem = i.freeram + i.bufferram;nomem = (availmem < ipvs->sysctl_amemthresh);
drop_entry处理

以下逻辑根据PROC系统文件drop_entry和nomem来计算IPVS的dropentry值,dropentry表示是否执行连接表项丢弃操作。

    switch (ipvs->sysctl_drop_entry) {case 0:atomic_set(&ipvs->dropentry, 0);break;case 1:if (nomem) {atomic_set(&ipvs->dropentry, 1);ipvs->sysctl_drop_entry = 2;} else {atomic_set(&ipvs->dropentry, 0);}break;case 2:if (nomem) {atomic_set(&ipvs->dropentry, 1);} else {atomic_set(&ipvs->dropentry, 0);ipvs->sysctl_drop_entry = 1;};break;case 3:atomic_set(&ipvs->dropentry, 1);break;}

如下函数todrop_entry负责判断是否丢弃待定的连接表项。首先如果连接建立还未超过60秒,将不进行删除操作,以便保证正常的连接处理。

static inline int todrop_entry(struct ip_vs_conn *cp)
{/* The drop rate array needs tuning for real environments. Called from timer bh only => no locking*/static const char todrop_rate[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8};static char todrop_counter[9] = {0};/* if the conn entry hasn't lasted for 60 seconds, don't drop it. This will leave enough time for normal connection to get through. */if (time_before(cp->timeout + jiffies, cp->timer.expires + 60*HZ))return 0;

如下示意图,

  createtime           expires||     timeout    |  60s | |----------------|------|||----------------||    timeout     |nowjiffies|    ||<60s|

如果此连接接收到的报文数量不在[0, 8]之间,包括0和8,不执行丢弃,即没有接收到报文的连接与接收到大于8个报文的连接,可能在正常的使用不执行丢弃。反之,接下来将处理接收报文数量在[0,8]直接的连接。

以todrop_rate数组的第9个元素值8为例,如果连接接收的报文数量等于8个,在静态数组todrop_counter的第9个元素首次赋值为8之后,要一致等到执行8次之后,todrop_counter[8]才会再次小于等于零,返回1执行一次丢弃连接操作。

即对于连接的接收报文数量,数组todrop_rate指定了依据报文数量而定的丢弃速率。报文数量越多,丢弃率越低。

    /* Don't drop the entry if its number of incoming packets is not located in [0, 8] */i = atomic_read(&cp->in_pkts);if (i > 8 || i < 0) return 0;if (!todrop_rate[i]) return 0;if (--todrop_counter[i] > 0) return 0;todrop_counter[i] = todrop_rate[i];return 1;
drop_packet处理

以下逻辑根据PROC系统文件drop_packet和nomem来计算IPVS的drop_rate丢弃速率值。drop_rate值为空表示不执行报文丢弃操作。丢弃率drop_rate值的计算参考以上PROC文件am_droprate的介绍。

    switch (ipvs->sysctl_drop_packet) {case 0:ipvs->drop_rate = 0;break;case 1:if (nomem) {ipvs->drop_rate = ipvs->drop_counter = ipvs->sysctl_amemthresh / (ipvs->sysctl_amemthresh-availmem);ipvs->sysctl_drop_packet = 2;} else {ipvs->drop_rate = 0;}break;case 2:if (nomem) {ipvs->drop_rate = ipvs->drop_counter= ipvs->sysctl_amemthresh / (ipvs->sysctl_amemthresh-availmem);} else {ipvs->drop_rate = 0;ipvs->sysctl_drop_packet = 1;}break;case 3:ipvs->drop_rate = ipvs->sysctl_am_droprate;break;}

报文丢弃的处理位于IPVS系统的各个协议的调度函数中,以UDP协议为例,其位于函数udp_conn_schedule中。如下的判断函数ip_vs_todrop。

static int udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,struct ip_vs_proto_data *pd, int *verdict, struct ip_vs_conn **cpp, struct ip_vs_iphdr *iph)
{if (svc) {if (ip_vs_todrop(ipvs)) {/* It seems that we are very loaded. We have to drop this packet :(*/*verdict = NF_DROP;return 0;

当drop_rate不为零时,每当drop_counter小于等于零时,丢弃当前的报文。

static inline int ip_vs_todrop(struct netns_ipvs *ipvs)
{if (!ipvs->drop_rate)return 0;if (--ipvs->drop_counter > 0)return 0;ipvs->drop_counter = ipvs->drop_rate;return 1;
secure_tcp处理

以下逻辑根据PROC系统文件secure_tcp和nomem来计算IPVS的to_change值,to_change表示是否更改TCP所使用的状态迁移表。

    switch (ipvs->sysctl_secure_tcp) {case 0:if (old_secure_tcp >= 2)to_change = 0;break;case 1:if (nomem) {if (old_secure_tcp < 2)to_change = 1;ipvs->sysctl_secure_tcp = 2;} else {if (old_secure_tcp >= 2)to_change = 0;}break;case 2:if (nomem) {if (old_secure_tcp < 2)to_change = 1;} else {if (old_secure_tcp >= 2)to_change = 0;ipvs->sysctl_secure_tcp = 1;}break;case 3:if (old_secure_tcp < 2)to_change = 1;break;}old_secure_tcp = ipvs->sysctl_secure_tcp;if (to_change >= 0)ip_vs_protocol_timeout_change(ipvs, ipvs->sysctl_secure_tcp > 1);

函数ip_vs_protocol_timeout_change负责具体执行TCP状态转移表的切换。目前只有TCP协议注册了timeout_change指针函数。

void ip_vs_protocol_timeout_change(struct netns_ipvs *ipvs, int flags)
{struct ip_vs_proto_data *pd;for (i = 0; i < IP_VS_PROTO_TAB_SIZE; i++) {for (pd = ipvs->proto_data_table[i]; pd; pd = pd->next) {if (pd->pp->timeout_change)pd->pp->timeout_change(pd, flags);

TCP协议的timeout_change指针函数如下:tcp_timeout_change。如果开启,将TCP状态转换表设置为tcp_states_dos;否则,使用tcp_states表。

static void tcp_timeout_change(struct ip_vs_proto_data *pd, int flags)
{int on = (flags & 1);       /* secure_tcp *//*** FIXME: change secure_tcp to independent sysctl var** or make it per-service or per-app because it is valid** for most if not for all of the applications. Something** like "capabilities" (flags) for each object.*/pd->tcp_state_table = (on ? tcp_states_dos : tcp_states);
}

连接表项丢弃处理

如在defense_work_handler函数中,如果update_defense_level函数将dropentry设置为非零值,将使用ip_vs_random_dropentry函数随机丢弃一定数量的连接表项。

static void defense_work_handler(struct work_struct *work)
{struct netns_ipvs *ipvs =container_of(work, struct netns_ipvs, defense_work.work);update_defense_level(ipvs);if (atomic_read(&ipvs->dropentry))ip_vs_random_dropentry(ipvs);

如下,在函数ip_vs_random_dropentry中,其随机选取1/32数量(ip_vs_conn_tab_size>>5)的哈希链表,随后遍历每个选定链表,获取候选丢弃表项。对于模板连接,如果存在子连接,或者其所属的虚拟服务未设置了OPS(One-Packet Scheduling),由于还在使用,不能丢弃此模板连接。否则,尝试进行丢弃操作。

/* Called from keventd and must protect itself from softirqs */
void ip_vs_random_dropentry(struct netns_ipvs *ipvs)
{struct ip_vs_conn *cp, *cp_c; /* Randomly scan 1/32 of the whole table every second*/for (idx = 0; idx < (ip_vs_conn_tab_size>>5); idx++) {unsigned int hash = prandom_u32() & ip_vs_conn_tab_mask;hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[hash], c_list) {if (cp->ipvs != ipvs)continue;if (cp->flags & IP_VS_CONN_F_TEMPLATE) {if (atomic_read(&cp->n_control) || !ip_vs_conn_ops_mode(cp))continue;else/* connection template of OPS */goto try_drop;}

对于TCP协议,如果其状态为IP_VS_TCP_S_SYN_RECV或者IP_VS_TCP_S_SYNACK,表明TCP连接尚处在建立阶段,直接break出来进行丢弃。而对于处在IP_VS_TCP_S_ESTABLISHED状态的TCP协议类型的连接,使用函数todrop_entry判断是否可进行丢弃。另外对于其它TCP状态的连接,不进行处理,遍历下一个。

            if (cp->protocol == IPPROTO_TCP) {switch(cp->state) {case IP_VS_TCP_S_SYN_RECV:case IP_VS_TCP_S_SYNACK:break;case IP_VS_TCP_S_ESTABLISHED:if (todrop_entry(cp))break;continue;default:continue;}

与以上的TCP协议类似,对于SCTP协议,如果其连接处于IP_VS_SCTP_S_INIT1或者IP_VS_SCTP_S_INIT状态,直接break出来进行丢弃处理。如果连接处于IP_VS_SCTP_S_ESTABLISHED状态,使用函数todrop_entry进行丢弃判断。其它SCTP协议状态的连接,不进行处理,遍历下一个。

            } else if (cp->protocol == IPPROTO_SCTP) {switch (cp->state) {case IP_VS_SCTP_S_INIT1:case IP_VS_SCTP_S_INIT:break;case IP_VS_SCTP_S_ESTABLISHED:if (todrop_entry(cp))break;continue;default:continue;}

除了以上的TCP和SCTP协议之外,其它的协议统一使用函数todrop_entry进行丢弃判断。

            } else {
try_drop:if (!todrop_entry(cp))continue;}

执行到此处的连接,表示要被进行丢弃。由函数ip_vs_conn_expire_now将连接的超时定时器更改为当下,最终由超时处理函数ip_vs_conn_expire执行连接的删除操作。

            IP_VS_DBG(4, "del connection\n");ip_vs_conn_expire_now(cp);cp_c = cp->control;/* cp->control is valid only with reference to cp */if (cp_c && __ip_vs_conn_get(cp)) {IP_VS_DBG(4, "del conn template\n");ip_vs_conn_expire_now(cp_c);__ip_vs_conn_put(cp);}

secure_tcp处理

static unsigned int ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int af)
{ip_vs_in_stats(cp, skb);ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd);if (cp->packet_xmit)ret = cp->packet_xmit(skb, cp, pp, &iph);/* do not touch skb anymore */

函数ip_vs_set_state封装了IPVS支持的各个协议所注册的状态转换函数指针state_transition。

static inline void ip_vs_set_state(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_proto_data *pd)
{if (likely(pd->pp->state_transition))pd->pp->state_transition(cp, direction, skb, pd);

对于TCP协议而言,其为tcp_state_transition函数,核心的子函数为set_tcp_state。

static void tcp_state_transition(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_proto_data *pd)
{struct tcphdr _tcph, *th;#ifdef CONFIG_IP_VS_IPV6int ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
#elseint ihl = ip_hdrlen(skb);
#endifth = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph);set_tcp_state(pd, cp, direction, th);

如下的set_tcp_state函数,由TCP协议转换表tcp_state_table推导出当前连接的下一个状态new_state,如果此新状态不是活跃的TCP状态,并且此连接之前为设置inactive标志,将为其设置IP_VS_CONN_F_INACTIVE标志,递减目的服务器的activeconns活跃连接计数,增加inactconns非活跃连接计数。反之亦然。

static inline void set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, int direction, struct tcphdr *th)
{int new_state = IP_VS_TCP_S_CLOSE;int state_off = tcp_state_off[direction];if ((state_idx = tcp_state_idx(th)) < 0) {IP_VS_DBG(8, "tcp_state_idx=%d!!!\n", state_idx);goto tcp_state_out;}new_state = pd->tcp_state_table[state_off+state_idx].next_state[cp->state];tcp_state_out:if (new_state != cp->state) {struct ip_vs_dest *dest = cp->dest;if (dest) {if (!(cp->flags & IP_VS_CONN_F_INACTIVE) && !tcp_state_active(new_state)) {atomic_dec(&dest->activeconns);atomic_inc(&dest->inactconns);cp->flags |= IP_VS_CONN_F_INACTIVE;} else if ((cp->flags & IP_VS_CONN_F_INACTIVE) && tcp_state_active(new_state)) {atomic_inc(&dest->activeconns);atomic_dec(&dest->inactconns);cp->flags &= ~IP_VS_CONN_F_INACTIVE;

以下为正常情况下的TCP状态转换表tcp_states,以及开启secure_tcp之后所使用的tcp_states_dos转换表。例如,在输入方向(TCP_DIR_INPUT),对于正常的tcp_states转换表,如果当前连接状态为sSR(SYN_RECV),那么下一个状态根据报文类型(SYN,FIN,ACK和RST)分别为(sSR,sTW,sES和sSR);而对于tcp_states_dos转换表,其下一个状态分别为(sSR,sTW,sSR和sSR),只有接收到FIN报文,其状态才会转换到sTW(TIME_WAIT),其它类型报文不引起状态变迁。目前还没有搞清楚这两张表的意义(…>_<…)。

static struct tcp_states_t tcp_states [] = {
/*  INPUT */
/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA */
/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR }},
/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sTW }},
/*ack*/ {{sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sCL, sLI, sES }},
/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sSR }},
...
};static struct tcp_states_t tcp_states_dos [] = {
/*  INPUT */
/*        sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI, sSA */
/*syn*/ {{sSR, sES, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSA }},
/*fin*/ {{sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI, sSA }},
/*ack*/ {{sES, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI, sSA }},
/*rst*/ {{sCL, sCL, sCL, sSR, sCL, sCL, sCL, sCL, sLA, sLI, sCL }},

内核版本 4.15

这篇关于IPVS之安全防御的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511788

相关文章

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

安全管理体系化的智慧油站开源了。

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本。用户只需在界面上进行简单的操作,就可以实现全视频的接入及布控。摄像头管理模块用于多种终端设备、智能设备的接入及管理。平台支持包括摄像头等终端感知设备接入,为整个平台提

2024网安周今日开幕,亚信安全亮相30城

2024年国家网络安全宣传周今天在广州拉开帷幕。今年网安周继续以“网络安全为人民,网络安全靠人民”为主题。2024年国家网络安全宣传周涵盖了1场开幕式、1场高峰论坛、5个重要活动、15场分论坛/座谈会/闭门会、6个主题日活动和网络安全“六进”活动。亚信安全出席2024年国家网络安全宣传周开幕式和主论坛,并将通过线下宣讲、创意科普、成果展示等多种形式,让广大民众看得懂、记得住安全知识,同时还

【Kubernetes】K8s 的安全框架和用户认证

K8s 的安全框架和用户认证 1.Kubernetes 的安全框架1.1 认证:Authentication1.2 鉴权:Authorization1.3 准入控制:Admission Control 2.Kubernetes 的用户认证2.1 Kubernetes 的用户认证方式2.2 配置 Kubernetes 集群使用密码认证 Kubernetes 作为一个分布式的虚拟

企业安全之WiFi篇

很多的公司都没有安全团队,只有运维来负责整个公司的安全,从而安全问题也大打折扣。我最近一直在给各个公司做安全检测,就把自己的心得写下来,有什么不足之处还望补充。 0×01  无线安全 很多的公司都有不怎么注重公司的无线电安全,有钱的公司买设备,没钱的公司搞人力。但是人的技术在好,没有设备的辅助,人力在牛逼也没有个卵用。一个好的路由器、交换机、IDS就像你装备了 无尽、狂徒、杀人书一

Linux 安全弹出外接磁盘

命令行操作 首先,需要卸载硬盘上的所有分区,可以使用umount来卸载分区 清空系统缓存,将所有的数据写入磁盘 sync 列出已挂载的文件系统 使用lsblk或者df命令来查找要卸载的分区 lsblk or df -h 确保没有文件正在使用 使用lsof 命令来检查 sudo lsof |grep /dev/sdc 卸载分区 假设硬盘的分区是 /dev/sdc1,使用u

3.比 HTTP 更安全的 HTTPS(工作原理理解、非对称加密理解、证书理解)

所谓的协议 协议只是一种规则,你不按规则来就无法和目标方进行你的工作 协议说白了只是人定的规则,任何人都可以定协议 我们不需要太了解细节,这些制定和完善协议的人去做的,我们只需要知道协议的一个大概 HTTPS 协议 1、概述 HTTPS(Hypertext Transfer Protocol Secure)是一种安全的超文本传输协议,主要用于在客户端和服务器之间安全地传输数据

【小迪安全笔记 V2022 】信息打点9~11

第9天 信息打点-CDN绕过篇&漏洞回链8接口探针&全网扫指&反向件 知识点: 0、CDN知识-工作原理及阻碍 1、CDN配置-域名&区域&类型 2、CDN绕过-靠谱十余种技战法 3、CDN绑定-HOSTS绑定指向访问 CDN 是构建在数据网络上的一种分布式的内容分发网。 CDN的作用是采用流媒体服务器集群技术,克服单机系统输出带宽及并发能力不足的缺点,可极大提升系统支持的并发流数目,减少或避

OpenStack中加固VNC访问安全

OpenStack中加固VNC访问安全 目录 OpenStack中加固VNC访问安全1.问题发现2.流程分析3.潜在后果4.解决方案④配置IPtables⑤VNC添加访问密码 5.参考链接 1.问题发现 很多同学使用noVNC之后都没有退出终端的习惯,往往都是用完了就直接关闭网页窗口。说这样隐患很大,如果内网里面有一些script kiddie随时都能将我们线上的虚拟

开源Apache服务器安全防护技术精要及实战

Apache 服务简介   Web服务器也称为WWW服务器或HTTP服务器(HTTPServer),它是Internet上最常见也是使用最频繁的服务器之一,Web服务器能够为用户提供网页浏览、论坛访问等等服务。   由于用户在通过Web浏览器访问信息资源的过程中,无须再关心一些技术性的细节,而且界面非常友好,因而Web在Internet上一推出就得到了爆炸性的发展。现在Web服务器已