BaseController.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. namespace pt\controllers;
  3. use bizHd\saas\services\StaffService;
  4. use common\components\jwt;
  5. use common\components\util;
  6. use Yii;
  7. class BaseController extends PublicController
  8. {
  9. public $staff, $staffId;
  10. public $isLogin = false;
  11. public $guestAccess = [];//不需要登陆的方法名
  12. public $validate = true;
  13. public function beforeAction($action)
  14. {
  15. // 新增:全局安全检查
  16. $this->securityCheck();
  17. //6表示总后台
  18. Yii::$app->params['ptStyle'] = 6;
  19. $staffId = jwt::getLoginId();
  20. if (empty($staffId)) {
  21. $this->validate = false;
  22. }
  23. //临时开放花材管理权限给商家
  24. $limitId = 4;
  25. if (getenv('YII_ENV') == 'production') {
  26. $limitId = 2;
  27. }
  28. if ($staffId == $limitId) {
  29. $currentRoute = $this->id . '/' . $action->id;
  30. $arr = [
  31. 'staff/login-detail',
  32. 'item/list',
  33. 'item-class/list',
  34. 'item-class/get-all-class',
  35. 'unit/get-all-unit',
  36. 'upload/save-img',
  37. 'item/add',
  38. ];
  39. if (in_array($currentRoute, $arr) == false) {
  40. util::fail('没有找到资源');
  41. }
  42. }
  43. //游客可以访问的方法
  44. if (in_array($action->id, $this->guestAccess)) {
  45. $this->validate = true;
  46. } else {
  47. $staff = StaffService::getById($staffId, true);
  48. if (empty($staff)) {
  49. util::logout();
  50. }
  51. if ($staff->status == 0) {
  52. util::logout("账号已冻结");
  53. }
  54. $this->staff = $staff;
  55. }
  56. if ($this->validate == false) {
  57. util::notLogin();
  58. }
  59. $this->staffId = $staffId;
  60. return parent::beforeAction($action);
  61. }
  62. /**
  63. * 全局安全检查
  64. */
  65. protected function securityCheck()
  66. {
  67. $request = Yii::$app->request;
  68. $this->checkSuspiciousParameters($request);
  69. $this->checkFileUploadSecurity($request);
  70. $this->checkSqlInjection($request);
  71. $this->checkXssAttack($request);
  72. $this->logSecurityActivity($request);
  73. }
  74. /**
  75. * 检查可疑参数
  76. */
  77. protected function checkSuspiciousParameters($request)
  78. {
  79. $dangerousPatterns = [
  80. // 代码执行相关
  81. '/eval\s*\(/i',
  82. '/exec\s*\(/i',
  83. '/system\s*\(/i',
  84. '/passthru\s*\(/i',
  85. '/shell_exec\s*\(/i',
  86. '/proc_open\s*\(/i',
  87. '/popen\s*\(/i',
  88. // 文件操作相关
  89. '/file_put_contents\s*\(/i',
  90. '/file_get_contents\s*\(/i',
  91. '/fwrite\s*\(/i',
  92. '/fopen\s*\(/i',
  93. // 目录遍历
  94. '/\.\.\//',
  95. '/\.\.\\\/',
  96. // 模板注入
  97. '/<\?php/i',
  98. '/<\?=/i',
  99. '/<\?/i',
  100. // 序列化攻击
  101. '/O:\d+:/',
  102. '/a:\d+:/',
  103. '/s:\d+:/',
  104. ];
  105. foreach (['get', 'post'] as $method) {
  106. $params = $request->$method();
  107. foreach ($params as $key => $value) {
  108. if (is_string($value)) {
  109. foreach ($dangerousPatterns as $pattern) {
  110. if (preg_match($pattern, $value)) {
  111. $this->logSecurityViolation($request, "Dangerous pattern detected: $pattern in $key");
  112. throw new \yii\web\HttpException(403, 'Access denied');
  113. }
  114. }
  115. }
  116. }
  117. }
  118. }
  119. /**
  120. * 检查文件上传安全
  121. */
  122. protected function checkFileUploadSecurity($request)
  123. {
  124. if (!empty($_FILES)) {
  125. foreach ($_FILES as $file) {
  126. if (isset($file['name'])) {
  127. $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
  128. $allowed = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'];
  129. if (!in_array($ext, $allowed)) {
  130. $this->logSecurityViolation($request, "Illegal file upload: " . $file['name']);
  131. throw new \yii\web\HttpException(403, 'Illegal file type');
  132. }
  133. }
  134. }
  135. }
  136. }
  137. /**
  138. * 检查SQL注入
  139. */
  140. protected function checkSqlInjection($request)
  141. {
  142. $sqlPatterns = [
  143. '/select\s.+\sfrom/i',
  144. '/union\s+select/i',
  145. '/insert\s+into/i',
  146. '/update\s.+\sset/i',
  147. '/delete\s+from/i',
  148. '/drop\s+table/i',
  149. '/--/',
  150. '/\bOR\b.+\=/i',
  151. ];
  152. foreach (['get', 'post'] as $method) {
  153. $params = $request->$method();
  154. foreach ($params as $key => $value) {
  155. if (is_string($value)) {
  156. foreach ($sqlPatterns as $pattern) {
  157. if (preg_match($pattern, $value)) {
  158. $this->logSecurityViolation($request, "SQL injection pattern: $pattern in $key");
  159. throw new \yii\web\HttpException(403, 'Access denied');
  160. }
  161. }
  162. }
  163. }
  164. }
  165. }
  166. /**
  167. * 检查XSS攻击
  168. */
  169. protected function checkXssAttack($request)
  170. {
  171. $xssPatterns = [
  172. '/<script\b[^>]*>(.*?)<\/script>/is',
  173. '/on\w+\s*=/i',
  174. '/javascript:/i',
  175. '/<iframe/i',
  176. '/<img/i',
  177. ];
  178. foreach (['get', 'post'] as $method) {
  179. $params = $request->$method();
  180. foreach ($params as $key => $value) {
  181. if (is_string($value)) {
  182. foreach ($xssPatterns as $pattern) {
  183. if (preg_match($pattern, $value)) {
  184. $this->logSecurityViolation($request, "XSS pattern: $pattern in $key");
  185. throw new \yii\web\HttpException(403, 'Access denied');
  186. }
  187. }
  188. }
  189. }
  190. }
  191. }
  192. /**
  193. * 记录安全日志
  194. */
  195. protected function logSecurityActivity($request)
  196. {
  197. $log = [
  198. 'time' => date('Y-m-d H:i:s'),
  199. 'ip' => $request->userIP,
  200. 'url' => $request->url,
  201. 'get' => $request->get(),
  202. 'post' => $request->post(),
  203. 'user_agent' => $request->userAgent,
  204. ];
  205. file_put_contents(
  206. Yii::getAlias('@runtime/logs/security_activity.log'),
  207. json_encode($log, JSON_UNESCAPED_UNICODE) . "\n",
  208. FILE_APPEND
  209. );
  210. }
  211. /**
  212. * 记录安全违规日志
  213. */
  214. protected function logSecurityViolation($request, $reason)
  215. {
  216. $log = [
  217. 'time' => date('Y-m-d H:i:s'),
  218. 'ip' => $request->userIP,
  219. 'url' => $request->url,
  220. 'get' => $request->get(),
  221. 'post' => $request->post(),
  222. 'user_agent' => $request->userAgent,
  223. 'reason' => $reason,
  224. ];
  225. file_put_contents(
  226. Yii::getAlias('@runtime/logs/security_violation.log'),
  227. json_encode($log, JSON_UNESCAPED_UNICODE) . "\n",
  228. FILE_APPEND
  229. );
  230. }
  231. }