web的越權訪問的處理(步驟詳解)
使用者越權訪問的處理
一般來說,越權放問就好比你是非系統管理員使用者,卻偷偷的跑進了系統管理選單,僭越權利訪問裡面的資訊甚至修改其中的資料(不同級別的越權又稱垂直越權訪問),因此對資料的安全性造成極大的威脅,是故每家企業都有其方法來保證企業內部資料的安全性,也就是解決越權訪問的問題。
有關改業務處理主要考慮下面兩個方面:
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,定義一個靜態公有
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. } }