是否可以将 AccessLogValve 配置为在将密码写入日志文件之前隐藏/替换密码?我对阀门不熟悉,也许有办法插入自定义过滤器/阀门?
3 回答
使用自定义 AccessLogValve 类的解决方案
创建一个单独的maven项目:
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>test</groupId> <artifactId>filtered-access-log-valve</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-catalina</artifactId> <version>7.0.70</version> </dependency> </dependencies> </project>
FilteredAccessLogValve.java
package test; import org.apache.catalina.valves.AccessLogValve; public class FilteredAccessLogValve extends AccessLogValve { @Override public void log(String message) { super.log(message.replaceAll("password=[^&]*", "password=***")); } }
从项目中构建 jar 工件并将其复制到tomcat/lib/
在tomcat/conf/server.xml更改访问日志阀门类
<Valve className="test.FilteredAccessLogValve" ...>
使用 servlet 过滤器的另一种解决方案
最后我来到了这个解决方案,因为它需要最少的 tomcat 配置。
- 在tomcat/conf/context.xml
<Valve>
通过注释标签关闭默认访问日志阀门。 创建AdvancedAccessLogFilter类:
package your.package; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; public class AdvancedAccessLogFilter implements Filter { private static final String PASSWORD_REGEX = "password=[^&]+"; private static final String PASSWORD_MASK = "password=***"; private FilterConfig filterConfig = null; public void destroy() { this.filterConfig = null; } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { if (filterConfig == null) { return; } HttpServletRequest request = (HttpServletRequest) servletRequest; String maskedPath = request.getRequestURI() + (request.getQueryString() == null ? "" : request.getQueryString().replaceAll(PASSWORD_REGEX, PASSWORD_MASK)) + " " + request.getProtocol(); request.setAttribute("maskedPath", maskedPath); chain.doFilter(request, servletResponse); } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } }
在项目的web.xml中注册 servlet 过滤器:
<filter> <filter-name>AdvancedAccessLogFilter</filter-name> <filter-class>your.package.AdvancedAccessLogFilter</filter-class> </filter> <filter-mapping> <filter-name>AdvancedAccessLogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
使用修改后的访问日志阀门模式创建src/main/webapp/META-INF/context.xml :
<?xml version='1.0' encoding='utf-8'?> <Context> <WatchedResource>WEB-INF/web.xml</WatchedResource> <Valve className='org.apache.catalina.valves.AccessLogValve' directory='logs' prefix='localhost_access_log.' suffix='.txt' pattern='%h %t %m "%{maskedPath}r" %s %b %D' /> </Context>
如果您想从 Spring 上下文中自动装配一些 bean,请添加SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
到过滤器的init()
方法中。
简单的答案是扩展 AccessLogValve 类并覆盖 log 方法,使用 String#replaceAll 将所有出现的密码替换为“ * ”。
在使用嵌入式 tomcat 服务器的 SAP/Hybris 项目之一中遇到了同样的问题。每当使用密码授予类型进行 oauth/token 调用时,用户和 OAuth 客户端的机密信息以以下格式记录在访问日志中。
0:0:0:0:0:0:0:1 - - [31/Mar/2021:21:19:38 +0530] "POST /authorizationserver/oauth/token?client_id=trusted_client&client_secret=secret&grant_type=password&username=admin&password=nimda HTTP/1.1" 200 334 "-" "PostmanRuntime/7.24.1"
**使用自定义 AccessLogValve 类解决**
创建一个独立的 Maven 项目。
更新 Pom.xml 如下
4.0.0 FilteredAccessLogValve filtered-access-log-valve 0.0.1-SNAPSHOT 过滤访问日志阀门 过滤访问日志阀门 用于自定义日志值 org.apache.tomcat tomcat-catalina 8.5.57 maven-compiler-plugin 3.5.1 1.8 1.8 org .apache.maven.plugins maven-jar-plugin 包jar
在 src/main/java 中创建一个类作为 FilteredAccessLogValve,它从 org.apache.catalina.valves 包扩展 AccessLogValve。该类如下所示。
包 org.apache.catalina.valves;
导入 java.io.CharArrayWriter;导入 java.io.IOException;
public class FilteredAccessLogValve extends AccessLogValve {
@Override
public void log(CharArrayWriter message) {
CharArrayWriter caw = new CharArrayWriter();
try {
caw.write(message.toString().replaceAll("password=[^&^ ]*", "password=***").replaceAll("client_secret=[^&^ ]*",
"client_secret=***"));
super.log(caw);
} catch (IOException e) {
e.printStackTrace();
} finally {
caw.close();
}
}
}
使用 mvn clean -> mvn compile -> mvn install 构建 Jar。从 /target 文件夹复制过滤访问日志阀 0.0.1-SNAPSHOT jar 并将其放在 hybris/config/customize/platform/tomcat/lib 文件夹中。
查找所有服务器.xml hybris/config/tcServer/conf 和 hybris/config/tomcat/conf 文件,并在其中将所有阀门类定义替换为新的 FilteredAccessLogValve 类,如下所示
前:
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="${HYBRIS_LOG_DIR}/tomcat"
prefix="access."
suffix=".log"
pattern="combined"
/>
后:
<Valve className="org.apache.catalina.valves.FilteredAccessLogValve"
directory="${HYBRIS_LOG_DIR}/tomcat"
prefix="access."
suffix=".log"
pattern="combined"
/>
在平台中运行ant customize,然后构建并启动服务器。
现在日志将如下所示
0:0:0:0:0:0:0:1 - - [31/Mar/2021:21:19:38 +0530] "POST /authorizationserver/oauth/token?client_id=trusted_client&client_secret= &grant_type=password&username=admin&password = HTTP/1.1" 200 334"-" "PostmanRuntime/7.24.1"