通知:博客已搬家到CSDN地址為:
https://blog.csdn.net/hdp134793
用戶越權訪問的處理
一般來說,越權放問就好比你是非系統管理員用戶,卻偷偷的跑進了系統管理菜單,僭越權利訪問里面的信息甚至修改其中的數據(不同級別的越權又稱垂直越權訪問),因此對數據的安全性造成極大的威脅,是故每家企業都有其方法來保證企業內部數據的安全性,也就是解決越權訪問的問題。
有關改業務處理主要考慮下面兩個方面:
url的越權訪問和接口方法的越權訪問
- 通過角色用戶來判斷是否越權訪問
分下面幾種情況來討論:
a.當沒有用戶登錄的時候:
只允許登錄界面和一些js,css等非jsp/html的頁面訪問,這樣算是越權
b.當用戶登錄了之后:
首先通過角色關系去數據庫中查找他能夠訪問的頁面,這樣的話就可以針對能訪問的做一個放行處理,非權限內的頁面屬於越權,這個時候攔截掉,可以直接讓其跳轉到登陸界面表示他越權了已經(自行處理越權后的操作)。
2.具體實現流程
a.統計好每個菜單url對應的接口方法和子頁面訪問路徑(jsp或html等)
b.將統計好的數據一一對應起來,存放在配置文件中或者數據庫某個表中,這些數據隨着業務的新增或者裁剪應有相關對應的維護,暫時以配置文件為例
c.在登錄模塊中通過登錄的用戶角色查找它能夠訪問的菜單URL(寫一個接口方法),存放在一個靜態公有list變量中,如下定義:
public static List<String> MENU_URLS = new ArrayList<>();
將查詢返回過來的url集合塞給MENU_URLS。
d,定義一個靜態公有Properties變量,用來存放配置文件中的鍵值對,如下定義:
public static Properties MENU_INTERFACE = null;
然后對其進行讀取配置文件並賦值
String url = request.getSession().getServletContext().getRealPath("/WEB-INF/classes/porturl.properties"); File file = new File(url); try { MENU_INTERFACE = new Properties(); FileInputStream inStream = new FileInputStream(file); MENU_INTERFACE.load(inStream); } catch (Exception e) { System.out.println(e); }
e.SpringMVC攔截器,判斷session中用戶是否過期,在doFilter 方法里匹配,只要js,css,pdf,png,jpg等文件可放行,在里面判斷用戶是否登錄,沒有登錄的話只要是非登錄頁面的頁面,統一視為越權訪問。如果是已經登錄的用戶,我們可以取到登錄后的MENU_URLS 和 MENU_INTERFACE 的信息,可以做如下判斷:
如果訪問的路徑checkURL和MENU_URLS 中的任意子串能匹配的上的話說明是可以訪問的,這種情況放行,否則攔截下來跳轉登錄,記錄越權訪問信息;
在上面的情況下,還會存在一種情況,當訪問的路徑是子頁面的時候,這個時候需要去匹配,能匹配上的可以放行,這個需要通過checkURL去配置文件中找到對應的父URL,然后再進行匹配MENU_URLS,這個里面的父URL是唯一的,配置文件中一(父)對多(子)。
接口訪問的也是同樣的道理。
其中放行方法:
//正常訪問,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; //初始化printWriterURL String printWriterURL="<script>window.location.href='"+httpRequest.getContextPath()+ "/jsps/login/login.jsp';</script>"; //其他jsp的時候算是越權訪問 logger.info("用戶越權訪問!!!!" + url); PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return;
這樣就大功告成,具體代碼細節如下所示:
public class SystemFilter implements Filter { private static Logger logger = Logger.getLogger(SystemFilter.class); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; HttpSession session = httpRequest.getSession(true); String url = httpRequest.getRequestURI(); String printWriterURL = "<script>window.location.href='" + httpRequest.getContextPath() + "/jsps/login/login.jsp';</script>"; String checkURL = url; if(checkURL.endsWith("/")){ checkURL = checkURL.substring(0, checkURL.length()-1); if(checkURL.split("/").length == 2){ PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } } Object object = session.getAttribute("user"); User user = object == null ? null : (User) object; boolean isAjaxRequest = false; if (!StringUtils.isBlank(httpRequest.getHeader("x-requested-with")) && httpRequest.getHeader("x-requested-with").equals("XMLHttpRequest")) { isAjaxRequest = true; } StringBuffer server = httpRequest.getRequestURL(); if (server.toString().contains(".css") || server.toString().contains(".jsp") || (server.toString().contains(".js") && !server.toString().contains(".jsp")) || server.toString().contains(".png") || server.toString().contains(".jpg") || server.toString().contains(".gif") || server.toString().contains(".svg") || server.toString().contains(".so") || server.toString().contains(".woff") || server.toString().contains(".ttf") || server.toString().endsWith("/downPDF") // 下載放行 || server.toString().contains("/websocket") // 推送放行 ){ if(user ==null && server.toString().contains(".jsp")){ if(server.toString().contains("index.jsp")){ logger.info("!!!用戶未登錄且使用index.jsp頁面:" + url); PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; }else if(server.toString().contains("login.jsp")){ //當訪問的是login.jsp的時候放行 filterChain.doFilter(servletRequest, servletResponse); return; }else{ //其他jsp的時候算是越權訪問 logger.info("用戶越權訪問!!!!" + url); PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } }else if(user !=null && server.toString().contains(".jsp") && !(server.toString().contains("login.jsp"))){ Boolean ISURL = false; //獲取訪問url的字符串 int urllen = checkURL.split("/").length; String checkurl = ""; for(int i=2;i<urllen;i++){ if(i<urllen-1){ checkurl+=checkURL.split("/")[i]+"/"; }else{ checkurl+=checkURL.split("/")[i]; } } c:for(int j=0;j<LoginService.MENU_URLS.size();j++){ //獲取角色用戶對應二級菜單的URL String _orUrls = LoginService.MENU_URLS.get(j); if(_orUrls.equals(checkurl)){ System.out.println("符合條件的:"+checkurl); ISURL = true; break c; } } //當上一個判斷時不能訪問考慮第二種情況 if(!ISURL){ //通過二級菜單讀取配置文件中對應的子url,防止空指針異常 String purls = LoginService.MENU_INTERFACE.get(checkurl)==null?"":LoginService.MENU_INTERFACE.get(checkurl).toString(); d:for(int j=0;j<LoginService.MENU_URLS.size();j++){ String _orUrls = LoginService.MENU_URLS.get(j); //獲取角色用戶對應二級菜單的URL和通過訪問路徑去查配置文件時候存在吻合則放行 if(_orUrls.equals(purls)){ System.out.println("符合條件的:"+purls); ISURL = true; break d; } } } if(!ISURL){ //越權訪問 String msg = "ip=" + user.getIpaddr() + "&name=" + user.getUsername(); logger.info("!!!越權訪問:" + url + ";用戶信息:" + msg); printWriterURL = "<script>window.location.href='" + httpRequest.getContextPath() + "/jsps/login/login.jsp?" + msg + "';</script>"; }else{ System.out.println("========>"+LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])); //正常訪問,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } // 如果發現是css或者js文件,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } if (!isAjaxRequest) { if (user != null && (server.toString().contains("index.jsp") || server.toString().contains("login.jsp"))) { // 如果發現是css或者js文件,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } else { if(user != null){ System.out.println("-----------1-----------"+checkURL); if(LoginService.MENU_INTERFACE != null && LoginService.MENU_INTERFACE.size() != 0 && LoginService.MENU_URLS != null && LoginService.MENU_URLS.size() != 0 ){ if(checkURL.split("/").length == 4){ System.out.println("-----------2-----------"+LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])); // if(LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3]) == null){ // // 如果發現是css或者js文件,直接放行 // filterChain.doFilter(servletRequest, servletResponse); // return; // } Boolean hasIn = false; if(null != LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])){ String[] urls = LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3]).toString().split(","); // jsp/pages/configmgt/device/deviceList.jsp,jsp/pages/configmgt/systemmgt/systemmgtList.jsp a:for(int i=0;i<urls.length;i++){ String _url = urls[i]; for(int j=0;j<LoginService.MENU_URLS.size();j++){ String _orUrls = LoginService.MENU_URLS.get(j); if(_orUrls.equals(_url)){ System.out.println("符合條件的:"+_url); hasIn = true; break a; } } } } if(!hasIn){ //越權訪問 String msg = "ip=" + user.getIpaddr() + "&name=" + user.getUsername(); logger.info("!!!越權訪問:" + url + ";用戶信息:" + msg); printWriterURL = "<script>window.location.href='" + httpRequest.getContextPath() + "/jsps/login/login.jsp?" + msg + "';</script>"; }else{ System.out.println("========>"+LoginService.MENU_INTERFACE.get(checkURL.split("/")[2]+"/"+checkURL.split("/")[3])); //正常訪問,直接放行 filterChain.doFilter(servletRequest, servletResponse); return; } } } } PrintWriter p = httpResponse.getWriter(); p.write(printWriterURL); p.flush(); p.close(); return; } } if (url.toString().contains(".jsp")) { logger.info(httpRequest.getSession().getServletContext().getRealPath("/") + "-------"); logger.info("攔截器放行地址:-------------------" + url); } filterChain.doFilter(servletRequest, servletResponse); return; } /** * 判斷是否為Ajax請求 * * @param request * HttpServletRequest * @return 是true, 否false */ public static boolean isAjaxRequest(HttpServletRequest request) { return request.getRequestURI().startsWith("/api"); // String requestType = request.getHeader("X-Requested-With"); // return requestType != null && requestType.equals("XMLHttpRequest"); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { // To change body of implemented methods use File | Settings | File // Templates. } }