如何设置 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>
不过,我会考虑添加一些<security-contraint>
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 应用程序本身仍然可供所有人访问?的主要内容,如果未能解决你的问题,请参考以下文章