DDoS攻击防御是每个网站运维人员的必修课,因为DDoS和CC攻击是门槛非常低的网络攻击方式,以至于成为脚本小子的最爱,这种攻击方式通常被用于恶性商业竞争、炫耀式的恶作剧,或用于敲诈勒索等,其危害性是不容小觑的。如果你是一个小博客网站,却遭到不明缘由的DDoS或CC攻击的话,那么这对你好不容易积累起来的网站权重的打击是毁灭性的。一般情况下,如果你在使用国内的VPS,会被直接打进黑洞清洗状态,一般持续2小时-12小时不等;如果你使用国外的VPS,一般会被打进黑洞半小时以上,期间你的网站主机商是不允许你重新上线的,除非你另外再开一台VPS。
网站防御DDoS和CC攻击不仅是大型网站的重要工作,也是小网站不可忽视的一项内容,但是这需要一定的技术门槛,我结合自己的理解和实践进行了总结,特此记录。
本文目录
1、隐藏并保护源站IP
(1)泄漏源站IP的方式有哪些?
1)扫描全网IP数据库
它7×24小时扫描全网IP,可能你正好在添加DNS解析,而且还没有套上CDN而被扫描到了,于是它就会把你的域名和源站IP的对应关系添加到数据库保存。
原理:当我们在浏览器输入域名,浏览器通过HTTP(S)协议访问具体网站的通讯过程是通过查询DNS域名解析获得目标网站的IP地址,就相当于http(s)://IP:端口的形式(HTTP默认端口:80、HTTPS默认端口:443)向源站获取网站内容。如果你在浏览器直接输入形如“http(s)://IP:端口”的地址,如果得到回应,会显示你的SSL证书绑定的域名信息。如下图所示:
2)Wordpress评论邮件泄漏源站IP
因为Wordpress系统自动发送的提醒邮件会包含你源站IP信息,如下图所示:
3)站长工具IP查询
有些站长喜欢用站长工具查询网站域名,殊不知,你一旦查询之后,你的域名和IP的绑定关系就被记录了,而且会被搜索引擎收录。常用的站长工具如 站长之家“http://ping.chinaz.com/”、爱站网“http://ping.aizhan.com/”等。
(2)如何隐藏你的源站IP地址?
1)在启用CDN防护之前,我们使用http协议,而暂时不配置SSL证书,同时修改你远程VPS的SSH连接端口为不常用端口,然后设置防火墙规则为仅允许你的CDN服务商的节点IP访问源站,其它的请求全部阻断。防火墙规则设置脚本内容如下:
nano firewall.sh ##创建一个防火墙脚本 # 输入以下内容 #!/bin/bash # Name : Anti IP Leakage # Author: Zhys # Date : 2019 # 禁止来自IPv4的所有HTTP/S访问请求 iptables -I INPUT -p tcp --dport 80 -j DROP iptables -I INPUT -p tcp --dport 443 -j DROP # 对Cloudflare CDN IPv4地址开放HTTP/S入站访问 for i in `curl https://www.cloudflare.com/ips-v4`; do iptables -I INPUT -s $i -p tcp --dport 80 -j ACCEPT; done for i in `curl https://www.cloudflare.com/ips-v4`; do iptables -I INPUT -s $i -p tcp --dport 443 -j ACCEPT; done # 禁止来自IPv6的所有HTTP/S访问请求 ip6tables -I INPUT -p tcp --dport 80 -j DROP ip6tables -I INPUT -p tcp --dport 443 -j DROP # 对Cloudflare CDN IPv6地址开放HTTP/S入站访问 for i in `curl https://www.cloudflare.com/ips-v6`; do ip6tables -I INPUT -s $i -p tcp --dport 80 -j ACCEPT; done for i in `curl https://www.cloudflare.com/ips-v6`; do ip6tables -I INPUT -s $i -p tcp --dport 443 -j ACCEPT; done # 保存iptables配置 iptables-save ip6tables-save # 注意:80/443为默认HTTP/S协议通讯使用端口,若实际应用有使用非80/443端口进行,请依葫芦画瓢自行修改脚本 # Ubuntu系统可以使用UFW则类似:for i in `curl https://www.cloudflare.com/ips-v4`; do ufw allow proto tcp from $i to any port 80; done # 基于Linux系统兼容性考虑脚本使用iptables配置系统防火墙,请自行根据各自系统、防火墙不同做相应配置调整实施 # 按CTRL+X 保存即可 bash firewall.sh ##使防火墙生效
注意事项:这个需要你有CDN服务商的IP段,否则容易造成误伤,这样可以有效防止IP地址被类似于 censys 这样的网站扫描到。
2)临时使用无关域名和源站IP的SSL证书
如果你是在无法得到CDN提供商的IP段,而且仍然想要不被自动扫描程序监控到IP跟域名的关系,那么你先可以使用临时无关域名的SSL证书。当加上CDN之后,再重新更新SSL证书。这种操作你可以借助宝塔面板添加自定义的假SSL证书,总之都是为了隐藏域名跟IP地址的绑定关系。其实,对于一般小博客不用这么麻烦,被扫描到的概率非常低,而且你只是短暂的暴露,大约5分钟左右就够了。
如果以上方法都没有成功隐藏源站IP,那么很可能你的IP早已经泄漏过了。
2、隐藏网站程序特征
如果你在使用 WordPress,那么推荐你使用插件“Hide My WP Ghost Lite”,土豪用户可以购买专业高级版,这可以有效防止针对 WordPress 程序的漏洞攻击,以及针对特定页面的CC攻击。
3、最大程度使网站静态化
如果你把网站的每一个页面全部静态化,然后开启 Cloudflare 缓存的“永久在线(Always Online)”,全站静态化缓存是最理想状态,这时候即使你源站关机也不影响用户访问。由于 Cloudflare 拥有超过35TB流量的防御能力,所以这时候你的网站约等于打不死。
4、开启 Cloudflare Workers 缓存
Cloudflare Workers 的缓存比一般的 CF 缓存加页面规则更有效,所以我们启用它。
(1)创建 Cloudflare Worker,代码如下:
// IMPORTANT: Either A Key/Value Namespace must be bound to this worker script // using the variable name EDGE_CACHE. or the API parameters below should be // configured. KV is recommended if possible since it can purge just the HTML // instead of the full cache. // API settings if KV isn't being used const CLOUDFLARE_API = { email: "你的邮箱", // From https://dash.cloudflare.com/profile key: "全局 API Token", // Global API Key from https://dash.cloudflare.com/profile zone: "对应域名的Zone ID" // "Zone ID" from the API section of the dashboard overview page https://dash.cloudflare.com/ }; // Default cookie prefixes for bypass // 注意!!!!这里填写你的对应路径,若你没有修改过就保持这样,修改过了WP的评论等路径的在此更改对应的路径成为你的路径 const DEFAULT_BYPASS_COOKIES = [ "wp-", "wordpress", "comment_", "woocommerce_", "comments_" ]; //后面的不动就行了。 /** * Main worker entry point. */ addEventListener("fetch", event => { const request = event.request; let upstreamCache = request.headers.get('x-HTML-Edge-Cache'); // Only process requests if KV store is set up and there is no // HTML edge cache in front of this worker (only the outermost cache // should handle HTML caching in case there are varying levels of support). let configured = false; if (typeof EDGE_CACHE !== 'undefined') { configured = true; } else if (CLOUDFLARE_API.email.length && CLOUDFLARE_API.key.length && CLOUDFLARE_API.zone.length) { configured = true; } // Bypass processing of image requests (for everything except Firefox which doesn't use image/*) const accept = request.headers.get('Accept'); let isImage = false; if (accept && (accept.indexOf('image/*') !== -1)) { isImage = true; } if (configured && !isImage && upstreamCache === null) { event.passThroughOnException(); event.respondWith(processRequest(request, event)); } }); /** * Process every request coming through to add the edge-cache header, * watch for purge responses and possibly cache HTML GET requests. * * @param {Request} originalRequest - Original request * @param {Event} event - Original event (for additional async waiting) */ async function processRequest(originalRequest, event) { let cfCacheStatus = null; const accept = originalRequest.headers.get('Accept'); const isHTML = (accept && accept.indexOf('text/html') >= 0); let {response, cacheVer, status, bypassCache} = await getCachedResponse(originalRequest); if (response === null) { // Clone the request, add the edge-cache header and send it through. let request = new Request(originalRequest); request.headers.set('x-HTML-Edge-Cache', 'supports=cache|purgeall|bypass-cookies'); response = await fetch(request); if (response) { const options = getResponseOptions(response); if (options && options.purge) { await purgeCache(cacheVer, event); status += ', Purged'; } bypassCache = bypassCache || shouldBypassEdgeCache(request, response); if ((!options || options.cache) && isHTML && originalRequest.method === 'GET' && response.status === 200 && !bypassCache) { status += await cacheResponse(cacheVer, originalRequest, response, event); } } } else { // If the origin didn't send the control header we will send the cached response but update // the cached copy asynchronously (stale-while-revalidate). This commonly happens with // a server-side disk cache that serves the HTML directly from disk. cfCacheStatus = 'HIT'; if (originalRequest.method === 'GET' && response.status === 200 && isHTML) { bypassCache = bypassCache || shouldBypassEdgeCache(originalRequest, response); if (!bypassCache) { const options = getResponseOptions(response); if (!options) { status += ', Refreshed'; event.waitUntil(updateCache(originalRequest, cacheVer, event)); } } } } if (response && status !== null && originalRequest.method === 'GET' && response.status === 200 && isHTML) { response = new Response(response.body, response); response.headers.set('x-HTML-Edge-Cache-Status', status); if (cacheVer !== null) { response.headers.set('x-HTML-Edge-Cache-Version', cacheVer.toString()); } if (cfCacheStatus) { response.headers.set('CF-Cache-Status', cfCacheStatus); } } return response; } /** * Determine if the cache should be bypassed for the given request/response pair. * Specifically, if the request includes a cookie that the response flags for bypass. * Can be used on cache lookups to determine if the request needs to go to the origin and * origin responses to determine if they should be written to cache. * @param {Request} request - Request * @param {Response} response - Response * @returns {bool} true if the cache should be bypassed */ function shouldBypassEdgeCache(request, response) { let bypassCache = false; if (request && response) { const options = getResponseOptions(response); const cookieHeader = request.headers.get('cookie'); let bypassCookies = DEFAULT_BYPASS_COOKIES; if (options) { bypassCookies = options.bypassCookies; } if (cookieHeader && cookieHeader.length && bypassCookies.length) { const cookies = cookieHeader.split(';'); for (let cookie of cookies) { // See if the cookie starts with any of the logged-in user prefixes for (let prefix of bypassCookies) { if (cookie.trim().startsWith(prefix)) { bypassCache = true; break; } } if (bypassCache) { break; } } } } return bypassCache; } const CACHE_HEADERS = ['Cache-Control', 'Expires', 'Pragma']; /** * Check for cached HTML GET requests. * * @param {Request} request - Original request */ async function getCachedResponse(request) { let response = null; let cacheVer = null; let bypassCache = false; let status = 'Miss'; // Only check for HTML GET requests (saves on reading from KV unnecessarily) // and not when there are cache-control headers on the request (refresh) const accept = request.headers.get('Accept'); const cacheControl = request.headers.get('Cache-Control'); let noCache = false; if (cacheControl && cacheControl.indexOf('no-cache') !== -1) { noCache = true; status = 'Bypass for Reload'; } if (!noCache && request.method === 'GET' && accept && accept.indexOf('text/html') >= 0) { // Build the versioned URL for checking the cache cacheVer = await GetCurrentCacheVersion(cacheVer); const cacheKeyRequest = GenerateCacheRequest(request, cacheVer); // See if there is a request match in the cache try { let cache = caches.default; let cachedResponse = await cache.match(cacheKeyRequest); if (cachedResponse) { // Copy Response object so that we can edit headers. cachedResponse = new Response(cachedResponse.body, cachedResponse); // Check to see if the response needs to be bypassed because of a cookie bypassCache = shouldBypassEdgeCache(request, cachedResponse); // Copy the original cache headers back and clean up any control headers if (bypassCache) { status = 'Bypass Cookie'; } else { status = 'Hit'; cachedResponse.headers.delete('Cache-Control'); cachedResponse.headers.delete('x-HTML-Edge-Cache-Status'); for (header of CACHE_HEADERS) { let value = cachedResponse.headers.get('x-HTML-Edge-Cache-Header-' + header); if (value) { cachedResponse.headers.delete('x-HTML-Edge-Cache-Header-' + header); cachedResponse.headers.set(header, value); } } response = cachedResponse; } } else { status = 'Miss'; } } catch (err) { // Send the exception back in the response header for debugging status = "Cache Read Exception: " + err.message; } } return {response, cacheVer, status, bypassCache}; } /** * Asynchronously purge the HTML cache. * @param {Int} cacheVer - Current cache version (if retrieved) * @param {Event} event - Original event */ async function purgeCache(cacheVer, event) { if (typeof EDGE_CACHE !== 'undefined') { // Purge the KV cache by bumping the version number cacheVer = await GetCurrentCacheVersion(cacheVer); cacheVer++; event.waitUntil(EDGE_CACHE.put('html_cache_version', cacheVer.toString())); } else { // Purge everything using the API const url = "https://api.cloudflare.com/client/v4/zones/" + CLOUDFLARE_API.zone + "/purge_cache"; event.waitUntil(fetch(url,{ method: 'POST', headers: {'X-Auth-Email': CLOUDFLARE_API.email, 'X-Auth-Key': CLOUDFLARE_API.key, 'Content-Type': 'application/json'}, body: JSON.stringify({purge_everything: true}) })); } } /** * Update the cached copy of the given page * @param {Request} originalRequest - Original Request * @param {String} cacheVer - Cache Version * @param {EVent} event - Original event */ async function updateCache(originalRequest, cacheVer, event) { // Clone the request, add the edge-cache header and send it through. let request = new Request(originalRequest); request.headers.set('x-HTML-Edge-Cache', 'supports=cache|purgeall|bypass-cookies'); response = await fetch(request); if (response) { status = ': Fetched'; const options = getResponseOptions(response); if (options && options.purge) { await purgeCache(cacheVer, event); } let bypassCache = shouldBypassEdgeCache(request, response); if ((!options || options.cache) && !bypassCache) { await cacheResponse(cacheVer, originalRequest, response, event); } } } /** * Cache the returned content (but only if it was a successful GET request) * * @param {Int} cacheVer - Current cache version (if already retrieved) * @param {Request} request - Original Request * @param {Response} originalResponse - Response to (maybe) cache * @param {Event} event - Original event * @returns {bool} true if the response was cached */ async function cacheResponse(cacheVer, request, originalResponse, event) { let status = ""; const accept = request.headers.get('Accept'); if (request.method === 'GET' && originalResponse.status === 200 && accept && accept.indexOf('text/html') >= 0) { cacheVer = await GetCurrentCacheVersion(cacheVer); const cacheKeyRequest = GenerateCacheRequest(request, cacheVer); try { // Move the cache headers out of the way so the response can actually be cached. // First clone the response so there is a parallel body stream and then // create a new response object based on the clone that we can edit. let cache = caches.default; let clonedResponse = originalResponse.clone(); let response = new Response(clonedResponse.body, clonedResponse); for (header of CACHE_HEADERS) { let value = response.headers.get(header); if (value) { response.headers.delete(header); response.headers.set('x-HTML-Edge-Cache-Header-' + header, value); } } response.headers.delete('Set-Cookie'); response.headers.set('Cache-Control', 'public; max-age=315360000'); event.waitUntil(cache.put(cacheKeyRequest, response)); status = ", Cached"; } catch (err) { // status = ", Cache Write Exception: " + err.message; } } return status; } /****************************************************************************** * Utility Functions *****************************************************************************/ /** * Parse the commands from the x-HTML-Edge-Cache response header. * @param {Response} response - HTTP response from the origin. * @returns {*} Parsed commands */ function getResponseOptions(response) { let options = null; let header = response.headers.get('x-HTML-Edge-Cache'); if (header) { options = { purge: false, cache: false, bypassCookies: [] }; let commands = header.split(','); for (let command of commands) { if (command.trim() === 'purgeall') { options.purge = true; } else if (command.trim() === 'cache') { options.cache = true; } else if (command.trim().startsWith('bypass-cookies')) { let separator = command.indexOf('='); if (separator >= 0) { let cookies = command.substr(separator + 1).split('|'); for (let cookie of cookies) { cookie = cookie.trim(); if (cookie.length) { options.bypassCookies.push(cookie); } } } } } } return options; } /** * Retrieve the current cache version from KV * @param {Int} cacheVer - Current cache version value if set. * @returns {Int} The current cache version. */ async function GetCurrentCacheVersion(cacheVer) { if (cacheVer === null) { if (typeof EDGE_CACHE !== 'undefined') { cacheVer = await EDGE_CACHE.get('html_cache_version'); if (cacheVer === null) { // Uninitialized - first time through, initialize KV with a value // Blocking but should only happen immediately after worker activation. cacheVer = 0; await EDGE_CACHE.put('html_cache_version', cacheVer.toString()); } else { cacheVer = parseInt(cacheVer); } } else { cacheVer = -1; } } return cacheVer; } /** * Generate the versioned Request object to use for cache operations. * @param {Request} request - Base request * @param {Int} cacheVer - Current Cache version (must be set) * @returns {Request} Versioned request object */ function GenerateCacheRequest(request, cacheVer) { let cacheUrl = request.url; if (cacheUrl.indexOf('?') >= 0) { cacheUrl += '&'; } else { cacheUrl += '?'; } cacheUrl += 'cf_edge_cache_ver=' + cacheVer; return new Request(cacheUrl); }
(2)为选择域名的 Worker 规则添加路由
我们点击要添加规则的域名,然后点击“Workers”菜单,点击右侧的“添加路由”按钮,弹出添加 Cloudflare Worker 规则的窗口。具体设置如下图所示:
以上添加的 Cloudflare Worker 规则代码需要填写注册 Cloudflare 账户的电子邮件地址(email)、“区域 ID (key)”和“全局 API (zone)”。如下图所示:
Cloudflare Worker 规则代码内容如下:
#!/bin/sh # #cdn.bnxb.com自动开盾对接脚本,后续功能实时完善更新,请详见网站通知,其他不需要改,仅需要改下面三行参数 # token="您的TOPKEN" #本站生成的TOKEN内容【需要改成分配给您的实际KEY】 mode="load" #判断服务器负载方式 load负载法 cpu CPU百分比法 只能选一个 keeptime=1800 #开盾负载下降后持续多少秒,进行尝试关盾 if [ "$mode" = "cpu" ]; then check=90 #5秒内CPU连续超过80 则开盾【可以根据您的服务器负荷情况调整】 #系统空闲时间 TIME_INTERVAL=5 time=$(date "+%Y-%m-%d %H:%M:%S") LAST_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}') LAST_SYS_IDLE=$(echo $LAST_CPU_INFO | awk '{print $4}') LAST_TOTAL_CPU_T=$(echo $LAST_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}') sleep ${TIME_INTERVAL} NEXT_CPU_INFO=$(cat /proc/stat | grep -w cpu | awk '{print $2,$3,$4,$5,$6,$7,$8}') NEXT_SYS_IDLE=$(echo $NEXT_CPU_INFO | awk '{print $4}') NEXT_TOTAL_CPU_T=$(echo $NEXT_CPU_INFO | awk '{print $1+$2+$3+$4+$5+$6+$7}') #系统空闲时间 SYSTEM_IDLE=`echo ${NEXT_SYS_IDLE} ${LAST_SYS_IDLE} | awk '{print $1-$2}'` #CPU总时间 TOTAL_TIME=`echo ${NEXT_TOTAL_CPU_T} ${LAST_TOTAL_CPU_T} | awk '{print $1-$2}'` load=`echo ${SYSTEM_IDLE} ${TOTAL_TIME} | awk '{printf "%.2f", 100-$1/$2*100}'` else load=$(cat /proc/loadavg | colrm 5) check=$(cat /proc/cpuinfo | grep "processor" | wc -l) fi if [ ! -f "status.txt" ];then echo "" > status.txt else status=$(cat status.txt) fi now=$(date +%s) time=$(date +%s -r status.txt) echo "当前$mode负载:$load" if [[ $status -eq 1 ]] then echo "当前开盾中" else echo "当前未开盾" fi newtime=`expr $now - $time` closetime=`expr $keeptime - $newtime` if [[ $load <$check ]]&&[[ $status -eq 1 ]]&&[[ $newtime -gt $keeptime ]] then echo -e "\n$mode负载低于$check,当前已开盾超过半小时($newtime秒),尝试关盾" url="https://cdn.bnxb.com/api/?token=$token&status=off" cResult=$(curl --insecure -X GET $url ) echo $cResult if [[ $cResult -eq 1 ]] then echo 0 > status.txt echo -e "\n关盾成功" fi elif [[ $load <$check ]] then echo -e "\n$mode负载低于$check,不做任何改变,$newtime秒" if [[ $status -eq 1 ]] then echo -e "将于$closetime秒后关盾" fi exit elif [[ $load >$check ]] && [[ $status -eq 1 ]] && [[ $newtime -gt $keeptime ]] then echo -e "\n$mode负载高于$check,当前已开盾超过$newtime秒,盾无效,请联系管理员定制其他方案" exit elif [[ $load >$check ]] && [[ $status -eq 1 ]] then echo -e "\n$mode负载高于$check,当前已开盾($newtime秒),请再观察" exit elif [[ $load >$check ]] then echo -e "\n$mode负载高于$check,开启防御规则" url="https://cdn.bnxb.com/api/?token=$token&status=on" cResult=$(curl --insecure -X GET $url ) echo $cResult if [[ $cResult -eq 1 ]] then echo 1 > status.txt echo -e "\n开盾成功" fi else echo 0 > status.txt fi
此规则需要配合Wordpress的 Cloudflare、Cloudflare Page Cache 或 WP Rocket 等具备自动管理 Cloudflare 边缘缓存页面功能的插件。
5、自动开启 Cloudflare 的5秒盾
对于防御 DDoS 和 CC 攻击,我这里推荐您使用通过 CloudFlare Partner 接入的 Cloudflare CDN,当然普通用户接触到的都是免费版,个别用户可以接触到特殊渠道的专业版。
最简单的做法就是开启Cloudflare的5秒盾,但是期间会非常影响用户体验,而且攻击者会在开启期间暂停攻击,一旦你撤掉5秒盾会再次攻击你的网站。这样搞你,是不是很烦?你不可能一直看着网站吧!没关系,你只需要通过调用 CloudFlare API 来实现自动判断攻击并开启5秒盾就行了,这样可以让你的网站时刻都处于防御状态。
具体操作方法如下:
登录笨牛网,然后打开“自动开盾[ON]”,使其处于绿色状态,然后下载自动开盾的脚本文件。如下图所示:
使用说明:请将SH文件下载打开,将$token=””;改成上面TOKEN内容,然后将文件放在您服务器上的任意地方,使用命令“chmod+x tz.sh”赋权,设置定时任务1分钟执行一次此SH文件代码。SH文件代码修改,如下图所示:
如果你正在使用宝塔面板,那么把以上代码添加到计划任务。如下图所示:
至此,设置完成。是不是很简单?您的网站已经可以防御绝大多数的DDoS和CC攻击了。
6、配置 Cloudflare 防火墙规则
(1)添加防火墙规则(Anti-DDoS)
添加防火墙规则主要用来防御DDoS攻击,具体操作步骤:我们选择要操作的域名,然后依次点击“防火墙”-“防火墙规则”-“创建防火墙规则”,进入规则详细设置页面。如下图所示:
以上规则设置确认无误后,点击“部署”完成添加防火墙规则。
(2)添加 Rate Limit 规则(Anti-CC)
添加 Rate Limit 规则主要用来防御CC攻击,具体操作步骤:我们选择要操作的域名,然后依次点击“防火墙”-“工具”-“启用速率限制”,进入规则详细设置页面。这个需要开通 Cloudflare Pro 套餐或单独用信用卡购买规则(0.05美元/10000次合法请求),已阻止的请求无需再付费。
信用卡购买规则有些不受控制,说不定一夜之间一套房就没了,所以还是开通 Cloudflare Pro 套餐比较可靠。
(3)添加 Cloudflare 托管规则(WAF)
Cloudflare 托管规则默认可以防御网络层和应用程序层的DDoS攻击,而且开通 Cloudflare Pro 套餐还可以防御针对特定 Web 应用程序的漏洞攻击,即WAF防御规则。
只有 Cloudflare Pro 套餐才可以使用全功能的防火墙规则配置,免费版无法使用 Rate Limit 和 Web应用程序防火墙等。
7、DDoS攻击防御/CC攻击防御结语
通过以上配置,你的Wordpress网站已经可以防御绝大多数的DDoS或CC攻击了,但是没有高级版的话,CC攻击防御功能主要依靠 Cloudflare 的自动5秒盾,也许这是最低成本的网站安全防御策略。如果你的网站不是那么值钱的话,我相信没有傻B愿意花更多的流量和时间来DDoS和CC攻击你了,因为这一点都不划算。
本篇博客内容主要是针对Wordpress网站安全方面的配置,用于网站被DDoS攻击防御和CC攻击防御;如果你想要对服务器性能和网站速度进行优化的话,我建议你参考文章 【VPS加速+WordPress网站优化】记一次网站数据迁移后的服务器加速优化过程 和 通过 Cloudflare Partner 的CName方式接入并利用智能DNS解析为不同网络线路分配优选Cloudflare自定义IP节点实现全球CDN加速
本文由一灯不是和尚于2020年7月12日更新;如果您有什么意见或建议,请在文章下面评论区留言反馈。