什么是CC攻击
攻击者短时间内发送多个URL请求到目标网站,专门攻击那些需要大量数据操作、占用大量计算的页面,从而拖垮网站,达到攻击目的。
预防策略
打铁还需自身硬,做好内部逻辑优化。处理慢查询、添加缓存读取、CDN负载集群模式。
服务器开启防CC攻击,如Nginx服务器。实现原理,通过给请求置Cookie或者置请求参数,进行预判,如果不带目标参数则设置后重定向。可以避免那些简单的发重复请求的攻击。(因为浏览器可以通过读协议头重定向到原先网址请求)
举例说明
网站开启防CC攻击,CURL请求接口(如下),反复重定向导致异常,无法获取数据。而贴到浏览器则能正常访问(自身做了重定向操作)
https://www.website.com/article.html
而且目前服务器响应头没有返回gzip压缩,但实际上返回的数据是经过gzip压缩,通过读取返回头无法判断,高版本浏览器可以内部识别,IE浏览器部分无法解析,因此可以判断返回的文本是不是gzip格式来处理。
如果是curl方式读取带gizp响应头的数据,内部会自行解压,因此遇到这种情况需要兼容处理。代码如下
//请求头
$opt = ['ua' = > 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36', 'headers' = > ['Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Encoding:gzip, deflate, br', 'Accept-Language:zh-CN', 'Cache-Control:no-cache', ], ];
$url = '目标地址';
$return = httpRequest($url, $opt, $code, $headers, false);
//检测是否需要重定向 防CC处理
if (isRedirectUrl($headers)) {
//获取验证信息 再次请求
$opt['cookies'] = getUrlCookie($headers);
$return = httpRequest($url, $opt, $code, $headers, false);
}
//检查是否有gzip压缩 解压gzip数据
if (is_gzip($return)) {
$return = gzdecode($return);
}
$return = json_decode($return, true);
// 判断是否是重定向
function isRedirectUrl($headers) {
if (strpos($headers, 'Location:') !== false) {
return true;
} else {
return false;
}
}
function getUrlCookie($headers) {
preg_match('#Set-Cookie: (.*)#', $headers, $matches);
return $matches[1];
}
//检查是否是GZIP压缩
function is_gzip($html) {
return 0 === mb_strpos($html, "\x1f".
"\x8b".
"\x08", 0, "US-ASCII");
}
if (!function_exists('gzdecode')) {
function gzdecode($data) {
$flags = ord(substr($data, 3, 1));
$headerlen = 10;
$extralen = 0;
$filenamelen = 0;
if ($flags & 4) {
$extralen = unpack('v', substr($data, 10, 2));
$extralen = $extralen[1];
$headerlen += 2 + $extralen;
}
if ($flags & 8) // Filename
{
$headerlen = strpos($data, chr(0), $headerlen) + 1;
}
if ($flags & 16) // Comment
{
$headerlen = strpos($data, chr(0), $headerlen) + 1;
}
if ($flags & 2) // CRC at end of file
{
$headerlen += 2;
}
$unpacked = @gzinflate(substr($data, $headerlen));
if ($unpacked === FALSE) {
$unpacked = $data;
}
return $unpacked;
}
}
/**
* curl HTTP请求
* @param string $url 网址
* @param mixed $opt 请求参数
* @param integer $code 响应状态码
* @param array &$headers 响应头信息
* @param boolean $redirect 自动重定向
* @param boolean $ssl 验证https证书
* @return string
*/
function httpRequest($url, $opt = 'GET', & $code = null, & $headers = null, $redirect = true, $ssl = false) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $ssl);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $ssl);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $redirect);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
if ($opt == 'POST' || (isset($opt['type']) && $opt['type'] == 'POST')) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, isset($opt['data']) ? $opt['data'] : '');
}
if (is_array($opt)) {
// User-Agent
if (array_key_exists('ua', $opt)) {
curl_setopt($ch, CURLOPT_USERAGENT, $opt['ua']);
}
// Headers
if (array_key_exists('headers', $opt)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, (array) $opt['headers']);
}
// Cookies
if (array_key_exists('cookies', $opt)) {
curl_setopt($ch, CURLOPT_COOKIE, $opt['cookies']);
}
// Referer
if (array_key_exists('referer', $opt)) {
curl_setopt($ch, CURLOPT_REFERER, $opt['referer']);
}
}
$result = curl_exec($ch);
if (curl_errno($ch)) {
$result = curl_error($ch);
} else {
// 取出状态码
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
// 获取头长度
$length = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
// 取出头信息
$headers = substr($result, 0, $length);
// 去掉头信息
$result = substr($result, $length);
}
curl_close($ch);
return $result;
}