• 0
  • 0

接口地址防CC加GIZP压缩处理

2019-07-09 909 0 admin 所属分类:PHP 记录

什么是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;
}


返回顶部