diff --git a/app/Exceptions/ServiceUnavailable.php b/app/Exceptions/ServiceUnavailable.php new file mode 100644 index 00000000..12d7e63c --- /dev/null +++ b/app/Exceptions/ServiceUnavailable.php @@ -0,0 +1,8 @@ +isNotSafeRequest()) { - if (!$this->checkHttpReferer() || !$this->checkCsrfToken()) { - $dispatcher->forward([ - 'controller' => 'public', - 'action' => 'robot', - ]); - return false; - } + $this->checkHttpReferer(); + $this->checkCsrfToken(); } + $this->checkRateLimit(); + $this->authUser = $this->getAuthUser(); if (!$this->authUser) { diff --git a/app/Http/Admin/Controllers/PublicController.php b/app/Http/Admin/Controllers/PublicController.php index c5f1ad41..ececdd1d 100644 --- a/app/Http/Admin/Controllers/PublicController.php +++ b/app/Http/Admin/Controllers/PublicController.php @@ -26,18 +26,6 @@ class PublicController extends \Phalcon\Mvc\Controller $this->response->redirect(['for' => 'admin.login']); } - /** - * @Route("/robot", name="admin.robot") - */ - public function robotAction() - { - $isAjaxRequest = is_ajax_request(); - - if ($isAjaxRequest) { - return $this->jsonError(['msg' => '疑似机器人请求']); - } - } - /** * @Route("/forbidden", name="admin.forbidden") */ diff --git a/app/Http/Admin/Controllers/SessionController.php b/app/Http/Admin/Controllers/SessionController.php index 97536ff0..61f4e5fa 100644 --- a/app/Http/Admin/Controllers/SessionController.php +++ b/app/Http/Admin/Controllers/SessionController.php @@ -13,8 +13,7 @@ use App\Traits\Security as SecurityTrait; class SessionController extends \Phalcon\Mvc\Controller { - use ResponseTrait; - use SecurityTrait; + use ResponseTrait, SecurityTrait; /** * @Route("/login", name="admin.login") @@ -23,13 +22,8 @@ class SessionController extends \Phalcon\Mvc\Controller { if ($this->request->isPost()) { - if (!$this->checkHttpReferer() || !$this->checkCsrfToken()) { - $this->dispatcher->forward([ - 'controller' => 'public', - 'action' => 'robot', - ]); - return false; - } + $this->checkHttpReferer(); + $this->checkCsrfToken(); $sessionService = new SessionService(); diff --git a/app/Http/Admin/Views/package/guiding.volt b/app/Http/Admin/Views/package/guiding.volt index ec20d922..d6c100be 100644 --- a/app/Http/Admin/Views/package/guiding.volt +++ b/app/Http/Admin/Views/package/guiding.volt @@ -20,7 +20,7 @@
市场价:¥{{ item.market_price }}
会员价:¥{{ item.vip_price }}
diff --git a/app/Http/Api/Controllers/Controller.php b/app/Http/Api/Controllers/Controller.php index cf0197b0..061831cc 100644 --- a/app/Http/Api/Controllers/Controller.php +++ b/app/Http/Api/Controllers/Controller.php @@ -13,13 +13,7 @@ class Controller extends \Phalcon\Mvc\Controller public function beforeExecuteRoute(Dispatcher $dispatcher) { - if (!$this->checkRateLimit()) { - $dispatcher->forward([ - 'controller' => 'public', - 'action' => 'throttle', - ]); - return false; - } + $this->checkRateLimit(); } } diff --git a/app/Http/Api/Controllers/PublicController.php b/app/Http/Api/Controllers/PublicController.php index 0383d387..f2f0a85c 100644 --- a/app/Http/Api/Controllers/PublicController.php +++ b/app/Http/Api/Controllers/PublicController.php @@ -12,12 +12,4 @@ class PublicController extends \Phalcon\Mvc\Controller use ResponseTrait; - /** - * @Get("/throttle", name="api.throttle") - */ - public function throttleAction() - { - return $this->jsonError(['msg' => '请求过于频繁']); - } - } diff --git a/app/Http/Html5/Controllers/Controller.php b/app/Http/Html5/Controllers/Controller.php index a7d35aba..9314420f 100644 --- a/app/Http/Html5/Controllers/Controller.php +++ b/app/Http/Html5/Controllers/Controller.php @@ -13,13 +13,7 @@ class Controller extends \Phalcon\Mvc\Controller public function beforeExecuteRoute(Dispatcher $dispatcher) { - if (!$this->checkRateLimit()) { - $dispatcher->forward([ - 'controller' => 'public', - 'action' => 'throttle', - ]); - return false; - } + $this->checkRateLimit(); } } diff --git a/app/Http/Html5/Controllers/PublicController.php b/app/Http/Html5/Controllers/PublicController.php index 6aaf6fa2..576ee842 100644 --- a/app/Http/Html5/Controllers/PublicController.php +++ b/app/Http/Html5/Controllers/PublicController.php @@ -12,12 +12,4 @@ class PublicController extends \Phalcon\Mvc\Controller use ResponseTrait; - /** - * @Get("/throttle", name="html5.throttle") - */ - public function throttleAction() - { - return $this->jsonError(['msg' => '请求过于频繁']); - } - } diff --git a/app/Http/Web/Controllers/Controller.php b/app/Http/Web/Controllers/Controller.php index 1fee24b3..bc60757a 100644 --- a/app/Http/Web/Controllers/Controller.php +++ b/app/Http/Web/Controllers/Controller.php @@ -20,23 +20,12 @@ class Controller extends \Phalcon\Mvc\Controller public function beforeExecuteRoute(Dispatcher $dispatcher) { - if (!$this->checkRateLimit()) { - $dispatcher->forward([ - 'controller' => 'public', - 'action' => 'throttle', - ]); - return false; + if ($this->isNotSafeRequest()) { + $this->checkHttpReferer(); + $this->checkCsrfToken(); } - if ($this->isNotSafeRequest()) { - if (!$this->checkHttpReferer() || !$this->checkCsrfToken()) { - $dispatcher->forward([ - 'controller' => 'public', - 'action' => 'robot', - ]); - return false; - } - } + $this->checkRateLimit(); $this->siteSettings = $this->getSiteSettings(); $this->navList = $this->getNavList(); diff --git a/app/Http/Web/Controllers/ErrorController.php b/app/Http/Web/Controllers/ErrorController.php index 00c38ea5..57597cdd 100644 --- a/app/Http/Web/Controllers/ErrorController.php +++ b/app/Http/Web/Controllers/ErrorController.php @@ -53,7 +53,7 @@ class ErrorController extends \Phalcon\Mvc\Controller $isAjaxRequest = is_ajax_request(); if ($isAjaxRequest || $isApiRequest) { - return $this->jsonError(['code' => 'sys.uri_not_found']); + return $this->jsonError(['code' => 'sys.not_found']); } } @@ -65,4 +65,12 @@ class ErrorController extends \Phalcon\Mvc\Controller $this->response->setStatusCode(500); } + /** + * @Get("/503", name="web.error.503") + */ + public function show503Action() + { + $this->response->setStatusCode(503); + } + } diff --git a/app/Http/Web/Controllers/PublicController.php b/app/Http/Web/Controllers/PublicController.php index 60773bf9..b65bb02f 100644 --- a/app/Http/Web/Controllers/PublicController.php +++ b/app/Http/Web/Controllers/PublicController.php @@ -12,56 +12,6 @@ class PublicController extends \Phalcon\Mvc\Controller use ResponseTrait; - /** - * @Route("/auth", name="web.auth") - */ - public function authAction() - { - $isAjaxRequest = is_ajax_request(); - - if ($isAjaxRequest) { - return $this->jsonError(['msg' => '会话已过期,请重新登录']); - } - - $this->response->redirect(['for' => 'web.login']); - } - - /** - * @Route("/robot", name="web.robot") - */ - public function robotAction() - { - $isAjaxRequest = is_ajax_request(); - - if ($isAjaxRequest) { - return $this->jsonError(['msg' => '疑似机器人请求']); - } - } - - /** - * @Route("/forbidden", name="web.forbidden") - */ - public function forbiddenAction() - { - $isAjaxRequest = is_ajax_request(); - - if ($isAjaxRequest) { - return $this->jsonError(['msg' => '无相关操作权限']); - } - } - - /** - * @Get("/throttle", name="web.throttle") - */ - public function throttleAction() - { - $isAjaxRequest = is_ajax_request(); - - if ($isAjaxRequest) { - return $this->jsonError(['msg' => 'web请求过于频繁']); - } - } - /** * @Get("/content/img/{id:[0-9]+}", name="web.content.img") */ diff --git a/app/Traits/Security.php b/app/Traits/Security.php index 9c9709cb..cb8a86e4 100644 --- a/app/Traits/Security.php +++ b/app/Traits/Security.php @@ -2,7 +2,7 @@ namespace App\Traits; -use App\Services\Throttle; +use App\Validators\Security as SecurityValidator; use Phalcon\Di; use Phalcon\Http\Request; @@ -11,39 +11,23 @@ trait Security public function checkCsrfToken() { - /** - * @var Request $request - */ - $request = Di::getDefault()->get('request'); + $validator = new SecurityValidator(); - $tokenKey = $request->getHeader('X-Csrf-Token-Key'); - $tokenValue = $request->getHeader('X-Csrf-Token-Value'); - - /** - * @var \App\Library\Security $security - */ - $security = Di::getDefault()->get('security'); - - return $security->checkToken($tokenKey, $tokenValue); + $validator->checkCsrfToken(); } public function checkHttpReferer() { - /** - * @var Request $request - */ - $request = Di::getDefault()->get('request'); + $validator = new SecurityValidator(); - $httpHost = parse_url($request->getHttpReferer(), PHP_URL_HOST); - - return $httpHost == $request->getHttpHost(); + $validator->checkHttpReferer(); } public function checkRateLimit() { - $throttle = new Throttle(); + $validator = new SecurityValidator(); - return $throttle->checkRateLimit(); + $validator->checkRateLimit(); } public function isNotSafeRequest() diff --git a/app/Validators/Account.php b/app/Validators/Account.php index 740a7a55..96c8c9dc 100644 --- a/app/Validators/Account.php +++ b/app/Validators/Account.php @@ -123,7 +123,7 @@ class Account extends Validator $user = $this->checkUserLogin($name, $password); if ($user->admin_role == 0) { - throw new ForbiddenException('sys.access_denied'); + throw new ForbiddenException('sys.forbidden'); } return $user; diff --git a/app/Validators/Security.php b/app/Validators/Security.php index a030bb37..aea0f860 100644 --- a/app/Validators/Security.php +++ b/app/Validators/Security.php @@ -3,13 +3,49 @@ namespace App\Validators; use App\Exceptions\BadRequest as BadRequestException; +use App\Exceptions\ServiceUnavailable as ServiceUnavailableException; use App\Library\Validator\Common as CommonValidator; use App\Services\Captcha as CaptchaService; +use App\Services\Throttle as ThrottleService; use App\Services\VerifyCode as VerifyCodeService; class Security extends Validator { + public function checkCsrfToken() + { + $tokenKey = $this->request->getHeader('X-Csrf-Token-Key'); + $tokenValue = $this->request->getHeader('X-Csrf-Token-Value'); + + $result = $this->security->checkToken($tokenKey, $tokenValue); + + if (!$result) { + throw new BadRequestException('security.invalid_csrf_token'); + } + } + + public function checkHttpReferer() + { + $httpHost = parse_url($this->request->getHttpReferer(), PHP_URL_HOST); + + $result = $httpHost == $this->request->getHttpHost(); + + if (!$result) { + throw new BadRequestException('security.invalid_http_referer'); + } + } + + public function checkRateLimit() + { + $throttleService = new ThrottleService(); + + $result = $throttleService->checkRateLimit(); + + if (!$result) { + throw new ServiceUnavailableException('security.too_many_requests'); + } + } + public function checkVerifyCode($key, $code) { $verifyCodeService = new VerifyCodeService(); diff --git a/app/Validators/Validator.php b/app/Validators/Validator.php index 77348a08..99f95dba 100644 --- a/app/Validators/Validator.php +++ b/app/Validators/Validator.php @@ -12,14 +12,14 @@ class Validator extends Component public function checkAuthUser($authUser) { if (empty($authUser['id'])) { - throw new UnauthorizedException('sys.auth_failed'); + throw new UnauthorizedException('sys.unauthorized'); } } public function checkOwner($userId, $ownerId) { if ($userId != $ownerId) { - throw new ForbiddenException('sys.access_denied'); + throw new ForbiddenException('sys.forbidden'); } } diff --git a/bootstrap/HttpErrorHandler.php b/bootstrap/HttpErrorHandler.php index 1e59660c..96ff74f1 100644 --- a/bootstrap/HttpErrorHandler.php +++ b/bootstrap/HttpErrorHandler.php @@ -5,6 +5,7 @@ namespace Bootstrap; use App\Exceptions\BadRequest as BadRequestException; use App\Exceptions\Forbidden as ForbiddenException; use App\Exceptions\NotFound as NotFoundException; +use App\Exceptions\ServiceUnavailable as ServiceUnavailableException; use App\Exceptions\Unauthorized as UnauthorizedException; use App\Library\Logger as AppLogger; use Phalcon\Mvc\User\Component; @@ -60,6 +61,8 @@ class HttpErrorHandler extends Component $this->response->setStatusCode(403); } elseif ($e instanceof NotFoundException) { $this->response->setStatusCode(404); + } elseif ($e instanceof ServiceUnavailableException) { + $this->response->setStatusCode(503); } else { $this->response->setStatusCode(500); } diff --git a/config/errors.php b/config/errors.php index 190bbd0e..c0d0dfd0 100644 --- a/config/errors.php +++ b/config/errors.php @@ -3,17 +3,22 @@ $error = []; /** - * 通用相关 + * 系统相关 */ -$error['sys.uri_not_found'] = '资源地址不存在'; -$error['sys.invalid_referer'] = '非法的请求来源'; -$error['sys.auth_failed'] = '认证失败'; -$error['sys.access_denied'] = '拒绝访问'; +$error['sys.unauthorized'] = '认证失败'; +$error['sys.forbidden'] = '拒绝访问'; +$error['sys.bad_request'] = '无效的请求'; +$error['sys.not_found'] = '资源不存在'; +$error['sys.internal_server_error'] = '内部错误'; +$error['sys.service_unavailable'] = '服务不可用'; $error['sys.unknown_error'] = '未知错误'; /** * 安全相关 */ +$error['security.too_many_requests'] = '请求过于频繁'; +$error['security.invalid_csrf_token'] = '无效的CSRF令牌'; +$error['security.invalid_http_referer'] = '无效请求来源'; $error['security.invalid_captcha_code'] = '无效的验证码'; $error['security.invalid_verify_code'] = '无效的验证码';