go 訪問 sftp 服務 github.com/pkg/sftp 的使用踩坑,連接未關閉(含 sftp 服務測試環境搭建)

前言

最近在使用 sftp 服務時,被告知發起了海量的連接,直接把服務器搞崩,ip 被封了。

這是啥情況?

golang 寫的代碼,我就正常的訪問 sftp 服務,連接使用過后也都關閉了,咋會出現連接一直連著沒關的情況呢?

原因分析

先上代碼,主要使用了開源庫 github.com/pkg/sftp

package mainimport ("fmt""github.com/pkg/sftp""golang.org/x/crypto/ssh""time"
)func main() {ticker := time.NewTicker(time.Second)for range ticker.C {client, err := createDefaultSftpClient()if err != nil {panic(err)}// 演示用wd, err := client.Getwd()if err != nil {panic(err)}fmt.Println(wd)client.Close()}
}func createSFTPClient(user, pwd, host, port string, pemBytes []byte) (*ssh.Client, *sftp.Client, error) {var authMethods []ssh.AuthMethodif pwd != "" {authMethods = append(authMethods, ssh.Password(pwd))}if len(pemBytes) > 0 {signer, err := ssh.ParsePrivateKey(pemBytes)if err != nil {return nil, nil, err}authMethods = append(authMethods, ssh.PublicKeys(signer))}config := &ssh.ClientConfig{User:            user,Auth:            authMethods,HostKeyCallback: ssh.InsecureIgnoreHostKey(),}conn, err := ssh.Dial("tcp", host+":"+port, config)if err != nil {return nil, nil, err}client, err := sftp.NewClient(conn)if err != nil {return nil, nil, err}return conn, client, nil
}var defaultSftpPemBytes = []byte(``)func createDefaultSftpClient() (*sftp.Client, error) {_, client, err := createSFTPClient("foo", "test", "127.0.0.1", "2222", defaultSftpPemBytes)return client, err
}

本篇的測試環境是 windows,當上述程序跑起來后,查看本機 2222 端口的使用情況(netstat -ano | findstr 2222),這一看,果然是好多連接啊。為什么我的 client 已經 Close 了還是會有這么多連接未關閉呢?
在這里插入圖片描述

想必細心的朋友們已經發現了問題,我故意給 createSFTPClient 返回了兩個連接,一個是 ssh.Client 還有一個是 sftp.Client,但是 createDefaultSftpClient 只返回了 sftp.Client

查看 github.com/pkg/sftp 源碼發現:

  • sftp.NewClient 會調用 SSH 連接的 NewSession 方法創建一個新會話,但不會持有 SSH 連接的所有權。
  • sftpClient.Close() 僅關閉 SFTP 會話的 Channel,而 SSH 連接的生命周期由調用方(即 sshClient)控制。

原因就是 ssh.Client 創建了沒有關閉,必須要顯示調用 sshClient.Close()!!!

搭建測試 sftp 服務

使用 docker 鏡像 atmoz/sftp 搭建 sftp 服務。

docker-compose.yaml

version: '3.8'services:sftp:image: atmoz/sftpvolumes:- ./atmoz_data:/home/foo/uploads# - ./atmoz_ssh_keys:/home/foo/.ssh/keys # 支持密鑰登錄command: foo:test:1001  # 用戶名:空密碼:UID:GIDports:- "2222:22"

這里我踩了兩個坑

  1. linux 環境下,服務啟動后,嘗試創建目錄時報錯 mkdir /test: permission denied。 是因為宿主機目錄的權限或所有權未與容器內用戶的 UID/GID 匹配。例如,容器內用戶 UID 為 1001,但宿主機目錄所有者是 root,導致權限沖突。可以調整宿主機目錄的權限 chown -R 1001:1001 /宿主機目錄/atmoz_data
  2. 若需支持密鑰登錄,需將上述的 docker-compose.yamlvolumes 的注釋去掉。注意:宿主機的 atmoz_ssh_keys 目錄下一定要把自己生成的 ssh key 公鑰放進去,不然會報錯
[/usr/local/bin/create-sftp-user] Parsing user data: "foo:test:1001"
cat: '/home/foo/.ssh/keys/*': No such file or directory

因為使用 atmoz/sftp 鏡像時,若在 command 中定義了用戶 foo:test:1001,鏡像會自動執行以下操作:

  • 創建用戶 foo(UID 1001)
  • 嘗試從 /home/foo/.ssh/keys/ 目錄加載公鑰文件(*.pubauthorized_keys)。
  • 將公鑰寫入 /home/foo/.ssh/authorized_keys

由于將容器內的 /home/foo/.ssh/keys/ 目錄映射出去了,但是有沒放密鑰文件進去,找不到文件,所以就直接報錯了。

這里還有一點,atmoz/sftp 搭建的服務應該是不支持 Ed25519 類型的密鑰的,可以使用 rsa

ssh-keygen -t rsa -b 4096

總結

本文主要分析了使用 go 三方庫 github.com/pkg/sftp 訪問 sftp 服務出現大量的連接未關閉的異常情況,需要顯式調用 sshClient.Close()

接著介紹了如何使用 docker 搭建 sftp 服務,一個權限,一個密鑰,需要注意。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/906735.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906735.shtml
英文地址,請注明出處:http://en.pswp.cn/news/906735.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android 直接通過 app_process 啟動的應用如何使用 Context

文章目錄 一、問題背景二、代碼實現三、代碼詳解 一、問題背景 在 Android 中,可以使用 Android Studio 編寫 Java 應用程序,通過編譯打包成 apk 文件,然后將文件推送至 /data/local/tmp 等可執行的目錄或安裝打包出來的應用,隨后…

【數據結構與算法】LeetCode 每日三題

如果你已經對數據結構與算法略知一二,現在正在復習數據結構與算法的一些重點知識 ------------------------------------------------------------------------------------------------------------------------- 點贊收藏🌈,每天更新總結文…

深度“求索”:DeepSeek+Dify構建個人知識庫

目錄 前言 環境部署 安裝Docker 安裝Dify 配置Dify 部署知識庫 創建應用 前言 在當今數字化信息爆炸的時代,數據隱私和個性化知識管理成為企業和個人關注的焦點。Dify,作為一款備受矚目的開源 AI 應用開發平臺,為用戶提供了完整的私有…

【Redis8】最新安裝版與手動運行版

目錄 一、直接運行 1. 下載 Redis百度網盤 2. 解壓后直接運行 redis-server.exe?編輯 二、安裝版運行 雙擊 install_redis_service.bat 輸入安裝路徑(請提前創建好安裝路徑)后直接回車?編輯 下一步直接回車即可,因為是使用配置模板…

@Column 注解屬性詳解

提示:文章旨在說明 Column 注解屬性如何在日常開發中使用,數據庫類型為 MySql,其他類型數據庫可能存在偏差,需要注意。 文章目錄 一、name 方法二、unique 方法三、nullable 方法四、insertable 方法五、updatable 方法六、column…

使用Gemini, LangChain, Gradio打造一個書籍推薦系統 (第二部分)

建立向量嵌入數據庫 from langchain_community.document_loaders import TextLoader from langchain_text_splitters import CharacterTextSplitter from langchain.docstore.document import Document from langchain_chroma.vectorstores import Chromaimport vertexai from…

【Go-4】函數

函數 函數是編程中的基本構建塊,用于封裝可重用的代碼邏輯。Go語言中的函數功能強大,支持多種特性,如多返回值、可變參數、匿名函數、閉包以及將函數作為值和類型傳遞。理解和掌握函數的使用對于編寫高效、可維護的Go程序至關重要。本章將詳…

【已解決】HBuilder X編輯器在外接顯示器或者4K顯示器怎么界面變的好小問題

觸發方式:主要涉及DPI縮放問題,可能在電腦息屏有概率觸發 修復方式: 1.先關掉軟件直接更改屏幕縮放,然后打開軟件,再關掉軟件恢復原來的縮放,再打開軟件就好了 2.(不推薦)右鍵HBuilder在屬性里…

spark調度系統核心組件SparkContext、DAGSchedul、TaskScheduler、Taskset介紹

目錄 1. SparkContext2.DAGScheduler3. TaskScheduler4. 協作關系5 TaskSet的定義6. 組件關系說明Spark調度系統的核心組件主要有SparkContext、DAGScheduler和TaskScheduler SparkContext介紹 1. SparkContext 1、資源申請: SparkContext是Spark應用程序與集群管理器(如St…

VSCode+EIDE通過KeilC51編譯,使VSCode+EIDE“支持”C和ASM混編

在使用Keil C51時,要讓Keil C51支持混編則需要在混編的.c文件上右鍵選擇Options for File *(ALTF7),打開選項界面后,在 Properties 頁 勾上 Generate Assembler SRC File 和 Assemble SRC File ,如下圖所示: 這樣設置后…

SQLynx:一款跨平臺的企業級數據庫管理工具

SQLynx 是一款支持跨平臺(Windows、Linux、macOS、Web)的企業級數據庫管理和 SQL 工具,可以提供高效、安全且適配國產化技術棧的數據庫管理解決方案。 數據源 SQLynx 支持連接各種關系型數據庫、非關系型數據庫以及大數據平臺,包…

實戰項目8(實訓)

目錄 項目01 【sw1】配置 【sw2】配置 任務結果截圖 項目02 【sw1】配置 【sw2】配置 任務結果截圖 項目03 【sw1】配置 任務結果截圖 項目04 【sw1】配置 【r1】配置 任務結果截圖 項目05 【r1】配置 【r2】配置 【r3】配置 任務結果截圖 項目06 【r1】…

TCP為什么是三次握手,而不是二次?

為什么需要三次握手? 想象一下,你要給遠方的朋友寄一份重要文件。你會怎么做? 普通人的做法: 直接扔進郵箱,祈禱別丟了 聰明人的做法: 先打電話確認地址,再發快遞,最后確認收到 T…

dubbo使用nacos作為注冊中心配置

<dubbo:registry protocol"nacos" address"${dubbo.registry.address.nacos}" /> <dubbo:metadata-report address"${dubbo.metadata-report.address}"/> 如果有多個地址&#xff0c;這塊如何配置呢&#xff1f; nacos://ip:端口?…

教師角色的轉變:從知識傳授者到學習引導者

教師角色的轉變&#xff1a;從知識傳授者到學習引導者 隨著人工智能&#xff08;AI&#xff09;和信息技術的迅速發展&#xff0c;教育正在經歷深刻的變革。其中&#xff0c;教師角色的轉變尤為關鍵。傳統上&#xff0c;教師主要承擔“知識傳授者”的職責&#xff0c;即向學生…

PostgreSQL 用戶權限與安全管理

1 系統默認角色 postgres# select rolname from pg_roles; rolname ----------------------------- postgres pg_database_owner pg_read_all_data pg_write_all_data pg_monitor pg_read_all_settings pg_read_all_stats pg_stat_scan_tables …

C++構造函數和析構函數

C++構造函數和析構函數 C++的構造函數和析構函數是類的特殊成員函數,用于對象的創建和銷毀,分別在對象的生命周期開始和結束時自動調用。它們的使用對資源管理和對象的初始化/清理至關重要。 1. 構造函數 定義 構造函數在對象創建時自動調用,用于初始化對象的數據成員。構造…

根據Cortex-M3(STM32F1)權威指南講解MCU內存架構與如何查看編譯器生成的地址具體位置

首先我們先查看官方對于Cortex-M3預定義的存儲器映射 1.存儲器映射 1.1 Cortex-M3架構的存儲器結構 內部私有外設總線&#xff1a;即AHB總線&#xff0c;包括NVIC中斷&#xff0c;ITM硬件調試&#xff0c;FPB, DWT。 外部私有外設總線&#xff1a;即APB總線&#xff0c;用于…

軟件設計師“測試用例”考點分析——求三連

一、測試用例設計核心要點解析 1. 白盒測試覆蓋標準 &#xff08;1&#xff09;路徑覆蓋&#xff1a;需覆蓋程序中所有可能的路徑。如2018年真題路徑覆蓋需要3組測試用例&#xff08;①②、①③、①③④&#xff09;&#xff0c;2020年流程圖則需4個用例覆蓋ace/abd/abe/acd四…

Linux 用戶無法遠程連接服務器

前言 昨天深夜一點多接到客戶電話&#xff0c;客戶說OS用戶下午下班前還能正常登錄。因為晚上一點半需要關閉所有服務進行遷移&#xff0c;但是用戶無法登錄了&#xff0c;導致后續流程無法執行。我讓他先通過root用戶緊急修改了密碼&#xff0c;先保證業務正常流轉。 問題 …