百度网盘golang实习面经

goroutine内存泄漏的情况?如何避免?

goroutine内存泄漏基本上是因为异常导致阻塞, 可以导致阻塞的情况

1 死锁, goroutine 等待的锁发生了死锁情况

2 chan没有正常被关闭,导致读取读chan的goroutine阻塞

如何避免

1 避免死锁

2 正常关闭

3 使用context管理goroutine, 超时结束goroutine

在Go语言中,Goroutine内存泄漏通常是由于Goroutine未能正确退出,导致其引用的对象无法被垃圾回收(GC)。以下是常见的内存泄漏场景及避免方法:


常见Goroutine内存泄漏场景

  1. 无限循环未设退出条件

    go 复制代码
    go func() {
        for { // 无退出条件
            // 持续执行任务...
        }
    }()
  2. 阻塞于未处理的Channel操作

    go 复制代码
    ch := make(chan int)
    go func() {
        <-ch // 永久阻塞,无数据发送
    }()
  3. 生产者提前退出,消费者未关闭

    go 复制代码
    func consumer(ch <-chan int) {
        for v := range ch { // 若生产者未关闭ch,消费者永久阻塞
            // 处理v
        }
    }
  4. 未释放资源(如time.Ticker)

    go 复制代码
    go func() {
        ticker := time.NewTicker(time.Second)
        for {
            <-ticker.C // 未调用ticker.Stop()
        }
    }()
  5. WaitGroup使用不当

    go 复制代码
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        // 忘记调用wg.Done()
    }()
    wg.Wait() // 永久阻塞

避免内存泄漏的方法

1. 使用context.Contextdone通道通知退出
  • 通过context的取消机制或自定义done通道,明确控制Goroutine生命周期。
go 复制代码
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func(ctx context.Context) {
    for {
        select {
        case <-ctx.Done(): // 收到退出信号
            return
        default:
            // 执行任务
        }
    }
}(ctx)
2. 避免永久阻塞:超时与select结合
  • 为Channel操作添加超时,防止永久阻塞。
go 复制代码
select {
case <-ch:
    // 正常处理
case <-time.After(1 * time.Second):
    // 超时处理
}
3. 正确关闭Channel
  • 确保生产者完成后关闭Channel,或在退出时通过done通道通知消费者。
go 复制代码
done := make(chan struct{})
ch := make(chan int)

go func() {
    defer close(ch) // 确保关闭Channel
    // 生产数据
}()

go func() {
    for {
        select {
        case v, ok := <-ch:
            if !ok {
                return
            }
            // 处理v
        case <-done: // 外部终止信号
            return
        }
    }
}()
4. 释放资源(如Ticker、锁、文件句柄)
  • 使用defer确保资源释放。
go 复制代码
go func() {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop() // 确保停止Ticker

    for {
        select {
        case <-ticker.C:
            // 执行任务
        case <-done:
            return
        }
    }
}()
5. 正确使用sync.WaitGroup
  • 使用defer wg.Done()避免遗漏。
go 复制代码
var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done() // 确保调用Done()
    // 执行任务
}()
wg.Wait()
6. 监控Goroutine数量
  • 使用pprofruntime.NumGoroutine()诊断泄漏。
go 复制代码
import (
    _ "net/http/pprof"
    "net/http"
)

func main() {
    go http.ListenAndServe(":6060", nil) // 暴露pprof接口
    // ...
}

访问http://localhost:6060/debug/pprof/goroutine?debug=2查看Goroutine堆栈。


总结

  • 设计原则:确保每个Goroutine都有明确的退出路径。
  • 资源管理 :通过defercontextdone通道管理生命周期。
  • 工具辅助 :利用pprof等工具监控和诊断泄漏。

遵循以上实践,可有效避免Goroutine内存泄漏问题。

讲一下协程和线程的区别?从多个角度说明,讲一下golang协程是如何调度的,和java线程的区别

主要的区别在于协程是用户级, 不需要进入到内核态处理. 所以协程更加轻量级, 不占用内核资源。2k

协程(Goroutine)和线程(Thread)是并发编程中的核心概念,它们在设计目标、资源管理、调度方式等方面有显著差异。以下是两者的详细对比,并重点分析 Go 协程的调度机制及其与 Java 线程的区别。


一、协程与线程的核心区别

角度 协程(Goroutine) 线程(Thread)
调度主体 由用户态调度(Go 运行时调度器) 由操作系统内核调度
内存占用 初始栈约 2KB,可动态扩展(最大默认 1GB) 固定栈(如 Linux 默认 8MB,Java 线程约 1MB)
切换成本 极低(无需内核切换,仅用户态操作) 高(需陷入内核态,上下文切换开销大)
并发数量 轻松支持百万级并发(资源占用小) 通常最多数千(受内核资源限制)
同步机制 基于 Channel 通信(CSP 模型),避免共享内存 依赖锁、信号量等(共享内存,需显式同步)
错误处理 通过 panic/recover 或返回值传递错误 通过异常捕获(如 try-catch
创建与销毁 极快(由 Go 运行时管理,无系统调用) 较慢(需系统调用,内核分配资源)

二、Go 协程的调度机制(GMP 模型)

Go 的协程调度器采用 GMP 模型,由以下三部分组成:

  1. G(Goroutine):协程对象,存储执行栈和状态。
  2. M(Machine):操作系统线程(实际执行单元),由内核调度。
  3. P(Processor):逻辑处理器,管理本地协程队列(每个 P 绑定一个 M)。
调度流程
  1. 协程创建

    当启动一个 Goroutine 时,它会被放入当前 P 的本地队列(或全局队列,若本地队列满)。

  2. 线程绑定(M 与 P 绑定)

    每个 P 会绑定一个 M(操作系统线程),M 从 P 的本地队列中获取 G 并执行。

  3. 协作式与抢占式调度

    • 协作式 :协程主动让出 CPU(如 runtime.Gosched() 或系统调用)。
    • 抢占式:Go 1.14+ 引入基于信号的抢占,防止协程长时间占用 CPU。
  4. Work Stealing

    若某个 P 的本地队列为空,会尝试从其他 P 的队列或全局队列"窃取" G,提高 CPU 利用率。

  5. 系统调用优化

    • 当 G 执行系统调用时,M 会解绑 P,P 转而绑定其他空闲 M,避免阻塞其他 G。
    • 系统调用完成后,M 尝试获取 P 继续执行,若无可用 P,则 G 进入全局队列。

三、Go 协程与 Java 线程的对比

1. 调度方式
  • Go 协程
    • 由 Go 运行时调度,用户态协作式+抢占式混合调度。
    • 无需内核介入,切换成本极低(如保存/恢复少量寄存器)。
  • Java 线程
    • 依赖操作系统内核调度(完全抢占式)。
    • 线程切换需陷入内核态,上下文切换开销大(如保存线程状态、切换页表等)。
2. 资源占用
  • Go 协程
    • 初始栈 2KB,按需动态扩展(避免内存浪费)。
    • 协程复用线程(M),1 个线程可运行数千个协程。
  • Java 线程
    • 固定栈大小(默认约 1MB),大量线程易导致内存耗尽。
    • 线程与内核线程 1:1 绑定,创建过多会触发 OOM。
3. 并发能力
  • Go 协程
    • 轻松支持百万级并发(如 Web 服务器处理海量连接)。
    • 典型场景:IO 密集型任务(网络、磁盘操作)。
  • Java 线程
    • 线程数量受限于内核(通常数千级别)。
    • 需结合线程池避免资源耗尽,但高并发时仍有瓶颈。
4. 同步与通信
  • Go 协程
    • 通过 Channel 通信,遵循 CSP 模型("不要通过共享内存通信,而通过通信共享内存")。
    • 天然避免竞态条件,减少锁的使用。
  • Java 线程
    • 依赖 synchronizedLockvolatile 等同步机制。
    • 共享内存模型易引发死锁、数据竞争等问题。
5. 错误处理
  • Go 协程
    • 错误通过返回值或 panic/recover 传递。
    • 若协程发生未捕获的 panic,整个程序会终止。
  • Java 线程
    • 异常需在线程内捕获,否则导致线程终止但进程不退出。
    • 可通过 Future 或全局异常处理器(UncaughtExceptionHandler)处理。

四、总结

特性 Go 协程 Java 线程
调度开销 极低(用户态调度) 高(内核态调度)
适用场景 高并发、IO 密集型任务 CPU 密集型任务、少量并发
资源占用 极小(动态栈,复用线程) 大(固定栈,线程与内核线程 1:1 绑定)
并发模型 CSP 模型(Channel 通信) 共享内存模型(锁同步)
调试复杂度 较低(天然避免部分竞态条件) 较高(需处理死锁、数据竞争)

五、为什么 Go 协程更适合高并发?

  1. 轻量级:协程创建和切换成本极低,允许海量并发。
  2. 高效调度:GMP 模型减少线程阻塞,最大化 CPU 利用率。
  3. 简化同步:Channel 取代锁,降低并发编程复杂度。
  4. 资源友好:动态栈和用户态调度避免内存和内核资源浪费。

七、结论

  • 协程是用户态的轻量级抽象,适合高并发、IO 密集型场景。
  • 线程是操作系统资源,适合 CPU 密集型任务,但需谨慎管理。
  • Go 的 GMP 调度器通过解耦协程与线程,结合协作式与抢占式调度,实现高效并发。
  • Java 线程受限于内核调度和资源开销,需依赖线程池等技术优化,但并发能力仍弱于协程。

slice和array的区别,讲一下底层的结构

array本质是一个固定数组, 内存层面就是一块固定的内存区域,不会改变, 传递的时候是拷贝一份完整数据.

slice本质上是一个动态数组的封装,底层指向不是一个固定内存,可以重新指向新的内存,包含一个指向 Array 的指针、长度和容量。

channel的用途和使用上要注意的点,底层的结构是怎样的

channel是golang中协程之间的数据交互的重要工具,相当于与进程内的一个消息队列.

注意点: 最重要的是chan的close 处理, 不然很容易出现异常, 1写数据goroutine中调用close, 2不要多次调用close, 3使用信号通知chan close了

底层结构: 环形队列(缓存数据, 无缓存的时候用不上), 读goroutine 队列(链表), 写goroutine 队列(链表), 锁

在 Go 语言中,Channel(通道) 是 Goroutine 之间通信和同步的核心机制,基于 CSP 模型(Communicating Sequential Processes)。以下是 Channel 的用途、使用注意事项及其底层结构的详细分析。


一、Channel 的用途

  1. Goroutine 间通信

    • 传递数据:通过 ch <- data(发送)和 data := <-ch(接收)实现数据交换。
    • 替代共享内存:遵循 Go 的哲学------"不要通过共享内存通信,而要通过通信共享内存"。
  2. 同步控制

    • 阻塞等待:无缓冲 Channel 的发送和接收会阻塞,直到对方准备好(天然的同步机制)。
    • 协调多个 Goroutine:例如通过 close(ch) 通知接收方数据结束。
  3. 工作池和任务分发

    • 结合缓冲 Channel,可构建生产者-消费者模型,控制并发数量。
  4. 超时控制

    • 通过 select 结合 time.After 实现超时机制:

      go 复制代码
      select {
      case <-ch:
          // 正常处理
      case <-time.After(1 * time.Second):
          // 超时处理
      }

二、使用 Channel 的注意事项

1. 初始化与零值
  • Channel 的零值为 nil,向 nil Channel 发送或接收会永久阻塞:

    go 复制代码
    var ch chan int // ch 是 nil
    ch <- 1         // 永久阻塞(无 panic)
    <-ch            // 永久阻塞(无 panic)
  • 正确做法 :使用 make 初始化 Channel:

    go 复制代码
    ch := make(chan int)     // 无缓冲 Channel
    bufferedCh := make(chan int, 10) // 缓冲容量为 10
2. 避免死锁
  • 无缓冲 Channel 的同步性 :发送和接收必须成对出现,否则死锁。

    go 复制代码
    func main() {
        ch := make(chan int)
        ch <- 1          // 发送后阻塞,无接收者导致死锁
        fmt.Println(<-ch) // 永远不会执行
    }
  • 解决方式 :确保发送和接收在不同的 Goroutine 中:

    go 复制代码
    go func() { ch <- 1 }()
    fmt.Println(<-ch)
3. 关闭 Channel 的规则
  • 关闭后不可发送 :向已关闭的 Channel 发送数据会引发 panic

  • 接收已关闭的 Channel :可继续接收剩余数据,返回零值时需通过 ok 判断是否关闭:

    go 复制代码
    v, ok := <-ch
    if !ok {
        // Channel 已关闭
    }
  • 关闭 Channel 的原则

    • 只由发送方关闭,避免多个 Goroutine 同时关闭。
    • 无需关闭 Channel(除非必须通知接收方"数据结束")。
4. 避免泄漏
  • 未关闭的 Channel:若接收方持续等待已不再发送数据的 Channel,会导致 Goroutine 泄漏。

  • 解决方式 :使用 contextdone 通道通知退出:

    go 复制代码
    done := make(chan struct{})
    go func() {
        select {
        case <-done:
            return
        case v := <-ch:
            // 处理数据
        }
    }()
    // 退出时关闭 done
    close(done)
5. 性能优化
  • 缓冲 Channel:减少阻塞频率,但需权衡内存占用。
  • 避免过度缓冲:缓冲大小应根据实际场景调整,避免资源浪费。

三、Channel 的底层结构

Go 的 Channel 实现基于 runtime.hchan 结构体(源码见 runtime/chan.go),核心字段如下:

1. hchan 结构体
go 复制代码
type hchan struct {
    qcount   uint          // 当前队列中元素数量
    dataqsiz uint          // 缓冲区的固定大小(容量)
    buf      unsafe.Pointer // 指向环形缓冲区的指针
    elemsize uint16        // 元素大小
    closed   uint32        // 是否已关闭(0-未关闭,1-已关闭)
    sendx    uint          // 发送索引(指向缓冲区下一个写入位置)
    recvx    uint          // 接收索引(指向缓冲区下一个读取位置)
    recvq    waitq         // 等待接收的 Goroutine 队列(sudog 链表)
    sendq    waitq         // 等待发送的 Goroutine 队列(sudog 链表)
    lock     mutex         // 互斥锁(保护 Channel 的并发操作)
}
2. 环形缓冲区(Buffered Channel)
  • 缓冲机制 :当 dataqsiz > 0 时,Channel 使用环形队列存储数据。
  • 写入流程
    • 若缓冲区未满,数据写入 buf[sendx]sendx = (sendx + 1) % dataqsiz
    • 若缓冲区已满,发送方 Goroutine 加入 sendq 队列并阻塞。
  • 读取流程
    • 若缓冲区非空,读取 buf[recvx]recvx = (recvx + 1) % dataqsiz
    • 若缓冲区为空,接收方 Goroutine 加入 recvq 队列并阻塞。
3. 直接发送与接收(Unbuffered Channel)
  • 无缓冲 Channeldataqsiz = 0,发送和接收必须同时就绪。
  • 同步过程
    • 若接收方已阻塞(在 recvq 中),发送方直接将数据拷贝到接收方的栈。
    • 若发送方已阻塞(在 sendq 中),接收方直接从发送方拷贝数据。
4. 等待队列(waitq
  • 阻塞的 Goroutine :当发送或接收无法立即完成时,Goroutine 被封装为 sudog 结构体,加入 sendqrecvq 队列。
  • 唤醒机制:当条件满足时(如缓冲区有空间或数据),调度器唤醒队列中的 Goroutine。

四、总结

特性 说明
核心用途 Goroutine 间通信与同步,替代共享内存
底层结构 基于环形缓冲区和等待队列(hchan),通过锁保证并发安全
注意事项 避免死锁、正确关闭、处理零值、防止泄漏
性能优化 合理使用缓冲、减少锁竞争、避免过度阻塞

Channel 是 Go 并发编程的核心工具,深入理解其机制和陷阱,能够编写出高效且健壮的并发代码。

orm框架的优缺点

orm封装了对数据库的操作,并且自动转换内存数据结构和数据库字段, 优点是方便,开发效率高, 缺点是有些场景性能低, 复杂对像转换处理起来不方便.

操作系统内核态和用户态的区别,何时进入内核态or用户态

进入内核态: 中断(系统调用, 时间片到期等)

进入用户态: 内核态处理完成,调度用户线程处理程序

tcp和udp的区别,他们的报头结构,tcp的三次握手和四次握手的中间状态有哪些







https中的TLS/SSL层是用来干什么的,讲一下根证书和证书链和https握手的流程


TLS/SSL 层的作用

TLS(Transport Layer Security) 及其前身 SSL(Secure Sockets Layer) 是位于传输层(如 TCP)和应用层(如 HTTP)之间的安全协议,主要用于:

  1. 加密通信:防止数据在传输过程中被窃听。
  2. 身份认证:验证服务器(或客户端)的身份,防止中间人攻击。
  3. 数据完整性:确保数据未被篡改(通过哈希算法和消息认证码)。

HTTPS = HTTP + TLS/SSL,所有数据在传输前会被 TLS 层加密。


根证书与证书链

1. 根证书(Root Certificate)
  • 颁发者:由受信任的根证书颁发机构(Root CA,如 DigiCert、Let's Encrypt)签发。
  • 存储位置:预装在操作系统或浏览器中(如 Windows 的受信任根证书存储)。
  • 作用:作为信任链的起点,用于验证其他证书的合法性。
2. 证书链(Certificate Chain)
  • 结构根证书 → 中间证书(Intermediate CA) → 服务器证书
  • 示例
    • 根证书:DigiCert Global Root CA
    • 中间证书:DigiCert TLS RSA SHA256 2020 CA1
    • 服务器证书:www.example.com
  • 作用
    • 分层信任:根证书不直接签发服务器证书,通过中间证书隔离风险(即使中间证书私钥泄露,只需吊销中间证书,无需替换根证书)。
    • 链式验证:客户端从服务器证书逐级向上验证,直到找到信任的根证书。
3. 证书验证过程
  1. 客户端收到服务器的证书(如 www.example.com)。
  2. 检查证书是否过期、域名是否匹配。
  3. 通过证书链向上追溯,验证每一级证书的签名是否合法,直到找到受信任的根证书。
  4. 若验证失败(如根证书不在信任库中),浏览器会提示"证书不受信任"。

HTTPS 握手流程(以 TLS 1.2 为例)

以下是客户端(如浏览器)与服务器建立 HTTPS 连接的详细步骤:

1. Client Hello
  • 客户端发送:
    • 支持的 TLS 版本(如 TLS 1.2)。
    • 客户端随机数(Client Random,用于生成会话密钥)。
    • 支持的密码套件 (如 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)。
    • SNI(Server Name Indication):指定访问的域名(用于多域名服务器)。
2. Server Hello
  • 服务器回应:
    • 选择的 TLS 版本密码套件
    • 服务器随机数(Server Random,用于生成会话密钥)。
    • 服务器证书链(包含服务器证书和中间证书)。
3. 证书验证
  • 客户端验证服务器证书链的合法性(如前文所述)。
4. 密钥交换(Key Exchange)
  • RSA 密钥交换 (传统方式):
    • 客户端生成预主密钥(Pre-Master Secret),用服务器证书的公钥加密后发送。
    • 服务器用私钥解密,得到预主密钥。
  • ECDHE 密钥交换 (现代方式,支持前向保密):
    • 服务器生成临时椭圆曲线参数和公钥(Server Params),签名后发送。
    • 客户端生成临时公钥(Client Params),发送给服务器。
    • 双方通过椭圆曲线算法生成预主密钥。
5. 生成会话密钥
  • 客户端和服务器使用以下三个随机数生成主密钥(Master Secret)
    • Client Random
    • Server Random
    • Pre-Master Secret
  • 主密钥进一步派生出会话密钥(对称加密密钥,如 AES 密钥),用于后续通信加密。
6. Finished
  • 双方发送加密的 Finished 消息,验证握手过程未被篡改。
  • 握手完成,后续应用数据通过对称加密传输。

TLS 1.3 的优化

TLS 1.3 简化握手流程,提升安全性和速度:

  1. 合并步骤:将密钥交换与证书验证合并为单次往返(1-RTT)。
  2. 移除不安全算法:禁用 RSA 密钥交换(仅支持前向保密的 ECDHE)。
  3. 0-RTT 模式:对重复连接可跳过握手(需谨慎使用,存在重放攻击风险)。

总结

关键点 说明
TLS/SSL 作用 加密数据、验证身份、保障完整性
根证书 信任链的起点,预装在系统中
证书链 分层签发,隔离风险,支持灵活吊销
握手流程 协商参数 → 交换密钥 → 生成会话密钥 → 加密通信
前向保密 ECDHE 确保即使服务器私钥泄露,历史会话仍安全(TLS 1.3 强制要求)

示例场景

当访问 https://www.example.com 时:

  1. 浏览器通过 TLS 握手验证服务器的证书链,确认其属于 example.com
  2. 双方协商出会话密钥,后续所有 HTTP 数据(如登录密码、支付信息)均通过 AES 加密传输,确保安全。

常见的攻击手法有哪些,讲一下中间人攻击和跨域攻击的原理,跨域攻击主要是利用了浏览器的什么机制


一、常见攻击手法分类

以下是网络安全中常见的攻击类型:

攻击类型 描述
中间人攻击(MITM) 攻击者拦截并篡改通信双方的数据流。
跨站脚本(XSS) 向网页注入恶意脚本,窃取用户数据或会话 Cookie。
SQL 注入 通过输入恶意 SQL 语句,操纵数据库查询。
跨站请求伪造(CSRF) 诱使用户在已认证的站点上执行非预期的操作(如转账)。
拒绝服务(DoS/DDoS) 通过大量请求耗尽目标资源,使其无法正常服务。
钓鱼攻击 伪造可信页面(如银行网站),诱导用户提交敏感信息。
目录遍历/文件包含 利用路径漏洞访问或执行服务器上的敏感文件。
社会工程学 通过心理欺骗获取敏感信息(如假冒客服骗取密码)。

二、中间人攻击(MITM)原理

1. 攻击场景
  • 未加密的通信:如 HTTP 明文传输、公共 Wi-Fi 环境。
  • 证书欺骗:伪造 SSL/TLS 证书(如自签名证书),诱导用户信任。
2. 攻击步骤
  1. 窃听(Eavesdrop)

    攻击者通过 ARP 欺骗、DNS 劫持或 Wi-Fi 嗅探,成为通信链路的中间节点。

    • ARP 欺骗:伪造 IP 和 MAC 地址映射,劫持局域网流量。
    • DNS 劫持:篡改 DNS 响应,将域名解析到攻击者控制的 IP。
  2. 篡改或伪造数据

    • 修改传输内容(如插入广告、重定向到钓鱼网站)。
    • 窃取敏感信息(如登录凭证、Cookie)。
  3. 伪装身份

    • 在 HTTPS 场景下,攻击者可能伪造证书(需用户手动信任),解密 HTTPS 流量。
3. 防御措施
  • 使用 HTTPS:加密通信内容,防止明文数据泄露。
  • HSTS(HTTP Strict Transport Security):强制浏览器使用 HTTPS,防止降级攻击。
  • 证书固定(Certificate Pinning):客户端固定合法证书,拒绝非预期证书。
  • 网络层防护:使用 VPN、避免使用公共 Wi-Fi 进行敏感操作。

三、跨域攻击(Cross-Origin Attacks)原理

跨域攻击主要利用浏览器**同源策略(Same-Origin Policy)**的漏洞,绕过安全限制,窃取数据或执行恶意操作。

1. 同源策略(SOP)
  • 定义 :浏览器限制脚本只能访问与当前页面同源(协议、域名、端口相同)的资源。
  • 目的:防止恶意网站读取其他站点的敏感数据(如 Cookie、DOM 内容)。
2. 跨域攻击类型
(1) 跨站脚本(XSS)
  • 原理 :攻击者注入恶意脚本到合法页面,脚本在用户浏览器执行。

    html 复制代码
    <!-- 示例:通过未过滤的用户输入注入脚本 -->
    <input value="<script>stealCookie()</script>">
  • 利用点

    • 窃取用户的 Cookie 或 Session ID。
    • 伪造用户操作(如自动转账)。
(2) 跨站请求伪造(CSRF)
  • 原理 :诱导用户访问恶意页面,该页面自动向目标站点发送已认证的请求。

    html 复制代码
    <!-- 恶意页面中隐藏的转账请求 -->
    <img src="https://bank.com/transfer?to=attacker&amount=1000000">
  • 利用点

    • 用户已登录目标站点(如银行),浏览器自动携带 Cookie。
    • 请求被执行(如转账、修改密码)。
(3) CORS 配置不当
  • 原理 :服务器错误设置 Access-Control-Allow-Origin: *,允许任意域访问资源。

    http 复制代码
    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: *
  • 利用点

    • 攻击者通过恶意网站发起跨域 AJAX 请求,窃取数据。
(4) JSONP 劫持
  • 原理 :利用 <script> 标签跨域加载 JSONP 接口,通过回调函数窃取数据。

    html 复制代码
    <script src="https://api.com/user?callback=stealData"></script>
    <script>
    function stealData(data) {
        // 发送数据到攻击者服务器
    }
    </script>
3. 防御措施
攻击类型 防御方法
XSS 输入输出过滤(如转义 <, >)、启用 CSP(Content Security Policy)。
CSRF 使用 CSRF Token、检查 Referer 头、设置 SameSite Cookie 属性。
CORS 严格限制 Access-Control-Allow-Origin(如白名单)、避免使用通配符 *
JSONP 弃用 JSONP,改用 CORS;或校验回调函数名、添加随机 Token。

四、总结

攻击类型 核心原理 浏览器机制利用
中间人攻击 拦截并篡改通信链路 无加密通信或证书信任漏洞
跨域攻击 绕过同源策略获取跨域数据或权限 SOP 限制不严、CORS/JSONP 配置错误

关键点

  • 中间人攻击依赖网络层的漏洞,防御需加密通信(HTTPS)和身份验证。
  • 跨域攻击利用浏览器同源策略的宽松配置,防御需严格限制跨域资源访问。

示例场景

  • MITM:公共 Wi-Fi 中,攻击者截获用户登录 HTTP 站点的密码。
  • 跨域攻击:恶意网站利用银行站点的 CORS 配置错误,窃取用户账户数据。

通过理解攻击原理和浏览器机制,开发者可更有效地设计安全防护策略。

相关推荐
计算机毕设指导68 分钟前
基于Springboot旅游网站系统【附源码】
java·开发语言·spring boot·后端·mysql·spring·旅游
code_shenbing10 分钟前
python常用科学计算库及使用示例
开发语言·python
Wabi_sabi_x17 分钟前
C++设计模式:面向对象的八大设计原则之二
开发语言·c++·设计模式
●^●22 分钟前
Python 部分内置函数及其用法详解
开发语言·python
caihuayuan536 分钟前
关于vue+iview中tabs嵌套及实际应用
java·大数据·spring boot·后端·课程设计
꧁坚持很酷꧂1 小时前
C++的基础知识(引用、类、封装、继承、多态、函数重载)
开发语言·c++
sunly_1 小时前
Flutter:组件10、倒计时
开发语言·javascript·flutter
a181001_1 小时前
python下载
开发语言·后端·python·青少年编程
躺不平的理查德2 小时前
C++-Lambda表达式
开发语言·c++
徐白11772 小时前
Node.js 事件循环和线程池任务完整指南
开发语言·javascript·node.js