最近有一个系统蜜罐需求,即设置一些假接口以供访问,当接口被访问时即有可能系统正在被扫描,需要将访问的路径和ip地址输出到指定日志文件中以便观察。由于输出日志写在了util中但是不可能将所有的util日志都当作是攻击日志,所以需要过滤指定内容的日志输出到蜜罐日志文件中。
定义日志输出util
private static final String IP_UNKNOWN = "unknown";
private static final String IP_LOCAL = "127.0.0.1";
private static final int IP_LEN = 15;
/**
* 获取客户端真实ip
* @param request request
* @return 返回ip
*/
public static String getIP(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
String ipAddress = headers.getFirst("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = headers.getFirst("Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = headers.getFirst("WL-Proxy-Client-IP");
}
if (ipAddress == null || ipAddress.length() == 0 || IP_UNKNOWN.equalsIgnoreCase(ipAddress)) {
ipAddress = Optional.ofNullable(request.getRemoteAddress())
.map(address -> address.getAddress().getHostAddress())
.orElse("");
if (IP_LOCAL.equals(ipAddress)) {
// 根据网卡取本机配置的IP
try {
InetAddress inet = InetAddress.getLocalHost();
ipAddress = inet.getHostAddress();
} catch (UnknownHostException e) {
// ignore
}
}
}
// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if (ipAddress != null && ipAddress.length() > IP_LEN) {
int index = ipAddress.indexOf(",");
if (index > 0) {
ipAddress = ipAddress.substring(0, index);
}
}
return ipAddress;
}
public static void printServerLog(ServerHttpRequest request){
String target = request.getURI().toASCIIString();
String uri = request.getPath().value();
String clientIp = getIp(request);
log.info("HoneyPotLog: clientIp={},uri={},target={}",clientIp,uri,clientIp);
}
}
定义蜜罐接口
@RestController
public class HoneyPotController{
@RequestMapping("/admin")
public void admin(ServerHttpRequest request){
WebUtil.printServerLog(request);
}
@RequestMapping("/config")
public void config(ServerHttpRequest request){
WebUtil.printServerLog(request);
}
}
自定义logback过滤器
public class HoneyPotLogFilter extends Filter<ILoggingEvent>{
@Override
public FilterReply decide(ILoggingEvent event){
if (StrUtil.startWith(event.getMessage,"HoneyPotLog: ")){
return FilterReply.ACCEPT;
}else{
return FilterReply.DENY;
}
}
}
使用自定义过滤器
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<property name="LOG_HOME" value="/test/logs"/>
<appender name="HONEYPOT_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${LOG_HOME}/honeypot.log</File>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%X{traceId}] %-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
<!--使用自定义过滤器-->
<filter class="com.test.gateway.filter.logback.HoneyPotLogFilter"/>
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindRollingPolicy">
<fileNamePattern>${LOG_HOME}/honeypot.log.%i.gz</fileNamePattern>
<minIndex>1</minIndex>
<maxIndex>3</maxIndex>
</rollingPolicy>
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<maxFileSize>50MB</maxFileSize>
</triggeringPolicy>
</appender>
<root level="INFO">
<appender-ref ref="HONEYPOT_FILE"/>
</root>
</configuration>