【问题标题】:How can I set API url such that the API is accessible only to IP whitelisted clients while the web application itself remains accessible to all?如何设置 API url,以便只有 IP 白名单客户端可以访问 API,而 Web 应用程序本身仍然可供所有人访问?
【发布时间】:2021-05-11 09:18:33
【问题描述】:

我有一个 Web 应用程序可供公众通过 url 访问,例如 example.com。 现在我想为一些客户端提供一个 REST API 来通过一个受保护的 url 访问我服务器上的数据,比如 api.example.com。 我不希望公众可以访问此 API 链接,并希望通过防火墙对其进行保护,只有来自白名单 IP 的请求才能使用这些服务。

**将 API 作为单独的应用程序托管似乎有点过头了
**基于 URL 的过滤,比如阻止 example.com/funnyapi/1 而允许 api.example.com/funnyapi/1 似乎也不是一个合适的解决方案。
我是 REST api 的新手。
请建议如何处理。

【问题讨论】:

  • [foobar.io 已注册,最好使用example.com] 你想如何限制对你的 API 的访问? HTTP 身份验证?你在你的 API 中使用什么,JAX-RS?
  • 我想通过防火墙级别的 IP 验证进行限制(如果这是规范的话)。是的,我正在使用 JAX-RS。

标签: servlets jax-rs firewall servlet-filters


【解决方案1】:

我不会根据主机名限制访问,而是根据 URI 路径限制访问:Web 应用程序通常会提供相同的内容,无论您使用哪个主机名。

假设您使用web.xml/contextPath/api 部署了Jersey servlet:

<servlet>
    <servlet-name>ApiServlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ApiServlet</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>

然后您可以轻松地将Filter 添加到您的servlet,它将根据远程地址进行过滤。如果您使用的是 Tomcat,那么已经有一个过滤器可以做到这一点:

<filter>
    <filter-name>AddressFilter</filter-name>
    <filter-class>org.apache.catalina.filters.RemoteAddrFilter</filter-class>
    <init-param>
        <param-name>allow</param-name>
        <param-value>192.168.\d+.\d+</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>AddressFilter</filter-name>
    <servlet-name>ApiServlet</servlet-name>
</filter-mapping>

不过,我会考虑添加一些&lt;security-contraint&gt;s:

<security-constraint>
   <web-resource-collection>
      <web-resource-name>Api</web-resource-name>
      <url-pattern>/api/*</url-pattern>
   </web-resource-collection>
     <auth-constraint>
         <role-name>apiUser</role-name> 
     </auth-constraint>
     <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
     </user-data-constraint>
</security-constraint>

Oracle's documentation 中描述了保护 RESTful API 的其他方法。

编辑:如果您正在使用另一个 servlet 容器,您可以像这样创建一个过滤器:

public class RemoteAddrFilter implements Filter {

   private Pattern allow;

   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
      final String pattern = filterConfig.getInitParameter("allow");
      if (pattern != null) {
         allow = Pattern.compile(pattern);
      }
   }

   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      if (allow == null) {
         return;
      }
      final String remoteAddr = request.getRemoteAddr();

      if (allow.matcher(remoteAddr).matches()) {
         chain.doFilter(request, response);
      } else {
         if (response instanceof HttpServletResponse) {
            ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
         }
      }
   }
}

【讨论】:

  • 注意:这个答案假定 OP 正在使用 Tomcat 服务器,但这在当前形式的问题中以及之前提出的 OP 问题中都没有明确说明。此答案不适用于其他服务器。
  • @BalusC:谢谢,我没有注意到缺少 tomcat 标记或任何提及 servlet 容器。我使用独立于容器的Filter 示例编辑了答案。
  • 感谢您的回答@PiotrP.Karwasz。确实,这听起来像是理想的解决方案。当一个简单的过滤器就足够时,我似乎把这个问题复杂化了。可能是因为我是 JAX-RS 的新手,不知道它实际上是如何工作的。
  • @BalusC Piotr 关于安全方面,每个请求都带有一个 SHA-256 加密的参数值(由分隔符分隔),使用只有客户端和我的服务器知道的私钥。仅当客户端发送的校验和与我的服务器使用相同的 SHA-256 和私钥生成的校验和匹配时,我才允许该请求。我是否让它足够安全。请提出建议。
  • 关于服务器,幸好我只使用Tomcat。
猜你喜欢
  • 2016-12-28
  • 2020-09-09
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 2015-05-07
  • 2015-07-31
  • 2014-02-06
  • 2011-03-18
相关资源
最近更新 更多