淘系的技术发展已经有相当一段历史了,在历史的长河中总能沉淀出很多复杂的巨型项目,包罗多个业务,而且往往服务依赖比较复杂;再加上一些特殊环境变量的设置,想要在本地运行、debug 自测这种大型应用的难度越来越高;尤其是对环境不太熟悉的新人而言成本会更高。
这类应用的单元测试不能像微服务化的应用一样,可以方便的将整个 service 在本地 Run Test,但是依靠于日常开发部署环境的远程 debug、日志、Arthas 等工具定位项目自测联调中的问题又会显得格外的笨重,问题修复几秒钟,发布一次 10min 会成为严重的效率瓶颈。
如何高效的自测代码逻辑,如何不启动整个服务就能验证我的目标方法呢?那就是我今天要介绍的三板斧 Mockito + PowerMock + AssertJ
上手
Mock 框架能帮助我们 mock 待测试的类中使用到的外部服务依赖,分布式缓存,DB查询等复杂逻辑,让我们轻松验证待测试类的目标方法的逻辑,当遇到外部依赖时可通过存根 mock 对应的返回结果,从而专注于验证本方法的逻辑正确性,而且跑单元测试不用把整个项目在本地跑起来,只会把当前测试所用到的类加载出来。换言之,Mock 能让代码对外部系统(或复杂依赖)隔离,不需要进行各种初始化操作。在假设外部依赖都能如预期返回的情况下验证自身逻辑的自洽性。
talk is cheap,show me your code. 开始盘它~
▐ 配置 Maven 依赖
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.5.2</version><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>2.0.5</version><scope>test</scope></dependency><dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><version>2.0.5</version><scope>test</scope></dependency><dependency><groupId>org.assertj</groupId><artifactId>assertj-core</artifactId><!-- use 2.9.1 for Java 7 projects --><version>3.17.1</version><scope>test</scope></dependency>
▐ Mockito
Mockito 可以 mock 类的 public 方法或接口的方法。它是通过 cglib 动态生成一个 Proxy,因此在未指定某个方法行为的情况下,会默认返回空值,当然,一个完善的框架肯定会支持直接访问被代理的对象的真实方法的,下文会有介绍,一共会有3种方式哦,我们继续吧。
这里我们使用的 mock 类定义如下:
import java.util.concurrent.TimeUnit;public class MockTarget {public void soSth() {System.out.println("do sth.");}public String sayHello() {return "Hello";}public String sayHello(String greetings) {return "Hello " + greetings;}public String callMethod(Object p) {return "callMethod " + p.toString();}public String callMethodWait(long million) {try {TimeUnit.MILLISECONDS.sleep(million);} catch (InterruptedException ignored) {}return "callMethod sleep " + million;}public Object callMethodWithException(Object p) {throw new IllegalStateException("测试异常");}}
when..then
用于 mock 方法调用的各种返回情况。
-
通过 doCallRealMethod 指定 mock 对象的方法调用它的真实逻辑,也可通过 thenAnswer(Answers.CALLS_REAL_METHODS) 实现
-
通过 when..thenThrow 或者 doThrow..when 的方式 mock 目标方法返回对应的异常
-
通过 AssertJ 的句法 assertThatExceptionOfType..isThrownBy..withXxx断言某个方法的执行会抛出预期异常
-
anyXxx() 可用于表示任意类型的任意参数
-
anyString() 代表任意字符串
-
anyInt() 代表任意int数值
-
anyObject() 代表任意类型对象
-
@Testpublic void testWhenAndThen() {MockTarget mock = Mockito.mock(MockTarget.class);when(mock.sayHello()).thenReturn("mock hello");assertEquals(mock.sayHello(), "mock hello");doCallRealMethod().when(mock).sayHello();assertEquals(mock.sayHello(), "Hello");when(mock.sayHello(anyString())).thenAnswer(Answers.CALLS_REAL_METHODS);assertEquals(mock.sayHello("testRun"), "Hello testRun");when(mock.callMethod(any())).thenReturn("mock return");assertEquals(mock.callMethod(new Object()), "mock return");when(mock.callMethodWithException(any())).thenThrow(new RuntimeException("mock throw exception"), new IllegalArgumentException("test illegal argument"));Assertions.assertThatExceptionOfType(RuntimeException.class).isThrownBy(() -> mock.callMethodWithException("first invoke")).withMessage("mock throw exception");Assertions.assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> mock.callMethodWithException("second invoke")).withMessage("test illegal argument").withNoCause();doAnswer((Answer<String>) invocation -> {Object[] args = invocation.getArguments();MockTarget mock1 = (MockTarget) invocation.getMock();return "mock sayHello " + args[0];}).when(mock).sayHello("doAnswer");assertEquals(mock.sayHello("doAnswer"), "mock sayHello doAnswer");// 1.doNothing, 2. throw RuntimeExceptiondoNothing().doThrow(RuntimeException.class).when(mock).soSth();mock.soSth();Assertions.assertThatExceptionOfType(RuntimeException.class).isThrownBy(mock::soSth);}
verify
用于验证某个方法是否被调用,包括可以验证该方法被调用的次数,以及等待异步方法调用完成等特性。
常用句式 verify(mockObject [, times(n) ] ).targetMethod
@Testpublic void testVerifyInteractions() {// mock creationList mockedList = mock(List.class);mockedList.clear();// only clear() invokedverify(mockedList, only()).clear();verifyNoMoreInteractions(mockedList);// 此处不会抛异常,因为是mock的list对象,非实际list对象when(mockedList.get(1)).thenReturn("two");assertEquals(mockedList.get(1), "two");// using mock object - it does not throw any "unexpected interaction" exceptionmockedList.add("one");// selective, explicit, highly readable verificationverify(mockedList).add("one");verify(mockedList, times(1)).clear();verify(mockedList, atLeastOnce()).add("one");verify(mockedList, atMostOnce()).add("one");verify(mockedList, atMost(1)).add("one");verify(mockedList, atLeast(1)).add("one");verify(mockedList, never()).add("never");}
verify 之 after 与 timeout
针对异步调用,我们可以通过 after 或 timeout 等待一定时间,来校验目标方法是否有调用,以及在此之后获取目标方法的返回值,作进一步逻辑校验
-
after 会阻塞等满时间之后再往下执行,是固定等待多长时间的语义
-
timeout 在等待期内,拿到结果后立即向下执行,不做多余等待;是最多等待多长时间的语义
@Testpublic void testAfterAndTimeout() throws Exception {MockTarget mock = mockTarget;doCallRealMethod().when(mock).callMethodWait(anyLong());final long timeout = 500L;final long delta = 100L;// 异步调用CompletableFuture<Void> async = CompletableFuture.runAsync(() -> {try {TimeUnit.MILLISECONDS.sleep(timeout);} catch (InterruptedException ignored) {}mock.sayHello();mock.callMethod("test");mock.callMethod("test");});// timeout() exits immediately with success when verification passes// verify(mock, description("invoke not yet, This will print on failure")).callMethod("test");verify(mock, timeout(timeout + delta).times(2)).callMethod("test");// immediately successverify(mock, timeout(10)).sayHello();async.get();// after() awaits full duration to check if verification passesverify(mock, after(10).times(2)).callMethod("test");verify(mock, after(10)).sayHello();}
spy
spy 的官方定义是:
partial mocking, real methods are invoked but still can be verified and stubbed
会调用被 spy 的真实对象的方法,但仍能被 Mockiton 所直接用于 mock 和 verify,也就是说在没有配置 mock 行为的情况下默认是调用被 mock 对象的真实方法。
-
句式 doXxx..when 当同一目标方法上定义了多个 mock 行为,后序 mock 可以覆盖前序 mock
-
clearInvocations 仅清理之前的调用
-
reset 会重置为初始状态(所有中途的赋值都会被清理掉)
@Testpublic void testDoReturn() {// real creationList list = new LinkedList();List spy = spy(list);//optionally, you can stub out some methods:int mockSize = 100;when(spy.size()).thenReturn(mockSize);//size() method was stubbed - 100 is printedassertEquals(spy.size(), mockSize);// Overriding a previous exception-stubbing:when(spy.size()).thenThrow(new IllegalStateException("not init"));doReturn(mockSize).when(spy).size();assertEquals(spy.size(), mockSize);//Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)Assertions.assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> spy.get(0));doReturn("mock data").when(spy).get(1);//using the spy calls real methodsspy.add("one");assertEquals(spy.get(0), "one");/*Use this method in order to only clear invocations, when stubbing is non-trivial. Use-cases can be:You are using a dependency injection framework to inject your mocks.The mock is used in a stateful scenario. For example a class is Singleton which depends on your mock.Try to avoid this method at all costs. Only clear invocations if you are unable to efficiently test your program.*/clearInvocations(spy);verify(spy, times(0)).add("two");reset(spy);when(spy.size()).thenReturn(0);assertEquals(spy.size(), 0);}
▐ PowerMock
以上介绍的是 Mockiton 中常用的API,而 PowerMock 则更强大,可以 mock static 方法,private 方法,final 方法,enum,构造函数调用等。
示例代码中用到的测试类如下:
public enum TypeEnum {Y("TRUE"),N("FALSE");private final String title;TypeEnum(String title) {this.title = title;}public String getTitle() {return title;}}public final class FinalTarget {public FinalTarget() { }public final String finalMethod() {return "Hello final!";}}public class StaticTarget {public static String firstMethod(String name) {return "Hello " + name + " !";}public static String secondMethod() {return "Hello no one!";}}public class PartialTarget {private String arg;public PartialTarget(String arg) {this.arg = arg;}public PartialTarget() { }public String getArg() {return arg;}private String privateWithArg(String arg) {return "Hello privateWithArg! " + arg;}public String privateMethodCaller(String arg) {return privateWithArg(arg) + " privateMethodCall.";}}
类注解
在使用 PowerMockito mock static , private , final , enum , constructor 之前需要在测试类上加入如下注解:
@RunWith(PowerMockRunner.class)@PrepareForTest({StaticTarget.class, PartialTarget.class, TypeEnum.class, FinalTarget.class})
static
PowerMockito.mockStatic 声明了要 mock static 方法的类
PowerMockito.mockStatic(StaticTarget.class);StaticTarget.firstMethod("xxx");
verify
值得注意的是,它的 verify 方法使用比 Mockiton 更复杂。
需要先声明一下验证目标类的静态方法再紧接着调用一下,表示待验证的目标方法
PowerMockito.verifyStatic(StaticTarget.class); // 1StaticTarget.firstMethod(invokeParam); // 2
也有类似于 Mockiton 的调用次数校验:
PowerMockito.verifyStatic(StaticTarget.class, times(1));PowerMockito.verifyStatic(StaticTarget.class, Mockito.atLeastOnce());
private
PowerMock 模拟 private 方法 "privateWithArg" 的返回值并校验 "privateWithArg" 被调用的次数
PartialTarget partialMock = PowerMockito.mock(PartialTarget.class);doCallRealMethod().when(partialMock).privateMethodCaller(anyString());PowerMockito.doReturn("mockResult").when(partialMock, "privateWithArg", any());// *privateMethodCaller* will invoke method *privateWithArg*String result = partialMock.privateMethodCaller("arg");Assert.assertEquals(result, "mockResult privateMethodCall.");PowerMockito.verifyPrivate(partialMock, times(1)).invoke("privateWithArg", "arg");
final
PowerMock 校验 mock final方法
FinalTarget finalTarget = PowerMockito.mock(FinalTarget.class);String finalReturn = "finalReturn";PowerMockito.when(finalTarget.finalMethod()).thenReturn(finalReturn);Assert.assertThat(finalTarget.finalMethod(), is(finalReturn));
enum
PowerMock mock enum,这里的 Whitebox.setInternalState 可以设置 TypeEnum fieldName=N 的值为给定的 mock 枚举
String mockValue = "mock title";TypeEnum typeMock = PowerMockito.mock(TypeEnum.class);Whitebox.setInternalState(TypeEnum.class, "N", typeMock);when(typeMock.getTitle()).thenReturn(mockValue);Assert.assertEquals(TypeEnum.N.getTitle(), mockValue);Assert.assertEquals(TypeEnum.Y.getTitle(), "TRUE");
constructor
构造器 mock 与 verify
String arg = "special arg";PartialTarget partialWithArgSpy = PowerMockito.spy(new PartialTarget(arg));whenNew(PartialTarget.class).withNoArguments().thenReturn(partialWithArgSpy);PartialTarget partialNoArg = new PartialTarget();Assert.assertEquals(partialNoArg.getArg(), arg);verifyNew(PartialTarget.class).withNoArguments();
完整示例如下:
import org.assertj.core.api.Assertions;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.mockito.Mockito;import org.powermock.api.mockito.PowerMockito;import org.powermock.core.classloader.annotations.PrepareForTest;import org.powermock.modules.junit4.PowerMockRunner;import org.powermock.reflect.Whitebox;import static org.hamcrest.core.Is.is;import static org.mockito.ArgumentMatchers.anyString;import static org.mockito.Mockito.times;import static org.powermock.api.mockito.PowerMockito.doCallRealMethod;import static org.powermock.api.mockito.PowerMockito.verifyNew;import static org.powermock.api.mockito.PowerMockito.when;import static org.powermock.api.mockito.PowerMockito.whenNew;@RunWith(PowerMockRunner.class)@PrepareForTest({StaticTarget.class, PartialTarget.class, TypeEnum.class, FinalTarget.class})public class PowerMockTest {@Testpublic void testStatic() throws Exception {PowerMockito.mockStatic(StaticTarget.class);String mockResult = "Static mock";PowerMockito.when(StaticTarget.firstMethod(anyString())).thenReturn(mockResult);String invokeParam = "any String parameter";Assert.assertEquals(StaticTarget.firstMethod(invokeParam), mockResult);// Verification of a static method is done in two steps.PowerMockito.verifyStatic(StaticTarget.class); // 1// StaticTarget.secondMethod();// not invokedStaticTarget.firstMethod(invokeParam);// 2// use argument matchersPowerMockito.verifyStatic(StaticTarget.class); // 1StaticTarget.firstMethod(anyString()); // 2// atLeastOncePowerMockito.verifyStatic(StaticTarget.class, Mockito.atLeastOnce()); // 1StaticTarget.firstMethod(anyString()); // 2// timesPowerMockito.verifyStatic(StaticTarget.class, times(1)); // 1StaticTarget.firstMethod(anyString()); // 2// partial mocking of a private method & verifyPrivate// PartialTarget partialNoArgSpy = PowerMockito.spy(new PartialTarget());PartialTarget partialMock = PowerMockito.mock(PartialTarget.class);doCallRealMethod().when(partialMock, "privateMethodCaller", anyString());PowerMockito.doReturn("mockResult").when(partialMock, "privateWithArg", any());// *privateMethodCaller* will invoke method *privateWithArg*String result = partialMock.privateMethodCaller("arg");Assert.assertEquals(result, "mockResult privateMethodCall.");PowerMockito.verifyPrivate(partialMock, times(1)).invoke("privateWithArg", "arg");// FinalFinalTarget finalTarget = PowerMockito.mock(FinalTarget.class);String finalReturn = "finalReturn";PowerMockito.when(finalTarget.finalMethod()).thenReturn(finalReturn);Assert.assertThat(finalTarget.finalMethod(), is(finalReturn));// enumString mockValue = "mock title";TypeEnum typeMock = PowerMockito.mock(TypeEnum.class);Whitebox.setInternalState(TypeEnum.class, "N", typeMock);when(typeMock.getTitle()).thenReturn(mockValue);Assert.assertEquals(TypeEnum.N.getTitle(), mockValue);Assert.assertEquals(TypeEnum.Y.getTitle(), "TRUE");// verify NewString arg = "special arg";PartialTarget partialWithArgSpy = PowerMockito.spy(new PartialTarget(arg));whenNew(PartialTarget.class).withNoArguments().thenReturn(partialWithArgSpy);PartialTarget partialNoArg = new PartialTarget();Assert.assertEquals(partialNoArg.getArg(), arg);verifyNew(PartialTarget.class).withNoArguments();// throw exceptionPowerMockito.doThrow(new ArrayStoreException("Mock secondMethod error")).when(StaticTarget.class);StaticTarget.secondMethod();// AssertJ: Exception assertionsAssertions.assertThatThrownBy(StaticTarget::secondMethod).isInstanceOf(ArrayStoreException.class).hasNoCause().hasMessage("Mock secondMethod error");}}
▐ AssertJ
上面提到的 AssertJ 是 Assert 的一些功能增强,以流式编程的方式调用,下面介绍一些常用的用法
-
isIn,isNotIn 和 matches 用于断言匹配条件
-
filteredOn 可以针对 assertThat 中传入的参数进行过滤,类似 java8 中Stream() 的 filter 方法
-
extracting 可以针对 assertThat 中传入的元组进行字段提取校验
-
assertThatExceptionOfType 和 assertThatThrownBy 可用于捕获预期的异常
为了方便使用,AssertJ 还提供了几种常用的异常断言的包装器:
// AssertJ provides wrappers for common exception typesAssertions.assertThatNoException();Assertions.assertThatIOException();Assertions.assertThatNullPointerException();Assertions.assertThatIllegalStateException();Assertions.assertThatIllegalArgumentException();
示例如下:
import org.assertj.core.api.Assertions;import org.junit.Test;import java.util.Arrays;import java.util.List;import static org.assertj.core.api.Assertions.tuple;public class AssertTest {@Testpublic void testAssertJ() {String title = "foo";AssertTarget assertTarget = new AssertTarget(title, 12, TypeEnum.Y);String msg = "Illegal Argument error";Exception cause = new NullPointerException("cause exception msg");Assertions.assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> assertTarget.throwIllegalArgumentException(msg, cause)).withMessage(msg).withMessageContaining("Argument error").overridingErrorMessage("new error message").withCause(cause);Assertions.assertThatThrownBy(() -> assertTarget.throwIllegalArgumentException(msg, cause)).isInstanceOf(IllegalArgumentException.class).hasMessageContaining("Argument error");Assertions.assertThat(assertTarget.getTitle())// as() is used to describe the test and will be shown before the error message.as("PartialTarget's arg is not match", assertTarget.getTitle()).startsWith(title).endsWith(title).contains(title).isNotEqualTo("foo bar").isEqualToIgnoringCase("FOO").isEqualTo(title);AssertTarget target1 = new AssertTarget("testTitle", 12, TypeEnum.N);AssertTarget target2 = new AssertTarget("titleVal1", 16, TypeEnum.N);AssertTarget target3 = new AssertTarget("titleVal2", 18, TypeEnum.Y);AssertTarget target4 = new AssertTarget("titleVal3", 20, TypeEnum.N);List<AssertTarget> assertTargetRing = Arrays.asList(target1, target2, target3);Assertions.assertThat(target1.getNum()).withFailMessage("the num not matches").isEqualTo(12);Assertions.assertThat(target1.getType().equals(TypeEnum.N)).isTrue();Assertions.assertThat(target1).isIn(assertTargetRing);Assertions.assertThat(target4).isNotIn(assertTargetRing);Assertions.assertThat(target4).matches(e -> e.getNum() > 18 && e.getType().equals(TypeEnum.N));Assertions.assertThat(assertTargetRing)// extracting multiple values at once grouped in tuples.extracting("num", "type.title").contains(tuple(16, TypeEnum.N.getTitle()), tuple(18, TypeEnum.Y.getTitle()));Assertions.assertThat(assertTargetRing)// filtering a collection before asserting.filteredOn(e -> e.getTitle().startsWith("title")).extracting(AssertTarget::getNum).contains(16, 18);}}
真香
以上针对自己使用的 mock 单元测试的三板斧 Mockito + PowerMock + AssertJ 常用姿势做了小结。
-
利用 Mockiton 做常规类和接口的 mock
-
PowerMock 则可以 mock 静态方法,私有方法,final 方法,枚举,构造函数等
-
AssertJ 流式风格,增强 assert 判断逻辑和校验异常流程
更多姿势等待大家在实操中继续解锁,利用这些姿势在后续的开发自测中可以更快速的做自我逻辑验证,而我再也不必等待每次项目开发环境的 10min 部署了。
这两年,IT行业面临经济周期波动与AI产业结构调整的双重压力,确实有很多运维与网络工程师因企业缩编或技术迭代而暂时失业。
很多人都在提运维网工失业后就只能去跑滴滴送外卖了,但我想分享的是,对于运维人员来说,即便失业以后仍然有很多副业可以尝试。
网工/运维副业方向
运维网工,千万不要再错过这些副业机会!
第一个是知识付费类副业:输出经验打造个人IP
在线教育平台讲师
操作路径:在慕课网、极客时间等平台开设《CCNA实战》《Linux运维从入门到精通》等课程,或与培训机构合作录制专题课。
收益模式:课程销售分成、企业内训。
技术博客与公众号运营
操作路径:撰写网络协议解析、故障排查案例、设备评测等深度文章,通过公众号广告、付费专栏及企业合作变现。
收益关键:每周更新2-3篇原创,结合SEO优化与社群运营。
第二个是技术类副业:深耕专业领域变现
企业网络设备配置与优化服务
操作路径:为中小型企业提供路由器、交换机、防火墙等设备的配置调试、性能优化及故障排查服务。可通过本地IT服务公司合作或自建线上接单平台获客。
收益模式:按项目收费或签订年度维护合同。
远程IT基础设施代维
操作路径:通过承接服务器监控、日志分析、备份恢复等远程代维任务。适合熟悉Zabbix、ELK等技术栈的工程师。
收益模式:按工时计费或包月服务。
网络安全顾问与渗透测试
操作路径:利用OWASP Top 10漏洞分析、Nmap/BurpSuite等工具,为企业提供漏洞扫描、渗透测试及安全加固方案。需考取CISP等认证提升资质。
收益模式:单次渗透测试报告收费;长期安全顾问年费。
比如不久前跟我一起聊天的一个粉丝,他自己之前是大四实习的时候做的运维,发现运维7*24小时待命受不了,就准备转网安,学了差不多2个月,然后开始挖漏洞,光是补天的漏洞奖励也有个四五千,他说自己每个月的房租和饭钱就够了。

为什么我会推荐你网安是运维和网工人员的绝佳副业&转型方向?
1.你的经验是巨大优势: 你比任何人都懂系统、网络和架构。漏洞挖掘、内网渗透、应急响应,这些核心安全能力本质上是“攻击视角下的运维”。你的运维背景不是从零开始,而是降维打击。
2.越老越吃香,规避年龄危机: 安全行业极度依赖经验。你的排查思路、风险意识和对复杂系统的理解能力,会随着项目积累而愈发珍贵,真正做到“姜还是老的辣”。
3.职业选择极其灵活: 你可以加入企业成为安全专家,可以兼职“挖洞“获取丰厚奖金,甚至可以成为自由顾问。这种多样性为你提供了前所未有的抗风险能力。
4.市场需求爆发,前景广阔: 在国家级政策的推动下,从一线城市到二三线地区,安全人才缺口正在急剧扩大。现在布局,正是抢占未来先机的黄金时刻。

网工运维转行学习网络安全路线

(一)第一阶段:网络安全筑基
1. 阶段目标
你已经有运维经验了,所以操作系统、网络协议这些你不是零基础。但要学安全,得重新过一遍——只不过这次我们是带着“安全视角”去学。
2. 学习内容
**操作系统强化:**你需要重点学习 Windows、Linux 操作系统安全配置,对比运维工作中常规配置与安全配置的差异,深化系统安全认知(比如说日志审计配置,为应急响应日志分析打基础)。
**网络协议深化:**结合过往网络协议应用经验,聚焦 TCP/IP 协议簇中的安全漏洞及防护机制,如 ARP 欺骗、TCP 三次握手漏洞等(为 SRC 漏扫中协议层漏洞识别铺垫)。
**Web 与数据库基础:**补充 Web 架构、HTTP 协议及 MySQL、SQL Server 等数据库安全相关知识,了解 Web 应用与数据库在网安中的作用。
**编程语言入门:**学习 Python 基础语法,掌握简单脚本编写,为后续 SRC 漏扫自动化脚本开发及应急响应工具使用打基础。
**工具实战:**集中训练抓包工具(Wireshark)、渗透测试工具(Nmap)、漏洞扫描工具(Nessus 基础版)的使用,结合模拟场景练习工具应用(掌握基础扫描逻辑,为 SRC 漏扫工具进阶做准备)。
(二)第二阶段:漏洞挖掘与 SRC 漏扫实战
1. 阶段目标
这阶段是真正开始“动手”了。信息收集、漏洞分析、工具联动,一样不能少。
熟练运用漏洞挖掘及 SRC 漏扫工具,具备独立挖掘常见漏洞及 SRC 平台漏扫实战能力,尝试通过 SRC 挖洞搞钱,不管是低危漏洞还是高危漏洞,先挖到一个。
2. 学习内容
信息收集实战:结合运维中对网络拓扑、设备信息的了解,强化基本信息收集、网络空间搜索引擎(Shodan、ZoomEye)、域名及端口信息收集技巧,针对企业级网络场景开展信息收集练习(为 SRC 漏扫目标筛选提供支撑)。
漏洞原理与分析:深入学习 SQL 注入、CSRF、文件上传等常见漏洞的原理、危害及利用方法,结合运维工作中遇到的类似问题进行关联分析(明确 SRC 漏扫重点漏洞类型)。
工具进阶与 SRC 漏扫应用:
-
系统学习 SQLMap、BurpSuite、AWVS 等工具的高级功能,开展工具联用实战训练;
-
专项学习 SRC 漏扫流程:包括 SRC 平台规则解读(如漏洞提交规范、奖励机制)、漏扫目标范围界定、漏扫策略制定(全量扫描 vs 定向扫描)、漏扫结果验证与复现;
-
实战训练:使用 AWVS+BurpSuite 组合开展 SRC 平台目标漏扫,练习 “扫描 - 验证 - 漏洞报告撰写 - 平台提交” 全流程。
SRC 实战演练:选择合适的 SRC 平台(如补天、CNVD)进行漏洞挖掘与漏扫实战,积累实战经验,尝试获取挖洞收益。
恭喜你,如果学到这里,你基本可以下班搞搞副业创收了,并且具备渗透测试工程师必备的「渗透技巧」、「溯源能力」,让你在黑客盛行的年代别背锅,工作实现升职加薪的同时也能开创副业创收!
如果你想要入坑黑客&网络安全,笔者给大家准备了一份:全网最全的网络安全资料包需要保存下方图片,微信扫码即可前往获取!
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
Mockito与PowerMock单元测试实战
