In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the relevant knowledge of "how to prevent IP from repeated anti-brushing attacks by SpringBoot+Redis+Lua". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Hackers or some malicious users to attack your website or APP. Request your interface through meat machine concurrency or endless loop. This leads to system downtime.
For interfaces with new data, there will be a lot of duplicate data, and even junk data will deplete your database and CPU or memory disks until the database is full.
The interface for the query. Hackers generally focus on slow queries. For example, a SQL is 2S. As long as the hackers attack uniformly, the system will inevitably be dragged down, the database queries will all be blocked, and the connection will not be released all the time, so that the database cannot be accessed.
The specific results to be achieved and achieved are:
Requirement: only 30 visits to the same IP 127.0.0.1 address are allowed within 10 seconds.
The final result:
Long execute = this.stringRedisTemplate.execute (defaultRedisScript, keyList, "30", "10")
Analysis: keylist = 127.0.0.1 expire 30 incr
Analysis 1: user ip address 127.0.0.1 visits incr once
Analysis 2: user ip address 127.0.0.1 visits incr once
Analysis 3: user ip address 127.0.0.1 visits incr once
Analysis 4: user ip address 127.0.0.1 visits incr once
Analysis 10: user ip address 127.0.0.1 visits incr once
Determine whether the current number of times has reached 10 times, and if so. Whether the current time is more than 30 seconds. If it is not greater than, access is not allowed, otherwise the expiration starts.
Method 1: implement it according to the user id or ip
Step 1: lua file
Create an iplimit.lua file under resource/lua
-- set the counter for the request IP of an interface, for example: 127.0.0.1 request course interface-- KEYS [1] = 127.0.0.1, that is, the user's IP-- ARGV [1] = expiration time 30mm2-ARGV [2] = limited number of times local limitCount = redis.call ('incr',KEYS [1]) If limitCount = 1 then redis.call ("expire", KEYS [1], ARGV [1]) end-- if the number of times has not expired and is still within the specified number of times, the same interface if limitCount > tonumber (ARGV [2]) then return 0endreturn 1 is still being requested
Step 2: create a lua object
@ SpringBootConfigurationpublic class LuaConfiguration {/ * load the contents of the lua script into DefaultRedisScript * @ return * / @ Bean public DefaultRedisScript initluascript () {DefaultRedisScript defaultRedisScript = new DefaultRedisScript (); defaultRedisScript.setScriptSource (new ResourceScriptSource (new ClassPathResource ("lua/iplimit.lua")); defaultRedisScript.setResultType (Long.class); return defaultRedisScript;}}
The third step is using
Package com.kuangstudy.controller;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;import java.util.List / * @ description: * @ author: xuke * @ time: 22:25 * / @ RestControllerpublic class IpLuaController {private static final Logger log = LoggerFactory.getLogger (IpLuaController.class) on 2021-7-3; @ Autowired private StringRedisTemplate stringRedisTemplate; @ Autowired private DefaultRedisScript iplimitLua; @ PostMapping ("/ ip/limit") / / @ IpList (second=10,limit=20) public String luaupdateuser (String ip) {String key = "user:" + ip / / 1: the value corresponding to KEYS is a set List keysList = new ArrayList (); keysList.add (key); / / 2: the specific value ARGV is a dynamic parameter, that is, an array / / 10 represents the expiration time 2 times, indicating that a maximum of 2 visits to Long execute = stringRedisTemplate.execute (iplimitLua, keysList, "10", "2") are allowed within 10 seconds. If (execute = = 0) {log.info ("1-> ip: {}, request received restrictions", key); return "Guest, don't be too fast to respond to the service...";} log.info ("2-> ip: {}, normal access, return course list", key) Return "normal access, return course list" + key;}}
In fact, you can also write a custom annotation, combined with lua to achieve current limit.
For example: @ iplimit (time=10,limit=2)
# method 2: annotation implementation
Requirements: user requests are allowed only 2 requests in one second.
The core is AOP.
The previous steps are the same, lua script, lua object, custom redisltemplate.
1.redis dependence
Org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-starter-data-redis
2.lua script
-- set the counter for the request IP of an interface, for example: 127.0.0.1 request course interface-- KEYS [1] = 127.0.0.1, that is, the user's IP-- ARGV [1] = expiration time 30mm2-ARGV [2] = limited number of times local limitCount = redis.call ('incr',KEYS [1]) If limitCount = 1 then redis.call ("expire", KEYS [1], ARGV [1]) end-- if the number of times has not expired and is still within the specified number of times, the same interface if limitCount > tonumber (ARGV [2]) then return 0endreturn 1 is still being requested
3. Create a lua object
Package com.kuangstudy.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.scripting.support.ResourceScriptSource / * * @ author Fei * @ Title: we have a learning website: https://www.kuangstudy.com * @ date 12:01 on 2021-5-21 * / @ Configurationpublic class LuaConfiguration {/ * load the contents of the lua script into DefaultRedisScript * @ return * / @ Bean public DefaultRedisScript limitUserAccessLua () {/ / 1: initialize the object of a lua script DefaultRedisScript DefaultRedisScript defaultRedisScript = new DefaultRedisScript () / / 2: the location where the lua script is loaded through this object ClassPathResource reads the lua script / / ClassPathResource under the classpath what is the classpath: the target/classes directory defaultRedisScript.setScriptSource (new ResourceScriptSource ("lua/userlimit.lua")) compiled by your maven; / / 3: what is the final return value of the lua script? It is suggested that we all return numbers. 1 defaultRedisScript.setResultType (Boolean.class); return defaultRedisScript;}}
4. Custom redistemplate
Package com.kuangstudy.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;import org.springframework.data.redis.serializer.StringRedisSerializer / * * @ author Fei * @ Title: learning companion product * @ Description: we have a learning website: https://www.kuangstudy.com * @ date 2021-5-20 13:16 * / @ Configurationpublic class RedisConfiguration {/ * * @ return org.springframework.data.redis.core.RedisTemplate * @ Description rewrite redistemplate serialization rules * * / @ Bean public RedisTemplate redisTemplate (RedisConnectionFactory RedisConnectionFactory) {/ / 1: start creating a redistemplate RedisTemplate redisTemplate = new RedisTemplate () / / 2: start the redis connection factory to install redisTemplate.setConnectionFactory (redisConnectionFactory); / / create a json serialization mode GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer (); / / set key to string serialization mode redisTemplate.setKeySerializer (new StringRedisSerializer ()); / / set value to process redisTemplate.setValueSerializer with jackjson (jackson2JsonRedisSerializer) / / hash also needs to modify redisTemplate.setHashKeySerializer (new StringRedisSerializer ()); redisTemplate.setHashValueSerializer (jackson2JsonRedisSerializer); / / call redisTemplate.afterPropertiesSet () by default; return redisTemplate;}}
5. Custom annotation
Package com.kuangstudy.limit.annotation;import java.lang.annotation.*;@Target (ElementType.METHOD) @ Retention (RetentionPolicy.RUNTIME) @ Documentedpublic @ interface AccessLimiter {/ / Target: @ AccessLimiter (limit= "1", timeout= "1", key= "user:ip:limit") / / interpretation: a user key visits limit key String key () at most during timeout time; / / limit the number of times int limit () default 1 / / expiration time int timeout () default 1;}
6. Custom section
Package com.kuangstudy.limit.aop;import com.kuangstudy.common.exception.BusinessException;import com.kuangstudy.limit.annotation.AccessLimiter;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate Import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import java.util.stream.Collectors;@Aspect@Componentpublic class AccessLimiterAspect {private static final Logger log = LoggerFactory.getLogger (AccessLimiterAspect.class); @ Autowired private StringRedisTemplate stringRedisTemplate; @ Autowired private DefaultRedisScript limitUserAccessLua / / 1: pointcut @ Pointcut ("@ annotation (com.kuangstudy.limit.annotation.AccessLimiter)") public void cut () {System.out.println ("cut");} / 2: notify and join point @ Before ("cut ()") public void before (JoinPoint joinPoint) {/ / 1: get the executed method MethodSignature signature = (MethodSignature) joinPoint.getSignature () Method method = signature.getMethod (); / / 2: get the annotation AccessLimiter annotation= method.getAnnotation (AccessLimiter.class) through the method; / / if annotation==null, no current limiting AccessLimiter is added to the method, indicating that no current limiting operation if (annotation==null) {return is required } / / 3: get the corresponding annotation parameters String key = annotation.key (); Integer limit = annotation.limit (); Integer timeout = annotation.timeout (); / / 4: if your key is empty if (StringUtils.isEmpty (key)) {String name = method.getDeclaringClass (). GetName () / / directly give the current method name to key key = name+ "#" + method.getName (); / / get the parameter list in the method / / ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer (); / / String [] parameterNames = pnd.getParameterNames (method); Class [] parameterTypes = method.getParameterTypes () For (Class parameterType: parameterTypes) {System.out.println (parameterType) } / / if the method has parameters, put the key rule = method name "#" parameter type if (parameterTypes! = null) {String paramtypes = Arrays.stream (parameterTypes) .map (Class::getName) .parameters (Collectors.joining (",")) Key = key + "#" + paramtypes;}} / / 1: define the list of key is List keysList = new ArrayList (); keysList.add (key); / / 2: execute lua script current limit Boolean accessFlag = stringRedisTemplate.execute (limitUserAccessLua, keysList, limit.toString (), timeout.toString ()) / / 3: judge the result of the current execution. If 0 is restricted, 1 represents normal if (! accessFlag) {throw new BusinessException (500, "server is busyworthiness!");}
7. Carry on the current limit test on the method that needs to limit the current
Package com.kuangstudy.controller;import com.kuangstudy.common.exception.BusinessException;import com.kuangstudy.limit.annotation.AccessLimiter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;import java.util.List;@RestControllerpublic class RateLimiterController {@ Autowired private StringRedisTemplate stringRedisTemplate @ Autowired private DefaultRedisScript limitUserAccessLua; / * handling method of current restriction * @ param userid * @ return * / @ GetMapping ("/ limit/user") public String limitUser (String userid) {/ / 1: define the list List keysList = new ArrayList () of key is; keysList.add ("user:" + userid) / / 2: execute lua script current limit Boolean accessFlag = stringRedisTemplate.execute (limitUserAccessLua, keysList, "1", "1"); / / 3: determine the result of the current execution. If 0 is restricted, 1 represents normal if (! accessFlag) {throw new BusinessException (500, "server is busyweights!");} return "scucess" } / * * current-limiting method * @ param userid * @ return * * solution 1: if one of your methods only allows 100 requests per second, key Common * solution 2: if a user allows 10 requests in a second, key must perform stitching according to the specific values of the parameters. * * / @ GetMapping ("/ limit/aop/user") @ AccessLimiter (limit = 1 limit/aop/user3 timeout = 1) public String limitAopUser (String userid) {return "scucess";} @ GetMapping ("/ limit/aop/user3") @ AccessLimiter (limit = 10 focus timeout = 1) public String limitAopUse3 (String userid) {return "scucess" } / * * current-limiting method * @ param userid * @ return * * solution 1: if one of your methods only allows 100 requests per second, key Common * solution 2: if a user allows 10 requests in a second, key must perform stitching according to the specific values of the parameters. * * / @ GetMapping ("/ limit/aop/user2") public String limitAopUser2 (String userid) {return "scucess";}} "how to prevent repeated IP anti-brushing attacks by SpringBoot+Redis+Lua" ends here. Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.