Prechádzať zdrojové kódy

增加sql注入拦截,页面测试关键字注入

xusl 1 rok pred
rodič
commit
1dc4398923

+ 14 - 7
backend/src/main/java/com/jiayue/ssi/config/WebSecurityConfig.java

@@ -44,13 +44,16 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     CustomLogoutSuccessHandler customLogoutSuccessHandler;
     @Autowired
     JwtTokenUtil jwtTokenUtil;
-    @Autowired
-    XssEscapeFilter xssEscapeFilter;
-    @Autowired
-    XssKeywordsFilter xssKeywordsFilter;
+//    @Autowired
+//    XssEscapeFilter xssEscapeFilter;
+//    @Autowired
+//    XssKeywordsFilter xssKeywordsFilter;
+//    @Autowired
+//    SqlFilter sqlFilter;
     @Autowired
     InterfaceLimitFilter interfaceLimitFilter;
 
+
     @Bean
     public MyAuthenticationProvider eacpsAuthenticationProvider(){
         MyAuthenticationProvider myAuthenticationProvider = new MyAuthenticationProvider();
@@ -76,14 +79,18 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
     @Override
     protected void configure(HttpSecurity httpSecurity) throws Exception {
         httpSecurity.addFilterBefore(interfaceLimitFilter, LogoutFilter.class);
-        httpSecurity.addFilterBefore(xssKeywordsFilter, LogoutFilter.class);
-        httpSecurity.addFilterBefore(xssEscapeFilter, LogoutFilter.class);
+//
+//        httpSecurity.addFilterBefore(xssEscapeFilter, LogoutFilter.class);
+//        httpSecurity.addFilterBefore(sqlFilter, LogoutFilter.class);
         httpSecurity.addFilterBefore(new VerifySmFilter(), LogoutFilter.class);
+        httpSecurity.addFilterBefore(new XssKeywordsFilter(), LogoutFilter.class);
+        httpSecurity.addFilterBefore(new XssEscapeFilter(), LogoutFilter.class);
+        httpSecurity.addFilterBefore(new SqlFilter(), LogoutFilter.class);
         httpSecurity.addFilterBefore(new VerifyCodeFilter(), LogoutFilter.class);
         httpSecurity.addFilterBefore(new MailCodeFilter(), LogoutFilter.class);
         httpSecurity.addFilterBefore(new JwtAuthenticationTokenFilter(userServiceImpl, jwtTokenUtil), LogoutFilter.class);
         httpSecurity.headers().frameOptions().disable();
-//        httpSecurity.headers().httpStrictTransportSecurity().includeSubDomains(true).preload(true).maxAgeInSeconds(31536000);
+        httpSecurity.headers().httpStrictTransportSecurity().includeSubDomains(true).preload(true).maxAgeInSeconds(31536000);
         httpSecurity
                 // 由于使用的是JWT,我们这里不需要csrf
                 .csrf().disable()

+ 21 - 18
backend/src/main/java/com/jiayue/ssi/filter/InterfaceLimitFilter.java

@@ -37,33 +37,36 @@ public class InterfaceLimitFilter extends OncePerRequestFilter {
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
         throws ServletException, IOException {
+        checkIp(request,response,filterChain);
+    }
+
+    synchronized void checkIp(HttpServletRequest request,HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{
         String remoteIp = IPUtils.getIpAddr(request);
         if (CacheConstants.blacklistMap.get(remoteIp)!=null){
+            log.info(remoteIp+"进入黑名单进行拦截!");
             response.setHeader("Access-Control-Allow-Origin", "*");
             response.setStatus(410);
             response.setContentType("text/html;charset=utf-8");
             response.getWriter().write("IP已进黑名单,请联系管理员!");
             return;
         }
-        else{
-            if (!InterfaceLimitUtil.checkInterface(request, 1000, 10)) {
-                log.info("接口拦截:{} 请求超过限制频率【{}次/{}ms】,IP为{}", request.getRequestURI(), 10,1000, remoteIp);
-                // 锁定ip黑名单
-                SysBlacklist sysBlacklist = new SysBlacklist();
-                sysBlacklist.setIp(remoteIp);
-                sysBlacklist.setIpTime(new Date());
-                sysBlacklist.setAddBy("SYSTEM");
-                SpringUtils.getBean(SysBlacklistService.class).save(sysBlacklist);
-                // 将锁定ip加入缓存
-                CacheConstants.blacklistMap.put(remoteIp,sysBlacklist.getId());
+        if (!InterfaceLimitUtil.checkInterface(request, 1000, 10)) {
+            log.info("接口拦截:{} 请求超过限制频率【{}次/{}ms】,IP为{}", request.getRequestURI(), 10,1000, remoteIp);
+            // 锁定ip黑名单
+            SysBlacklist sysBlacklist = new SysBlacklist();
+            sysBlacklist.setIp(remoteIp);
+            sysBlacklist.setIpTime(new Date());
+            sysBlacklist.setAddBy("SYSTEM");
+            SpringUtils.getBean(SysBlacklistService.class).save(sysBlacklist);
+            // 将锁定ip加入缓存
+            CacheConstants.blacklistMap.put(remoteIp,sysBlacklist.getId());
 
-                response.setHeader("Access-Control-Allow-Origin", "*");
-                response.setStatus(410);
-                response.setContentType("text/html;charset=utf-8");
-                response.getWriter().write("IP已进黑名单,请联系管理员!");
-                return;
-            }
-            filterChain.doFilter(request, response);
+            response.setHeader("Access-Control-Allow-Origin", "*");
+            response.setStatus(410);
+            response.setContentType("text/html;charset=utf-8");
+            response.getWriter().write("IP已进黑名单,请联系管理员!");
+            return;
         }
+        filterChain.doFilter(request, response);
     }
 }

+ 1 - 1
backend/src/main/java/com/jiayue/ssi/filter/MailCodeFilter.java

@@ -26,7 +26,7 @@ import lombok.RequiredArgsConstructor;
 * @since 2023/02/20
 */
 @RequiredArgsConstructor
-@Order(6)
+@Order(8)
 public class MailCodeFilter extends OncePerRequestFilter {
     private String defaultFilterProcessUrl = "/user/login";
 

+ 64 - 0
backend/src/main/java/com/jiayue/ssi/filter/SqlFilter.java

@@ -0,0 +1,64 @@
+package com.jiayue.ssi.filter;
+
+import com.jiayue.ssi.util.IPUtils;
+import com.jiayue.ssi.util.ResponseInfo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+* 防sql注入
+*
+* @author xsl
+* @since 2023/05/19
+*/
+//@RequiredArgsConstructor
+//@Order(4)
+//@Slf4j
+//@Component
+@Order(6)
+@Slf4j
+public class SqlFilter  extends OncePerRequestFilter {
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+        //获得所有请求参数名
+        Enumeration<String> names = request.getParameterNames();
+        while (names.hasMoreElements()){
+            //得到参数名
+            String name = names.nextElement().toString();
+            //得到参数对应值
+            String[] values = request.getParameterValues(name);
+            for (int i = 0; i < values.length; i++) {
+                if (sqlValidate(values[i])){
+                    ResponseInfo.doResponse(response, "请求中的参数中含有非法字符!", 401);
+                    return;
+                }
+            }
+        }
+        filterChain.doFilter(request,response);
+    }
+    //效验
+    protected static boolean sqlValidate(String str){
+        String s = str.toLowerCase();//统一转为小写
+        String badStr =
+                "select|update|and|or|delete|insert|truncate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|table|"+
+                        "char|declare|sitename|xp_cmdshell|like|from|grant|use|group_concat|column_name|" +
+                        "information_schema.columns|table_schema|union|where|order|by|" +
+                        "'\\*|\\;|\\-|\\--|\\+|\\,|\\//|\\/|\\%|\\#";//过滤掉的sql关键字,特殊字符前面需要加\\进行转义
+        String regx = ".*(\\b(exec|execute|insert|into|create|drop|table|from|grant|group_concat|column_name|" +
+                "information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|" +
+                "chr|mid|master|truncate|char|declare|or|like)\\b).*";
+        //使用正则表达式进行匹配
+        boolean matches = s.matches(regx);
+        return matches;
+    }
+}

+ 1 - 1
backend/src/main/java/com/jiayue/ssi/filter/VerifyCodeFilter.java

@@ -26,7 +26,7 @@ import lombok.RequiredArgsConstructor;
 * @since 2023/02/20
 */
 @RequiredArgsConstructor
-@Order(5)
+@Order(7)
 public class VerifyCodeFilter extends OncePerRequestFilter {
     private String defaultFilterProcessUrl = "/user/login";
 

+ 8 - 7
backend/src/main/java/com/jiayue/ssi/filter/VerifySmFilter.java

@@ -29,7 +29,7 @@ import java.util.Map;
  * @author xsl
  * @since 2023/02/27
  */
-@Order(4)
+@Order(3)
 @Slf4j
 public class VerifySmFilter extends OncePerRequestFilter {
     private String defaultFilterProcessUrl = "/user/login";
@@ -41,7 +41,8 @@ public class VerifySmFilter extends OncePerRequestFilter {
             ParameterRequestWrapper initWrapper = new ParameterRequestWrapper(request);
             // 不是登录操作
             if (!("POST".equalsIgnoreCase(request.getMethod())
-                && defaultFilterProcessUrl.equals(request.getServletPath()))) {
+                && defaultFilterProcessUrl.equals(request.getServletPath())) && !("/getVerifyCode".equals(request.getServletPath()))
+                    && !("/sysParameterController/getUseSendMail".equals(request.getServletPath())) && !("/getMailCode".equals(request.getServletPath()))) {
                 // 验证token
                 String tokenStr = request.getHeader("Authorization");
                 if (StringUtils.isNotEmpty(tokenStr)) {
@@ -142,14 +143,14 @@ public class VerifySmFilter extends OncePerRequestFilter {
                 // get请求无参数,取出是null
                 String get_sm2Str = request.getParameter("0");
                 if (StringUtils.isNotEmpty(get_sm2Str)) {
-                    String[] tempStr = get_sm2Str.split("&");
                     Map<String, String> tempMap = new HashMap(16);
-                    for (int i = 0; i < tempStr.length; i++) {
-                        String[] fieldStr = tempStr[i].split("=");
-                        tempMap.put(fieldStr[0], fieldStr[1]);
-                    }
                     // 对加密串解密验签
                     try {
+                        String[] tempStr = get_sm2Str.replaceAll("&","&").split("&");
+                        for (int i = 0; i < tempStr.length; i++) {
+                            String[] fieldStr = tempStr[i].split("=");
+                            tempMap.put(fieldStr[0], fieldStr[1]);
+                        }
                         decryptStr =
                             SM2CryptUtils.decrypt(tempMap.get("secretData"), SecretKeyConstants.SERVER_PRIVATE_KEY);
                     } catch (Exception e) {

+ 5 - 4
backend/src/main/java/com/jiayue/ssi/filter/XssEscapeFilter.java

@@ -18,10 +18,12 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 //拦截请求
-@RequiredArgsConstructor
-@Order(3)
+//@RequiredArgsConstructor
+//@Order(3)
+//@Slf4j
+//@Component
+@Order(5)
 @Slf4j
-@Component
 public class XssEscapeFilter extends OncePerRequestFilter {
 
     @Override
@@ -31,7 +33,6 @@ public class XssEscapeFilter extends OncePerRequestFilter {
             XssEscapeHttpServletRequestWrapper wrapper = new XssEscapeHttpServletRequestWrapper(request);
             filterChain.doFilter(wrapper, response);
         } catch (Exception e) {
-            log.error(IPUtils.getIpAddr(request) + "访问系统失败", e);
             ResponseInfo.doResponse(response, "访问失败,联系管理员!", 401);
             return;
         }

+ 6 - 19
backend/src/main/java/com/jiayue/ssi/filter/XssKeywordsFilter.java

@@ -21,30 +21,17 @@ import java.io.IOException;
  * @author xsl
  * @since 2023/05/16
  */
-@RequiredArgsConstructor
-@Order(2)
+//@RequiredArgsConstructor
+//@Order(2)
+//@Slf4j
+//@Component
+
+@Order(4)
 @Slf4j
-@Component
 public class XssKeywordsFilter extends OncePerRequestFilter {
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
         try {
-            //跨域设置
-//        if(servletResponse instanceof HttpServletResponse){
-//            HttpServletResponse httpServletResponse=(HttpServletResponse)servletResponse;
-//            //通过在响应 header 中设置 ‘*’ 来允许来自所有域的跨域请求访问。
-//            httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
-//            //通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
-//            //设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
-//            //httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true");
-//            //请求方式
-//            httpServletResponse.setHeader("Access-Control-Allow-Methods", "*");
-//            //(预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久
-//            httpServletResponse.setHeader("Access-Control-Max-Age", "86400");
-//            //首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段
-//            httpServletResponse.setHeader("Access-Control-Allow-Headers", "*");
-//        }
-
             XssKeywordsHttpServletRequestWrapper xssRequest = new XssKeywordsHttpServletRequestWrapper(request);
 //            String method = request.getMethod();
 //

+ 6 - 2
backend/src/main/java/com/jiayue/ssi/servlet/XssKeywordsHttpServletRequestWrapper.java

@@ -29,13 +29,17 @@ public class XssKeywordsHttpServletRequestWrapper extends HttpServletRequestWrap
     private Set<String> notAllowedKeyWords = new HashSet<String>(0);
 
     HttpServletRequest orgRequest = null;
-    private Map<String, String[]> parameterMap;
+    private Map<String, String[]> parameterMap = new HashMap<>();
     private final byte[] body; //用于保存读取body中数据
 
     public XssKeywordsHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
         super(request);
         orgRequest = request;
-        parameterMap = request.getParameterMap();
+        Enumeration enu=request.getParameterNames();
+        while(enu.hasMoreElements()){
+            String paraName=(String)enu.nextElement();
+            parameterMap.put(paraName,new String[]{request.getParameter(paraName)});
+        }
         body = StreamUtils.copyToByteArray(request.getInputStream());
 
         String keyStr[] = key.split("\\|");

+ 1 - 1
ui/src/utils/request.js

@@ -18,7 +18,7 @@ service.interceptors.request.use(
     const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
     // get请求映射params参数
     if (config.method === 'get' && config.params) {
-      if (config.params.toString().indexOf('secretData') !=-1 && config.params.toString().indexOf('paramSign')){
+      if (config.params.toString().indexOf('secretData') ==-1 && config.params.toString().indexOf('paramSign')==-1){
         // 不是token刷新后执行上次操作,进行参数加密。
         let encryptParam = doEncrypt(JSON.stringify(config.params))
         // 参数签名

+ 0 - 1
ui/src/views/monitor/server/index.vue

@@ -320,7 +320,6 @@ export default {
     /** 查询服务器信息 */
     getList() {
       getServer().then(response => {
-        console.log(response.data)
         this.server = response.data;
         // this.$modal.closeLoading();
       });