0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

分享一种优雅的接口防刷处理方案

jf_ro2CN3Fa 来源:稀土掘金 2023-03-29 14:56 次阅读

原理

通过ip地址+uri拼接用以作为访问者访问接口区分

通过在Interceptor中拦截请求,从Redis中统计用户访问接口次数从而达到接口防刷目的

如下图所示

b7163ee8-cdfd-11ed-bfe3-dac502259ad0.jpg

工程

其中,Interceptor处代码处理逻辑最为重要

b7264f7c-cdfd-11ed-bfe3-dac502259ad0.jpg

/**
*@author:Zero
*@time:2023/2/14
*@description:接口防刷拦截处理
*/
@Slf4j
publicclassAccessLimintInterceptorimplementsHandlerInterceptor{
@Resource
privateRedisTemplateredisTemplate;

/**
*多长时间内
*/
@Value("${interfaceAccess.second}")
privateLongsecond=10L;

/**
*访问次数
*/
@Value("${interfaceAccess.time}")
privateLongtime=3L;

/**
*禁用时长--单位/秒
*/
@Value("${interfaceAccess.lockTime}")
privateLonglockTime=60L;

/**
*锁住时的key前缀
*/
publicstaticfinalStringLOCK_PREFIX="LOCK";

/**
*统计次数时的key前缀
*/
publicstaticfinalStringCOUNT_PREFIX="COUNT";


publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{

Stringuri=request.getRequestURI();
Stringip=request.getRemoteAddr();//这里忽略代理软件方式访问,默认直接访问,也就是获取得到的就是访问者真实ip地址
StringlockKey=LOCK_PREFIX+ip+uri;
ObjectisLock=redisTemplate.opsForValue().get(lockKey);
if(Objects.isNull(isLock)){
//还未被禁用
StringcountKey=COUNT_PREFIX+ip+uri;
Objectcount=redisTemplate.opsForValue().get(countKey);
if(Objects.isNull(count)){
//首次访问
log.info("首次访问");
redisTemplate.opsForValue().set(countKey,1,second,TimeUnit.SECONDS);
}else{
//此用户前一点时间就访问过该接口
if((Integer)count< time){
                    // 放行,访问次数 + 1
                    redisTemplate.opsForValue().increment(countKey);
                }else{
                    log.info("{}禁用访问{}",ip, uri);
                    // 禁用
                    redisTemplate.opsForValue().set(lockKey, 1,lockTime, TimeUnit.SECONDS);
                    // 删除统计
                    redisTemplate.delete(countKey);
                    throw new CommonException(ResultCode.ACCESS_FREQUENT);
                }
            }
        }else{
            // 此用户访问此接口已被禁用
            throw new CommonException(ResultCode.ACCESS_FREQUENT);
        }
        return true;
    }
}

在多长时间内访问接口多少次,以及禁用的时长,则是通过与配置文件配合动态设置

b72b37da-cdfd-11ed-bfe3-dac502259ad0.jpg

当处于禁用时直接抛异常则是通过在ControllerAdvice处统一处理 (这里代码写的有点丑陋)

b73270c2-cdfd-11ed-bfe3-dac502259ad0.jpg

下面是一些测试(可以把项目通过Git还原到“【初始化】”状态进行测试)

正常访问时

b73827c4-cdfd-11ed-bfe3-dac502259ad0.jpgb74115be-cdfd-11ed-bfe3-dac502259ad0.jpg

访问次数过于频繁时

b747cc60-cdfd-11ed-bfe3-dac502259ad0.jpgb752a1da-cdfd-11ed-bfe3-dac502259ad0.jpg

自我提问

上述实现就好像就已经达到了我们的接口防刷目的了

但是,还不够

为方便后续描述,项目中新增补充Controller,如下所示

b759fe4e-cdfd-11ed-bfe3-dac502259ad0.jpg

简单来说就是

PassCotroller和RefuseController

每个Controller分别有对应的get,post,put,delete类型的方法,其映射路径与方法名称一致

接口自由

对于上述实现,不知道你们有没有发现一个问题

就是现在我们的接口防刷处理,针对是所有的接口(项目案例中我只是写的接口比较少)

而在实际开发中,说对于所有的接口都要做防刷处理,感觉上也不太可能(写此文时目前大四,实际工作经验较少,这里不敢肯定)

那么问题有了,该如何解决呢?目前来说想到两个解决方案

拦截器映射规则

项目通过Git还原到"【Interceptor设置映射规则实现接口自由】"版本即可得到此案例实现

我们都知道拦截器是可以设置拦截规则的,从而达到拦截处理目的

b7652170-cdfd-11ed-bfe3-dac502259ad0.jpg

1.这个AccessInterfaceInterceptor是专门用来进行防刷处理的,那么实际上我们可以通过设置它的映射规则去匹配需要进行【接口防刷】的接口即可

2.比如说下面的映射配置

b76b7aac-cdfd-11ed-bfe3-dac502259ad0.jpg

3.这样就初步达到了我们的目的,通过映射规则的配置,只针对那些需要进行【接口防刷】的接口才会进行处理

4.至于为啥说是初步呢?下面我就说说目前我想到的使用这种方式进行【接口防刷】的不足点:

所有要进行防刷处理的接口统一都是配置成了 x 秒内 y 次访问次数,禁用时长为 z 秒

要知道就是要进行防刷处理的接口,其 x, y, z的值也是并不一定会统一的

某些防刷接口处理比较消耗性能的,我就把x, y, z设置的紧一点

而某些防刷接口处理相对来说比较快,我就把x, y, z 设置的松一点

这没问题吧

但是现在呢?x, y, z值全都一致了,这就不行了

这就是其中一个不足点

当然,其实针对当前这种情况也有解决方案

那就是弄多个拦截器

每个拦截器的【接口防刷】处理逻辑跟上述一致,并去映射对应要处理的防刷接口

唯一不同的就是在每个拦截器内部,去修改对应防刷接口需要的x, y, z值

这样就是感觉会比较麻烦

防刷接口映射路径修改后维护问题

虽然说防刷接口的映射路径基本上定下来后就不会改变

但实际上前后端联调开发项目时,不会有那么严谨的Api文档给我们用(这个在实习中倒是碰到过,公司不是很大,开发起来也就不那么严谨,啥都要自己搞,功能能实现就好)

也就是说还是会有那种要修改接口的映射路径需求

当防刷接口数量特别多,后面的接手人员就很痛苦了

就算是项目是自己从0到1实现的,其实有时候项目开发到后面,自己也会忘记自己前面是如何设计的

而使用当前这种方式的话,谁维护谁蛋疼

自定义注解 + 反射

咋说呢

就是通过自定义注解中定义 x 秒内 y 次访问次数,禁用时长为 z 秒

自定义注解 + 在需要进行防刷处理的各个接口方法上

在拦截器中通过反射获取到各个接口中的x, y, z值即可达到我们想要的接口自由目的

下面做个实现

声明自定义注解

b770cfc0-cdfd-11ed-bfe3-dac502259ad0.jpg

Controlller中方法中使用

b7795514-cdfd-11ed-bfe3-dac502259ad0.jpg

Interceptor处逻辑修改(最重要是通过反射判断此接口是否需要进行防刷处理,以及获取到x, y, z的值)

/**
*@author:Zero
*@time:2023/2/14
*@description:接口防刷拦截处理
*/
@Slf4j
publicclassAccessLimintInterceptorimplementsHandlerInterceptor{
@Resource
privateRedisTemplateredisTemplate;
/**
*锁住时的key前缀
*/
publicstaticfinalStringLOCK_PREFIX="LOCK";

/**
*统计次数时的key前缀
*/
publicstaticfinalStringCOUNT_PREFIX="COUNT";


publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{
//自定义注解+反射实现
//判断访问的是否是接口方法
if(handlerinstanceofHandlerMethod){
//访问的是接口方法,转化为待访问的目标方法对象
HandlerMethodtargetMethod=(HandlerMethod)handler;
//取出目标方法中的AccessLimit注解
AccessLimitaccessLimit=targetMethod.getMethodAnnotation(AccessLimit.class);
//判断此方法接口是否要进行防刷处理(方法上没有对应注解就代表不需要,不需要的话进行放行)
if(!Objects.isNull(accessLimit)){
//需要进行防刷处理,接下来是处理逻辑
Stringip=request.getRemoteAddr();
Stringuri=request.getRequestURI();
StringlockKey=LOCK_PREFIX+ip+uri;
ObjectisLock=redisTemplate.opsForValue().get(lockKey);
//判断此ip用户访问此接口是否已经被禁用
if(Objects.isNull(isLock)){
//还未被禁用
StringcountKey=COUNT_PREFIX+ip+uri;
Objectcount=redisTemplate.opsForValue().get(countKey);
longsecond=accessLimit.second();
longmaxTime=accessLimit.maxTime();

if(Objects.isNull(count)){
//首次访问
log.info("首次访问");
redisTemplate.opsForValue().set(countKey,1,second,TimeUnit.SECONDS);
}else{
//此用户前一点时间就访问过该接口,且频率没超过设置
if((Integer)count< maxTime) {
                            redisTemplate.opsForValue().increment(countKey);
                        } else {

                            log.info("{}禁用访问{}", ip, uri);
                            long forbiddenTime = accessLimit.forbiddenTime();
                            // 禁用
                            redisTemplate.opsForValue().set(lockKey, 1, forbiddenTime, TimeUnit.SECONDS);
                            // 删除统计--已经禁用了就没必要存在了
                            redisTemplate.delete(countKey);
                            throw new CommonException(ResultCode.ACCESS_FREQUENT);
                        }
                    }
                } else {
                    // 此用户访问此接口已被禁用
                    throw new CommonException(ResultCode.ACCESS_FREQUENT);
                }
            }
        }
        return  true;
    }
}

由于不好演示效果,这里就不贴测试结果图片了

项目通过Git还原到"【自定义主键+反射实现接口自由"版本即可得到此案例实现,后面自己可以针对接口做下测试看看是否如同我所说的那样实现自定义x, y, z 的效果

嗯,现在看起来,可以针对每个要进行防刷处理的接口进行针对性自定义多长时间内的最大访问次数,以及禁用时长,哪个接口需要,就直接+在那个接口方法出即可

感觉还不错的样子,现在网上挺多资料也都是这样实现的

但是还是可以有改善的地方

先举一个例子,以我们的PassController为例,如下是其实现

b784144a-cdfd-11ed-bfe3-dac502259ad0.jpg

下图是其映射路径关系

b78dbaae-cdfd-11ed-bfe3-dac502259ad0.jpg

同一个Controller的所有接口方法映射路径的前缀都包含了/pass

我们在类上通过注解@ReqeustMapping标记映射路径/pass,这样所有的接口方法前缀都包含了/pass,并且以致于后面要修改映射路径前缀时只需改这一块地方即可

这也是我们使用SpringMVC最常见的用法

那么,我们的自定义注解也可不可以这样做呢?先无中生有个需求

假设PassController中所有接口都是要进行防刷处理的,并且他们的x, y, z值就一样

如果我们的自定义注解还是只能加载方法上的话,一个一个接口加,那么无疑这是一种很呆的做法

要改的话,其实也很简单,首先是修改自定义注解,让其可以作用在类上

b794bb60-cdfd-11ed-bfe3-dac502259ad0.jpg

接着就是修改AccessLimitInterceptor的处理逻辑

AccessLimitInterceptor中代码修改的有点多,主要逻辑如下

b79b63fc-cdfd-11ed-bfe3-dac502259ad0.jpg

与之前实现比较,不同点在于x, y, z的值要首先尝试在目标类中获取

其次,一旦类中标有此注解,即代表此类下所有接口方法都要进行防刷处理

如果其接口方法同样也标有此注解,根据就近优先原则,以接口方法中的注解标明的值为准

/**
*@author:Zero
*@time:2023/2/14
*@description:接口防刷拦截处理
*/
@Slf4j
publicclassAccessLimintInterceptorimplementsHandlerInterceptor{
@Resource
privateRedisTemplateredisTemplate;

/**
*锁住时的key前缀
*/
publicstaticfinalStringLOCK_PREFIX="LOCK";

/**
*统计次数时的key前缀
*/
publicstaticfinalStringCOUNT_PREFIX="COUNT";


publicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{

//自定义注解+反射实现,版本2.0
if(handlerinstanceofHandlerMethod){
//访问的是接口方法,转化为待访问的目标方法对象
HandlerMethodtargetMethod=(HandlerMethod)handler;
//获取目标接口方法所在类的注解@AccessLimit
AccessLimittargetClassAnnotation=targetMethod.getMethod().getDeclaringClass().getAnnotation(AccessLimit.class);
//特别注意不能采用下面这条语句来获取,因为Spring采用的代理方式来代理目标方法
//也就是说targetMethod.getClass()获得是classorg.springframework.web.method.HandlerMethod,而不知我们真正想要的Controller
//AccessLimittargetClassAnnotation=targetMethod.getClass().getAnnotation(AccessLimit.class);
//定义标记位,标记此类是否加了@AccessLimit注解
booleanisBrushForAllInterface=false;
Stringip=request.getRemoteAddr();
Stringuri=request.getRequestURI();
longsecond=0L;
longmaxTime=0L;
longforbiddenTime=0L;
if(!Objects.isNull(targetClassAnnotation)){
log.info("目标接口方法所在类上有@AccessLimit注解");
isBrushForAllInterface=true;
second=targetClassAnnotation.second();
maxTime=targetClassAnnotation.maxTime();
forbiddenTime=targetClassAnnotation.forbiddenTime();
}
//取出目标方法中的AccessLimit注解
AccessLimitaccessLimit=targetMethod.getMethodAnnotation(AccessLimit.class);
//判断此方法接口是否要进行防刷处理
if(!Objects.isNull(accessLimit)){
//需要进行防刷处理,接下来是处理逻辑
second=accessLimit.second();
maxTime=accessLimit.maxTime();
forbiddenTime=accessLimit.forbiddenTime();
if(isForbindden(second,maxTime,forbiddenTime,ip,uri)){
thrownewCommonException(ResultCode.ACCESS_FREQUENT);
}
}else{
//目标接口方法处无@AccessLimit注解,但还要看看其类上是否加了(类上有加,代表针对此类下所有接口方法都要进行防刷处理)
if(isBrushForAllInterface&&isForbindden(second,maxTime,forbiddenTime,ip,uri)){
thrownewCommonException(ResultCode.ACCESS_FREQUENT);
}
}
}
returntrue;
}

/**
*判断某用户访问某接口是否已经被禁用/是否需要禁用
*
*@paramsecond多长时间单位/秒
*@parammaxTime最大访问次数
*@paramforbiddenTime禁用时长单位/秒
*@paramip访问者ip地址
*@paramuri访问的uri
*@returnture为需要禁用
*/
privatebooleanisForbindden(longsecond,longmaxTime,longforbiddenTime,Stringip,Stringuri){
StringlockKey=LOCK_PREFIX+ip+uri;//如果此ip访问此uri被禁用时的存在Redis中的key
ObjectisLock=redisTemplate.opsForValue().get(lockKey);
//判断此ip用户访问此接口是否已经被禁用
if(Objects.isNull(isLock)){
//还未被禁用
StringcountKey=COUNT_PREFIX+ip+uri;
Objectcount=redisTemplate.opsForValue().get(countKey);
if(Objects.isNull(count)){
//首次访问
log.info("首次访问");
redisTemplate.opsForValue().set(countKey,1,second,TimeUnit.SECONDS);
}else{
//此用户前一点时间就访问过该接口,且频率没超过设置
if((Integer)count< maxTime) {
                    redisTemplate.opsForValue().increment(countKey);
                } else {
                    log.info("{}禁用访问{}", ip, uri);
                    // 禁用
                    redisTemplate.opsForValue().set(lockKey, 1, forbiddenTime, TimeUnit.SECONDS);
                    // 删除统计--已经禁用了就没必要存在了
                    redisTemplate.delete(countKey);
                    return true;
                }
            }
        } else {
            // 此用户访问此接口已被禁用
            return true;
        }
        return false;
    }
}

好了,这样就达到我们想要的效果了

b7a014d8-cdfd-11ed-bfe3-dac502259ad0.jpg

项目通过Git还原到"【自定义注解+反射实现接口自由-版本2.0】"版本即可得到此案例实现,自己可以测试万一下

这是目前来说比较理想的做法,至于其他做法,暂时没啥了解到

时间逻辑漏洞

这是我一开始都有留意到的问题

也是一直搞不懂,就是我们现在的所有做法其实感觉都不是严格意义上的x秒内y次访问次数

特别注意这个x秒,它是连续,任意的(代表这个x秒时间片段其实是可以发生在任意一个时间轴上)

我下面尝试表达我的意思,但是我不知道能不能表达清楚

假设我们固定某个接口5秒内只能访问3次,以下面例子为例

b7a8083c-cdfd-11ed-bfe3-dac502259ad0.jpg

底下的小圆圈代表此刻请求访问接口

按照我们之前所有做法的逻辑走

第2秒请求到,为首次访问,Redis中统计次数为1(过期时间为5秒)

第7秒,此时有两个动作,一是请求到,二是刚刚第二秒Redis存的值现在过期

我们先假设这一刻,请求处理完后,Redis存的值才过期

按照这样的逻辑走

第七秒请求到,Redis存在对应key,且不大于3, 次数+1

接着这个key立马过期

再继续往后走,第8秒又当做新的一个起始,就不往下说了,反正就是不会出现禁用的情况

按照上述逻辑走,实际上也就是说当出现首次访问时,当做这5秒时间片段的起始

第2秒是,第8秒也是

但是有没有想过,实际上这个5秒时间片段实际上是可以放置在时间轴上任意区域的

上述情况我们是根据请求的到来情况人为的把它放在【2-7】,【8-13】上

而实际上这5秒时间片段是可以放在任意区域的

那么,这样的话,【7-12】也可以放置

而【7-12】这段时间有4次请求,就达到了我们禁用的条件了

是不是感觉怪怪的

想过其他做法,但是好像严格意义上真的做不到我所说的那样(至少目前来说想不到)

之前我们的做法,正常来说也够用,至少说有达到防刷的作用

后面有机会的话再看看,不知道我是不是钻牛角尖了

路径参数问题

假设现在PassController中有如下接口方法

b7bd6c90-cdfd-11ed-bfe3-dac502259ad0.jpg

也就是我们在接口方法中常用的在请求路径中获取参数的套路

但是使用路径参数的话,就会发生问题

那就是同一个ip地址访问此接口时,我携带的参数值不同

按照我们之前那种前缀+ip+uri拼接的形式作为key的话,其实是区分不了的

下图是访问此接口,携带不同参数值时获取的uri状况

b7c4e394-cdfd-11ed-bfe3-dac502259ad0.jpg

这样的话在我们之前拦截器的处理逻辑中,会认为是此ip用户访问的是不同的接口方法,而实际上访问的是同一个接口方法

也就导致了【接口防刷】失效

接下来就是解决它,目前来说有两种

不要使用路径参数

这算是比较理想的做法,相当于没这个问题

但有一定局限性,有时候接手别的项目,或者自己根本没这个权限说不能使用路径参数

替换uri

我们获取uri的目的,其实就是为了区别访问接口

而把uri替换成另一种可以区分访问接口方法的标识即可

最容易想到的就是通过反射获取到接口方法名称,使用接口方法名称替换成uri即可

当然,其实不同的Controller中,其接口方法名称也有可能是相同的

实际上可以再获取接口方法所在类类名,使用类名 + 方法名称替换uri即可

实际解决方案有很多,看个人需求吧

真实ip获取

在之前的代码中,我们获取代码都是通过request.getRemoteAddr()获取的

但是后续有了解到,如果说通过代理软件方式访问的话,这样是获取不到来访者的真实ip的

至于如何获取,后续我再研究下http再说,这里先提个醒

总结

说实话,挺有意思的,一开始自己想【接口防刷】的时候,感觉也就是转化成统计下访问次数的问题摆了。后面到网上看别人的写法,又再自己给自己找点问题出来,后面会衍生出来一推东西出来,诸如自定义注解+反射这种实现方式。

以前其实对注解 + 反射其实有点不太懂干嘛用的,而从之前的数据报表导出,再到基本权限控制实现,最后到今天的【接口防刷】一点点来进步去补充自己的知识点,而且,感觉写博客真的是件挺有意义的事情,它会让你去更深入的了解某个点,并且知识是相关联的,探索的过程中会牵扯到其他别的知识点,就像之前的写的【单例模式】实现,一开始就了解到懒汉式,饿汉式

后面深入的话就知道其实会还有序列化/反序列化,反射调用生成实例,对象克隆这几种方式回去破坏单例模式,又是如何解决的,这也是一个进步的点,后续为了保证线程安全问题,牵扯到的synchronized,voliate关键字,继而又关联到JVM,JUC,操作系统的东西。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 计数器
    +关注

    关注

    32

    文章

    2256

    浏览量

    94559
  • MVC
    MVC
    +关注

    关注

    0

    文章

    73

    浏览量

    13853
  • API接口
    +关注

    关注

    1

    文章

    84

    浏览量

    10438
  • Redis
    +关注

    关注

    0

    文章

    375

    浏览量

    10872

原文标题:优雅的接口防刷处理方案

文章出处:【微信号:芋道源码,微信公众号:芋道源码】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    一种低功耗以太网接口电路的设计方案

    能力。##AX88796C支持可变I/O工作电压的SPI或Non-PCI接口,可以灵活选用不同的微处理器进行以太网接口的电路设计。##本文以以太网控制芯片AX88796C为核心,提出一种
    发表于 01-14 11:11 8241次阅读
    <b class='flag-5'>一种</b>低功耗以太网<b class='flag-5'>接口</b>电路的设计<b class='flag-5'>方案</b>

    一种低成本的 高速SRAM 替代解决方案

    本帖最后由 病友来看病 于 2017-7-11 23:13 编辑 SRAM是各种memory(SDRAM,DDR1/2/3/4, LPDDR/2/3/4)中最昂贵的一种存储方案, 高速SRAM
    发表于 07-05 22:08

    一种PCIe接口的视频采集解决方案

    一种PCIe接口的视频采集解决方案
    发表于 04-30 06:29

    一种低成本高速USB接口的设计方案

    一种基于DSP平台的低成本高速USB接口方案
    发表于 05-10 07:13

    分享一种智能卡接口的设计方案

    分享一种智能卡接口的设计方案
    发表于 05-27 06:01

    请问怎样去设计一种监狱安系统?

    为什么要设计一种监狱安系统?怎样去设计一种监狱安系统?如何对监狱安系统进行仿真测试?
    发表于 05-31 06:02

    介绍一种差分串行接口方案

    折叠式手机面临哪些问题?一种满足手机高速图像数据传输的差分串行接口方案
    发表于 06-01 06:51

    如何去实现一种高速通信接口的设计?

    一种FPGA与DSP的高速通信接口设计与实现方案
    发表于 06-02 06:07

    一种基于TMS320C6xll接口的图像获取方案

    本文提出了一种基于TMS320C6xll接口的图像获取方案
    发表于 06-03 06:53

    分享一种CH451与AMEG32的接口方案

    分享一种CH451与AMEG32的接口方案
    发表于 06-04 06:06

    一种基于GSM和Zigbee技术的无线安系统

    ,为安系统的建设提供了一种灵活、方便的无线解决方案。该系统具有良好的可扩展性和实用价值,可以实现全方位的安全监控与防护,而其最重要的点在于,该系统能够通过无线网络可靠地与用户通信,
    发表于 12-01 09:36

    分享一种基于littlevgl2rtt软件包的RGB屏幕接口优化方案

    DMA2D的方式,一种是中断方式,一种是轮询方式。如果使用中断方式,需要添加DMA2D中断处理函数。两者的区别就是,采用轮询方式的,则直等待DMA2D传输结束,然后通过函数
    发表于 06-07 14:57

    一种高速串行视频接口TIDA-00137参考设计

    描述TIDA-00137 参考设计是一种高速串行视频接口,通过此接口,可将采用 DVP (LVCMOS) 接口的远程汽车 WVGA TFT LCD 显示屏连接到视频
    发表于 09-19 07:05

    一种篡改的电能表

    一种篡改的电能表
    发表于 04-17 17:39 5次下载
    <b class='flag-5'>一种</b><b class='flag-5'>防</b>篡改的电能表

    优雅接口处理方案

    采用https协议可以将传输的明文进行加密,但是黑客仍然可以截获传输的数据包,进步伪造请求进行重放攻击。如果黑客使用特殊手段让请求方设备使用了伪造的证书进行通信,那么https加密的内容也会被解密。
    的头像 发表于 04-14 10:59 639次阅读