问题回顾
前两天,打开博客,发现评论区,出现好多奇怪的评论,非正常评论,而且时间间隔就几秒,这就显示有人使用其他手段恶意刷评论。
想着可能就是谁无聊而已。放了几天,没想到他还天天刷,这就有点过分。所以需要给博客防护下了。
nginx限制ip
1、首先查看nginx的日志
通过日志分析,发现这个恶意的评论都是来自 109.70.100.*,这个ip网段。
所以,可以通过nginx的deny,限制ip。
2、配置如下:
这样就可以限制109.70.100.*,这个网段的所有ip。
3、结果如下:
这是这个ip访问的就拦截了。
网关限制
虽然nginx,已经可以帮助我们拦截IP了,但是当ip数量多,还有一些敏感词汇的拦截等等,所以自己用springcloud的zuul,搭建一个网关。
1、新建一个springboot的项目,加入pom
<!--zuuljar包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2、增加配置文件 application.yml
zuul:
routes:
eureka-application-service.path: /**
eureka-application-service.url: http://127.0.0.1:8080
max:
host:
connections: 500
host:
socket-timeout-millis: 60000
connect-timeout-millis: 60000
server:
port: 8091
eureka:
client:
register-with-eureka: false
fetch-registry: false
security:
basic:
enabled: false
fengpt:
blackIp: "109.70.100.*"
sensitive:
urlList: "/api/content/posts/comments"
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 600000
ribbon:
ReadTimeout: 600000
ConnectTimeout: 600000
logging:
# 将日志输出到文件 注意name和path同时使用只会生效后一个配置
file: "/usr/local/apps/fengptzuul/logs/log.log"
# 日志文件大小默认是10M单位是KB
#max-size: 10MB
# 每天切割打包日志的数量默认是7
#max-history: 7
#日志格式
pattern:
#输出到日志文件日志格式
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
#输出到控制台日志格式
# %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
#时间格式 默认 yyyy-MM-dd HH:mm:ss.SSS
dateformat: "yyyy-MM-dd HH:mm:ss.SSS"
#日志等级对齐方式 默认%5p日志级别输出右对齐
level:
#切割文件名称 默认是${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz 如过单个日志文件超过定义的大小就切割打包
rolling-file-name: "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz"
#需要记录日志的等级
level:
# 根目录所以class日志记录等级
root: info
# 自定义对应包下class 日志等级
cn.fengpt.gateway.filter.GateWayFilter: info
说明:
- blackIp: 填写需要拦截的ip,可以是多个以逗号分隔
- sensitive: 填写需要拦截的敏感词汇,可以是多个以逗号分隔
- urlList: 填写需要拦截的url,可以是多个以逗号分隔
3、启动类加EnableZuulProxy
@SpringBootApplication
@EnableZuulProxy
public class FengptGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(FengptGatewayApplication.class, args);
}
}
4、编写拦截规则
@Component
public class GateWayFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(GateWayFilter.class);
@Value("${fengpt.blackIp}")
private String blackIp;
@Value("${fengpt.sensitive}")
private String sensitive;
@Value("${fengpt.urlList}")
private String urlList;
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
log.info(String.format("blackIp:%s >>> ;sensitive: %s",blackIp,sensitive));
String ip= getIpAddress(request);
log.info(String.format("ip >>> %s", ip));
boolean flag = ipPattern(blackIp, ip);
if (!flag){
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("Illegal request");
}catch (Exception e){}
return null;
}
String url= request.getRequestURL().toString();
if(StringUtils.isNotBlank(url)&&StringUtils.isNotBlank(urlList)){
boolean flag2 = urlPattern(urlList,url);
if(!flag2){
try{
// 获取请求的输入流
InputStream in = request.getInputStream();
String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
log.info(String.format("body >>> %s", body));
boolean flag1 =sensitivePattern(sensitive,body);
if (!flag1){
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
try {
ctx.getResponse().getWriter().write("Illegal request");
}catch (Exception e){
}
return null;
}
}catch(Exception e){
}
}
}
log.info("ok");
return null;
}
/**
* 获取Ip地址
* @param request
* @return
*/
private static String getIpAddress(HttpServletRequest request) {
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
//多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = XFor.indexOf(",");
if(index != -1){
return XFor.substring(0,index);
}else{
return XFor;
}
}
XFor = Xip;
if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
return XFor;
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return XFor;
}
public static boolean sensitivePattern(String sensitives,String body) {
boolean flag=true;
if (StringUtils.isNotBlank(sensitives)&&StringUtils.isNotBlank(sensitives)){
List<String> tbList = Arrays.asList(sensitives.split(","));
if (tbList!=null&&tbList.size()!=0){
for (int i=0;i<tbList.size();i++){
if(body.contains(tbList.get(i))){
flag=false;
break;
}
}
}
}
return flag;
}
public static boolean urlPattern(String urlList,String url) {
boolean flag=true;
if (StringUtils.isNotBlank(urlList)&&StringUtils.isNotBlank(url)){
List<String> tbList = Arrays.asList(urlList.split(","));
if (tbList!=null&&tbList.size()!=0){
for (int i=0;i<tbList.size();i++){
if(url.contains(tbList.get(i))){
flag=false;
break;
}
}
}
}
return flag;
}
/**
* 过滤ip
* @param ips
* @param ip
* @return
*/
public static boolean ipPattern(String ips,String ip) {
boolean flag=true;
if (StringUtils.isNotBlank(ips)&&StringUtils.isNotBlank(ip)){
String[] split = ips.split(",");
if (split!=null&&split.length!=0){
for (int i=0;i<split.length;i++){
if(Pattern.matches(split[i],ip)){
flag=false;
break;
}
}
}
}
return flag;
}
}
5、测试
编译打包成jar,后运行。
评论区