先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上网络安全知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
线程有可能只对工作内存中的副本进行赋值,只到最后一次赋值后才同步到主存储区,所以assign,store,weite顺序可以由JVM实现系统决定。假设有一个共享变量x,线程a执行x=x+1。从上面的描述中可以知道x=x+1并不是一个原子操作,它的执行过程如下:
1 从主存中读取变量x副本到工作内存
2 给x加1
3 将x加1后的值写回主 存
如果另外一个线程b执行x=x-1,执行过程如下:
1 从主存中读取变量x副本到工作内存
2 给x减1
3 将x减1后的值写回主存
那么显然,最终的x的值是不可靠的。假设x现在为10,线程a加1,线程b减1,从表面上看,似乎最终x还是为10,但是多线程情况下会有这种情况发生:
1:线程a从主存读取x副本到工作内存,工作内存中x值为10
2:线程b从主存读取x副本到工作内存,工作内存中x值为10
3:线程a将工作内存中x加1,工作内存中x值为11
4:线程a将x提交主存中,主存中x为11
5:线程b将工作内存中x值减1,工作内存中x值为9
6:线程b将x提交到中主存中,主存中x为9
同样,x有可能为11,如果x是一个银行账户,线程a存款,线程b扣款,显然这样是有严重问题的,要解决这个问题,必须保证线程a和线程b是有序执行的,并且每个线程执行的加1或减1是一个原子操作。看看下面代码:
-
public class Account {
-
private int balance;
-
public Account(int balance) {
-
this.balance = balance;
-
}
-
public int getBalance() {
-
return balance;
-
}
-
public void add(int num) {
-
balance = balance + num;
-
}
-
public void withdraw(int num) {
-
balance = balance - num;
-
}
-
public static void main(String[] args) throws InterruptedException {
-
Account account = new Account(1000);
-
Thread a = new Thread(new AddThread(account, 20), “add”);
-
Thread b = new Thread(new WithdrawThread(account, 20), “withdraw”);
-
a.start();
-
b.start();
-
a.join();
-
b.join();
-
System.out.println(account.getBalance());
-
}
-
static class AddThread implements Runnable {
-
Account account;
-
int amount;
-
public AddThread(Account account, int amount) {
-
this.account = account;
-
this.amount = amount;
-
}
-
public void run() {
-
for (int i = 0; i < 200000; i++) {
-
account.add(amount);
-
}
-
}
-
}
-
static class WithdrawThread implements Runnable {
-
Account account;
-
int amount;
-
public WithdrawThread(Account account, int amount) {
-
this.account = account;
-
this.amount = amount;
-
}
-
public void run() {
-
for (int i = 0; i < 100000; i++) {
-
account.withdraw(amount);
-
}
-
}
-
}
-
}
public class Account {
private int balance;
public Account(int balance) {
this.balance = balance;
}
public int getBalance() {
return balance;
}
public void add(int num) {
balance = balance + num;
}
public void withdraw(int num) {
balance = balance - num;
}
public static void main(String[] args) throws InterruptedException {
Account account = new Account(1000);
Thread a = new Thread(new AddThread(account, 20), “add”);
Thread b = new Thread(new WithdrawThread(account, 20), “withdraw”);
a.start();
b.start();
a.join();
b.join();
System.out.println(account.getBalance());
}
static class AddThread implements Runnable {
Account account;
int amount;
public AddThread(Account account, int amount) {
this.account = account;
this.amount = amount;
}
public void run() {
for (int i = 0; i < 200000; i++) {
account.add(amount);
}
}
}
static class WithdrawThread implements Runnable {
Account account;
int amount;
public WithdrawThread(Account account, int amount) {
this.account = account;
this.amount = amount;
}
public void run() {
for (int i = 0; i < 100000; i++) {
account.withdraw(amount);
}
}
}
}
第一次执行结果为10200,第二次执行结果为1060,每次执行的结果都是不确定的,因为线程的执行顺序是不可预见的。这是java同步产生的根源,synchronized关键字保证了多个线程对于同步块是互斥的,synchronized作为一种同步手段,解决java多线程的执行有序性和内存可见性,而volatile关键字之解决多线程的内存可见性问题。后面将会详细介绍。
synchronized关键字
上面说了,java用synchronized关键字做为多线程并发环境的执行有序性的保证手段之一。当一段代码会修改共享变量,这一段代码成为互斥区或临界区,为了保证共享变量的正确性,synchronized标示了临界区。典型的用法如下:
-
synchronized(锁){
-
临界区代码
-
}
synchronized(锁){
临界区代码
}
为了保证银行账户的安全,可以操作账户的方法如下:
-
public synchronized void add(int num) {
-
balance = balance + num;
-
}
-
public synchronized void withdraw(int num) {
-
balance = balance - num;
-
}
public synchronized void add(int num) {
balance = balance + num;
}
public synchronized void withdraw(int num) {
balance = balance - num;
}
刚才不是说了synchronized的用法是这样的吗:
-
synchronized(锁){
-
临界区代码
-
}
synchronized(锁){
临界区代码
}
那么对于public synchronized void add(int num)这种情况,意味着什么呢?其实这种情况,锁就是这个方法所在的对象。同理,如果方法是public static synchronized void add(int num),那么锁就是这个方法所在的class。
理论上,每个对象都可以做为锁,但一个对象做为锁时,应该被多个线程共享,这样才显得有意义,在并发环境下,一个没有共享的对象作为锁是没有意义的。假如有这样的代码:
-
public class ThreadTest{
-
public void test(){
-
Object lock=new Object();
-
synchronized (lock){
-
//do something
-
}
-
}
-
}
public class ThreadTest{
public void test(){
Object lock=new Object();
synchronized (lock){
//do something
}
}
}
lock变量作为一个锁存在根本没有意义,因为它根本不是共享对象,每个线程进来都会执行Object lock=new Object();每个线程都有自己的lock,根本不存在锁竞争。
每个锁对象都有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,当一个被线程被唤醒 (notify)后,才会进入到就绪队列,等待cpu的调度。当一开始线程a第一次执行account.add方法时,jvm会检查锁对象account 的就绪队列是否已经有线程在等待,如果有则表明account的锁已经被占用了,由于是第一次运行,account的就绪队列为空,所以线程a获得了锁,执行account.add方法。如果恰好在这个时候,线程b要执行account.withdraw方法,因为线程a已经获得了锁还没有释放,所以线程 b要进入account的就绪队列,等到得到锁后才可以执行。
一个线程执行临界区代码过程如下:
1 获得同步锁
2 清空工作内存
3 从主存拷贝变量副本到工作内存
4 对这些变量计算
5 将变量从工作内存写回到主存
6 释放锁
可见,synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。
生产者/消费者模式
生产者/消费者模式其实是一种很经典的线程同步模型,很多时候,并不是光保证多个线程对某共享资源操作的互斥性就够了,往往多个线程之间都是有协作的。
假设有这样一种情况,有一个桌子,桌子上面有一个盘子,盘子里只能放一颗鸡蛋,A专门往盘子里放鸡蛋,如果盘子里有鸡蛋,则一直等到盘子里没鸡蛋,B专门从盘子里拿鸡蛋,如果盘子里没鸡蛋,则等待直到盘子里有鸡蛋。其实盘子就是一个互斥区,每次往盘子放鸡蛋应该都是互斥的,A的等待其实就是主动放弃锁,B 等待时还要提醒A放鸡蛋。
如何让线程主动释放锁
很简单,调用锁的wait()方法就好。wait方法是从Object来的,所以任意对象都有这个方法。看这个代码片段:
-
Object lock=new Object();//声明了一个对象作为锁
-
synchronized (lock) {
-
balance = balance - num;
-
//这里放弃了同步锁,好不容易得到,又放弃了
-
lock.wait();
-
}
Object lock=new Object();//声明了一个对象作为锁
synchronized (lock) {
balance = balance - num;
//这里放弃了同步锁,好不容易得到,又放弃了
lock.wait();
}
如果一个线程获得了锁lock,进入了同步块,执行lock.wait(),那么这个线程会进入到lock的阻塞队列。如果调用 lock.notify()则会通知阻塞队列的某个线程进入就绪队列。
声明一个盘子,只能放一个鸡蛋
-
import java.util.ArrayList;
-
import java.util.List;
-
public class Plate {
-
List eggs = new ArrayList();
-
public synchronized Object getEgg() {
-
while(eggs.size() == 0) {
-
try {
-
wait();
-
} catch (InterruptedException e) {
-
}
-
}
-
Object egg = eggs.get(0);
-
eggs.clear();// 清空盘子
-
notify();// 唤醒阻塞队列的某线程到就绪队列
-
System.out.println(“拿到鸡蛋”);
-
return egg;
-
}
-
public synchronized void putEgg(Object egg) {
-
while(eggs.size() > 0) {
-
try {
-
wait();
-
} catch (InterruptedException e) {
-
}
-
}
-
eggs.add(egg);// 往盘子里放鸡蛋
-
notify();// 唤醒阻塞队列的某线程到就绪队列
-
System.out.println(“放入鸡蛋”);
-
}
-
static class AddThread extends Thread{
-
private Plate plate;
-
private Object egg=new Object();
-
public AddThread(Plate plate){
-
this.plate=plate;
-
}
-
public void run(){
-
for(int i=0;i<5;i++){
-
plate.putEgg(egg);
-
}
-
}
-
}
-
static class GetThread extends Thread{
-
private Plate plate;
-
public GetThread(Plate plate){
-
this.plate=plate;
-
}
-
public void run(){
-
for(int i=0;i<5;i++){
-
plate.getEgg();
-
}
-
}
-
}
-
public static void main(String args[]){
-
try {
-
Plate plate=new Plate();
-
Thread add=new Thread(new AddThread(plate));
-
Thread get=new Thread(new GetThread(plate));
-
add.start();
-
get.start();
-
add.join();
-
get.join();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
System.out.println(“测试结束”);
-
}
-
}
import java.util.ArrayList;
import java.util.List;
public class Plate {
如何自学黑客&网络安全
黑客零基础入门学习路线&规划
初级黑客
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)
2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等
3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)
4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现
5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固
6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k
到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?
如果你想要入坑黑客&网络安全,笔者给大家准备了一份:282G全网最全的网络安全资料包评论区留言即可领取!
7、脚本编程(初级/中级/高级)
在网络安全领域。是否具备编程能力是“脚本小子”和真正黑客的本质区别。在实际的渗透测试过程中,面对复杂多变的网络环境,当常用工具不能满足实际需求的时候,往往需要对现有工具进行扩展,或者编写符合我们要求的工具、自动化脚本,这个时候就需要具备一定的编程能力。在分秒必争的CTF竞赛中,想要高效地使用自制的脚本工具来实现各种目的,更是需要拥有编程能力.
如果你零基础入门,笔者建议选择脚本语言Python/PHP/Go/Java中的一种,对常用库进行编程学习;搭建开发环境和选择IDE,PHP环境推荐Wamp和XAMPP, IDE强烈推荐Sublime;·Python编程学习,学习内容包含:语法、正则、文件、 网络、多线程等常用库,推荐《Python核心编程》,不要看完;·用Python编写漏洞的exp,然后写一个简单的网络爬虫;·PHP基本语法学习并书写一个简单的博客系统;熟悉MVC架构,并试着学习一个PHP框架或者Python框架 (可选);·了解Bootstrap的布局或者CSS。
8、超级黑客
这部分内容对零基础的同学来说还比较遥远,就不展开细说了,附上学习路线。
网络安全工程师企业级学习路线
如图片过大被平台压缩导致看不清的话,评论区点赞和评论区留言获取吧。我都会回复的
视频配套资料&国内外网安书籍、文档&工具
当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
一些笔者自己买的、其他平台白嫖不到的视频教程。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img](https://img-blog.csdnimg.cn/img_convert/3fd39c2ba8ec22649979f245f4221608.webp?x-oss-process=image/format,png)
网络安全工程师企业级学习路线
如图片过大被平台压缩导致看不清的话,评论区点赞和评论区留言获取吧。我都会回复的
视频配套资料&国内外网安书籍、文档&工具
当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
一些笔者自己买的、其他平台白嫖不到的视频教程。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!