如何使用过滤器限制来自地址栏的所有请求

Posted

技术标签:

【中文标题】如何使用过滤器限制来自地址栏的所有请求【英文标题】:How to restrict all the requests coming from address bar using filters 【发布时间】:2016-05-24 14:39:05 【问题描述】:

我正在使用 struts 2hibernate 开发一个 java web 应用程序。我想通过直接在地址栏上键入来限制用户调用任何 struts 操作。相反,用户应该使用 JSP 页面本身提供的链接,因为在我的应用程序中有许多访问级别,所以现在用户通过直接在地址栏上键入操作名称来进行未经授权的访问。在返回成功之前,我已经检查了每个功能上登录用户的访问级别。但这不是到处检查的好习惯。我搜索了如何使用 java Filters 来执行此操作,但没有成功。

我用来实现过滤器的东西如下:-

web.xmlSecurity 是我的包名,SessionFilterservlet 类)

<filter>
    <filter-name>SessionFilter</filter-name>
    <filter-class>
        Security.SessionFilter
    </filter-class>
    <init-param>
        <param-name>avoid-urls</param-name>
        <param-value>Index.jsp</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>SessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Index.jsp 是我的应用程序的入口点,所以我希望只允许通过在地址栏上键入来直接访问此页面。如果用户在地址栏上键入任何其他操作名称,他/她应该再次被重定向到登录页面,这就是为什么在下面的代码中我写了这个 response.sendRedirect("Index.jsp");

SessionFilter.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SessionFilter implements Filter 

    private ArrayList<String> urlList;

    public void destroy() 
    

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String url = request.getServletPath();
        boolean allowedRequest = false;

        if (urlList.contains(url)) 
            allowedRequest = true;
        

        if (!allowedRequest) 
            HttpSession session = request.getSession(false);
            if (null == session) 
                response.sendRedirect("Index.jsp");
            
        
        chain.doFilter(req, res);
    

    public void init(FilterConfig config) throws ServletException 
        String urls = config.getInitParameter("avoid-urls");
        StringTokenizer token = new StringTokenizer(urls, ",");
        urlList = new ArrayList<String>();
        while (token.hasMoreTokens()) 
            urlList.add(token.nextToken());
        
    

【问题讨论】:

“我想限制用户通过直接在地址栏上输入来调用任何 struts 操作”,然后“我希望只允许通过在地址栏上输入来直接访问此页面”。互相矛盾。 我认为无法通过直接在地址栏中输入或单击链接来检查用户是否访问特定页面。您应该在服务器端实现适当的安全性(例如存储一些会话变量等) 问题确实很奇怪,因为您在过滤器中无处检查登录用户,但前提是是否创建了 HTTP 会话(“拥有会话”!=“登录用户“!)。至少,这能提供洞察力吗? ***.com/q/13274279 【参考方案1】:

首先,访问级别检查不应该在jsp页面上。这个页面应该只显示视图。用户是否有权访问特定资源应在服务器端使用某种用户级别或角色级别安全性进行处理。为此,您可以实现自己的过滤器,也可以使用已经可用的安全库,例如 spring-security 或 shiro security。

但是,如果您不想这样做并且想坚持当前的方法,那么您可以检查每个请求的标头 X-Requested-With。对于 ajax 请求,它包含 XMLHttpRequest。但它不是标准标头,所有浏览器/用户代理可能不会发送此标头。为了确定 ajax 请求,您可以为从页面发送的每个请求添加一些自定义标头。

但同样使用这种方法,如果未经授权的用户想要访问某个操作,他/她可以通过手动将该标头添加到他们的请求中来实现。因此,在服务器端而不是在客户端检查授权将是一个不错的选择。

【讨论】:

我已经完成了访问级别的服务器端身份验证。实际上,我不想让用户通过直接在地址栏上输入操作名称来访问任何页面。确实用户可以使用提供的链接。【参考方案2】:

您可以实施过滤器来检查授权访问,并通过将它们重定向到登录或索引页面来拒绝任何未经授权的访问。

但是因为你使用 struts2 ;您可以利用 struts2 拦截器:

定义一个struts2拦截器:

public class LogInInterceptor implements Interceptor 

    @Override
    public String intercept(ActionInvocation invocation) throws Exception 

        Map<String, Object> sessionMap = ActionContext.getContext().getSession();

        if (sessionMap.get("urlList").contains(url)) 
            return invocation.invoke();
         else 
            return "index-jsp-alias";
        

    

    // setters and getters.

在 struts.xml 文件中定义这个拦截器:

        <interceptors>
            <interceptor name="mylogging" class="LogInInterceptor" />
            <interceptor-stack name="loggingStack">
                <interceptor-ref name="mylogging" />
                <interceptor-ref name="defaultStack" />
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="loggingStack" />
        <global-results>
        <result name="index-jsp-alias">Index.jsp</result>
    </global-results>

【讨论】:

【参考方案3】:

我得到了我的问题的解决方案并在我的应用程序中成功实施。非常感谢所有有用的答案和建议。

我实现的内容如下:-

web.xml

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
    <filter-name>SessionFilter</filter-name>
    <filter-class>
        Security.SessionFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>SessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

SessionFilter.java

package Security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SessionFilter implements Filter 

    public void destroy() 
    

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException 

        if (req instanceof HttpServletRequest) 
            req.setCharacterEncoding("UTF-8");
            HttpServletRequest request = (HttpServletRequest) req;
            String referrer = request.getHeader("referer");
            if (null == request.getSession(true).getAttribute("emp_id")) 
                if (referrer == null) 
                    if (isSessionExcluded(req)) 
                        req.setAttribute("isSessionExpire", "true");
                        RequestDispatcher reqDisp = req.getRequestDispatcher("/Index.jsp");
                        reqDisp.forward(req, resp);
                    
                
             else 
                if (referrer == null) 
                    RequestDispatcher reqDisp = req.getRequestDispatcher("/Error.jsp");
                    reqDisp.forward(req, resp);
                
            
            chain.doFilter(req, resp);
        
    

    public void init(FilterConfig config) throws ServletException 
    

    private boolean isSessionExcluded(ServletRequest req) 
        if (req instanceof HttpServletRequest) 
            HttpServletRequest request = (HttpServletRequest) req;
            String contextPath = request.getContextPath();
            String reqUri = request.getRequestURI();
            if (!(contextPath + "/Index.jsp").equals(reqUri)) 
                return true;
            
        
        return false;
    

我在 doFilter 方法中使用了 String referrer = request.getHeader("referer");。这将区分请求是通过在地址栏上键入还是通过单击某个链接生成的请求。如果请求是通过地址栏输入产生的,referrer的值为null

我希望这个解决方案对其他人也有帮助。

【讨论】:

不好的方法。原因如下:***.com/q/2648984 和 ***.com/q/6880659 换句话说:不要依赖引用者来获取控制器/业务逻辑。最终用户可以完全控制其价值。 如果用户键入任何操作名称,上述代码将不会受到限制。它只会限制最后扩展名为 .jsp 的地址。

以上是关于如何使用过滤器限制来自地址栏的所有请求的主要内容,如果未能解决你的问题,请参考以下文章

使用过滤器来限制 JSP 访问?

拒绝来自 Opera 地址栏的服务器端(PHP 或 Apache)的 Fetch API 请求

js如何获取地址栏的参数

关于原生ajax请求及其封装

如何限制来自 GraphQL API 端点的匿名用户?

如何限制 Firebase 云功能仅接受来自 Firebase 托管网站的请求