如何设置 API url,以便只有 IP 白名单客户端可以访问 API,而 Web 应用程序本身仍然可供所有人访问?

Posted

技术标签:

【中文标题】如何设置 API url,以便只有 IP 白名单客户端可以访问 API,而 Web 应用程序本身仍然可供所有人访问?【英文标题】: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? 【发布时间】: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。 【参考方案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。

以上是关于如何设置 API url,以便只有 IP 白名单客户端可以访问 API,而 Web 应用程序本身仍然可供所有人访问?的主要内容,如果未能解决你的问题,请参考以下文章

如何保护 REST-API?

微信小程序 IP白名单是指外网IP还是内网IP呢?如:192.168.2.144还是外网的IP?

win2008服务器 防火墙如何加ip地址的白名单

如何设置防火墙白名单

Asp.Net Core 中如何设置 IP 白名单

“阿里云”ECS服务器怎么设置IP白名单?