2025-05-20 16:33:23 +08:00

187 lines
8.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace addons\webscan\library;
use addons\webscan\model\WebscanLog;
use think\Config;
use think\exception\HttpResponseException;
use think\Request;
use think\Response;
use think\Url;
/**
* SQL注入XSS攻击助手
* @author amplam 122795200@qq.com
* @date 2019年10月29日 17:43:27
*/
class Webscan extends Server
{
protected $error = "";
//get拦截规则
private $getfilter = "\\<.+javascript:window\\[.{1}\\\\x|<.*=(&#\\d+?;?)+?>|<.*(data|src)=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|\\b(group_)?concat[\\s\\/\\*]*?\\([^\\)]+?\\)|\bcase[\s\/\*]*?when[\s\/\*]*?\([^\)]+?\)|load_file\s*?\\()|<[a-z]+?\\b[^>]*?\\bon([a-z]{4,})\s*?=|^\\+\\/v(8|9)|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
//post拦截规则
private $postfilter = "<.*=(&#\\d+?;?)+?>|<.*data=data:text\\/html.*>|\\b(alert\\(|confirm\\(|expression\\(|prompt\\(|benchmark\s*?\(.*\)|sleep\s*?\(.*\)|\\b(group_)?concat[\\s\\/\\*]*?\\([^\\)]+?\\)|\bcase[\s\/\*]*?when[\s\/\*]*?\([^\)]+?\)|load_file\s*?\\()|<[^>]*?\\b(onerror|onmousemove|onload|onclick|onmouseover)\\b|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
//cookie拦截规则
private $cookiefilter = "benchmark\s*?\(.*\)|sleep\s*?\(.*\)|load_file\s*?\\(|\\b(and|or)\\b\\s*?([\\(\\)'\"\\d]+?=[\\(\\)'\"\\d]+?|[\\(\\)'\"a-zA-Z]+?=[\\(\\)'\"a-zA-Z]+?|>|<|\s+?[\\w]+?\\s+?\\bin\\b\\s*?\(|\\blike\\b\\s+?[\"'])|\\/\\*.*\\*\\/|<\\s*script\\b|\\bEXEC\\b|UNION.+?SELECT\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)|UPDATE\s*(\(.+\)\s*|@{1,2}.+?\s*|\s+?.+?|(`|'|\").*?(`|'|\")\s*)SET|INSERT\\s+INTO.+?VALUES|(SELECT|DELETE)@{0,2}(\\(.+\\)|\\s+?.+?\\s+?|(`|'|\").*?(`|'|\"))FROM(\\(.+\\)|\\s+?.+?|(`|'|\").*?(`|'|\"))|(CREATE|ALTER|DROP|TRUNCATE)\\s+(TABLE|DATABASE)";
protected $config = [
'webscan_switch' => 1,//拦截开关(1为开启0关闭)
//提交方式拦截(1开启拦截,0关闭拦截,post,get,cookie,referre选择需要拦截的方式)
'webscan_post' => 1,
'webscan_get' => 1,
'webscan_cookie' => 1,
'webscan_referre' => 1,
'black_auto' => 0,//攻击多少次/天自动加入黑名单。为0不加入黑名单
'webscan_warn' => "检测有非法攻击代码,请停止攻击,否则将加入黑名单,如有疑问请联系我们",//提示
'webscan_white_module' => '',//放行指定模块 多个以|隔开 如admin|admin1
'webscan_white_url' => '',//模块/控制器/方法 一行一条记录 如admin/index/login
'webscan_white_ip' => '',//白名单ip 一行一条记录 如127.0.0.1
];
/**
* 构造函数
* WxPay constructor.
* @param $config
*/
public function __construct($config = [])
{
$this->config = array_merge($this->config, $config);
}
/**
* 开始拦截
*/
public function start()
{
if ($this->config['webscan_switch'] && $this->webscanWhite($this->config['webscan_white_module'], $this->config['webscan_white_url'])) {
if ($this->config['webscan_get']) {
$_GET['temp_url_path'] = \request()->pathinfo();//请求的路径也加入检测
foreach ($_GET as $key => $value) {
$this->webscanStopAttack($key, $value, $this->getfilter, "GET");
}
}
if ($this->config['webscan_post']) {
foreach ($_POST as $key => $value) {
$this->webscanStopAttack($key, $value, $this->postfilter, "POST");
}
}
if ($this->config['webscan_cookie']) {
foreach ($_COOKIE as $key => $value) {
$this->webscanStopAttack($key, $value, $this->cookiefilter, "COOKIE");
}
}
if ($this->config['webscan_referre']) {
//referer获取
$webscan_referer = empty($_SERVER['HTTP_REFERER']) ? array() : array('HTTP_REFERER' => $_SERVER['HTTP_REFERER']);
foreach ($webscan_referer as $key => $value) {
$this->webscanStopAttack($key, $value, $this->postfilter, "REFERRER");
}
}
//其他类似put,delete的检测
$method = \request()->method(true);
// 自动获取请求变量
switch ($method) {
case 'PUT':
case 'DELETE':
case 'PATCH':
$put_arr = \request()->put();
foreach ($put_arr as $key => $value) {
$this->webscanStopAttack($key, $value, $this->postfilter, $method);
}
break;
default:
}
}
}
/**
* 拦截白名单
* true需要拦截false 不需要
*/
private function webscanWhite($webscan_white_module, $webscan_white_url)
{
//ip白名单
if ($this->whiteIp($this->config['webscan_white_ip'])) return false;
//URL白名单
if ($this->whiteUrl($webscan_white_url)) return false;
return true;
}
/**
* 攻击检查拦截
*/
private function webscanStopAttack($StrFiltKey, $StrFiltValue, $ArrFiltReq, $method)
{
$StrFiltValue = $this->webscanArrForeach($StrFiltValue);
if (preg_match("/" . $ArrFiltReq . "/is", $StrFiltValue) == 1) {
$this->webscanSlog(array('ip' => \request()->ip(), 'page' => $_SERVER["PHP_SELF"], 'method' => \request()->method(), 'rkey' => $StrFiltKey, 'rdata' => $StrFiltValue, 'user_agent' => $_SERVER['HTTP_USER_AGENT'], 'request_url' => $_SERVER["REQUEST_URI"], 'type' => 'webscan'));
return $this->webscanPape();
}
if (preg_match("/" . $ArrFiltReq . "/is", $StrFiltKey) == 1) {
$this->webscanSlog(array('ip' => \request()->ip(), 'page' => $_SERVER["PHP_SELF"], 'method' => \request()->method(), 'rkey' => $StrFiltKey, 'rdata' => $StrFiltKey, 'user_agent' => $_SERVER['HTTP_USER_AGENT'], 'request_url' => $_SERVER["REQUEST_URI"], 'type' => 'webscan'));
return $this->webscanPape();
}
}
/**
* 参数拆分
*/
private function webscanArrForeach($arr)
{
static $str;
static $keystr;
if (!is_array($arr)) {
return $arr;
}
foreach ($arr as $key => $val) {
$keystr = $keystr . $key;
if (is_array($val)) {
return $this->webscanArrForeach($val);
} else {
$str[] = $val . $keystr;
}
}
return implode($str);
}
/**
* 防护提示
*/
public function webscanPape()
{
if ($this->config['return_json']) {
$url_var = $_SERVER['REQUEST_URI'];
$url_var = strpos($url_var, '/') != 0 ?: substr($url_var, 1);
$search = ["/", "?", "=", ".", "&", '|'];
$replace = ["\/", "\?", "\=", "\.", "\&", '|^'];
$this->config['return_json'] = str_replace($search, $replace, $this->config['return_json']);
if (preg_match("/^" . $this->config['return_json'] . "/is", $url_var)) {
return $this->result($this->config['webscan_warn'], [], '-110', 'json');
}
}
return $this->result($this->config['webscan_warn'], [], '-110', $this->getResponseType());
}
}