参考:

    • SFTP搭建(密码认证、密钥认证)、客户端连接、java代码连接_青牛-CSDN博客_sftp 密码

    https://blog.csdn.net/alan_gui/article/details/85220010

    • 教你如何配置linux用户实现禁止ssh登陆机器但可用sftp登录!_yinn-CSDN博客

    https://blog.csdn.net/qq_35440678/article/details/52788808

    密钥认证需要在用户(/home/xxx/.ssh)目录下面配置密钥
    chmod 555 文件夹 可以让所属sftp用户只有只读权限 没有上传删除的权限
    参考:
    linux 普通用户可以拥有删除root用户文件的权限吗?-森林的个人博客
    https://www.liuhaolin.com/linux/324.html
    Linux权限详解(chmod、600、644、666、700、711、755、777、4755、6755、7755)_wlin的博客-CSDN博客_chmod
    https://blog.csdn.net/u013197629/article/details/73608613
    一、SFTP 搭建

    在一些情况下(如需要为商户提供对账文件),你需要一台文件服务器存放这些文件,并允许用户登陆这台文件服务器传输(上传和下载)文件,但是不允许使用 SSH 方式(如 secureCRT)登录文件服务器,你只允许其访问指定根目录(/home/sftp)下文件,这样 SFTP 服务就能很好满足这种需求。sftp 传输数据(文件)使用的依旧是 SSH 协议,linux 开启了 sshd 就相当于开启了 SFTP。注:搭建 SFTP 文件服务器不需求安装什么额外的包,除了 SSH,ssh 需要 OpenSSH4.8p1 以后的版本。因为要使用 chroot 设置根目录(用户能看见和访问的根目录)。

    查看 SSH 版本

    ssh -V

    搭建步骤:

    使用 root 操作

    1、建 SFTP 组

    groupadd sftp

    创建完成后使用 cat /etc/group 可以看到

    2、创建用户 albert

    useradd -g sftp -s /sbin/nologin -M albert

    -g 加入到 sftp 组

    -s 禁止 ssh 登陆

    -M 不要自动建立用户的登陆目录(在 / home 下)

    3、为 albert 用户设置密码

    passwd albert

    alan123456

    重复输入两次同一密码

    4、创建 sftp 存放文件的目录并设置文件拥有者

    mkdir -p /dala/sftp/verifyfile

    chown -R albert:sftp /data/sftp/verifyfile

    chmod 755 /data/sftp/verifyfile

    5、编辑配置文件 / etc/ssh/sshd_config

    注:修改配置文件前先备份原有正常配置文件,方面还原

    cp /etc/ssh/sshd_confiig /etc/ssh/sshd_config.bak

    vi /etc/ssh/sshd_config

    注释掉 Subsystem sftp /usr/libexec/openssh/sftp-server

    在其下面添加

    Subsystem sftp internal-sftp

    在文件最后添加

    Match Group sftp # 指定活动目录

    ChrootDirectory /data/sftp # 指定根目录

    ForceCommand internal-sftp # 强制执行内部 SFTP, 并忽略任何~/.ssh/rc 中的命令

    AllowTcpForwarding no # 禁用端口转发

    X11Forwarding no # 禁用 X11 图形界面转发

    6、重启 sshd

    service sshd restart

    7、测试

    sftp albert@ip

    输入密码即可连接上

    8、权限控制

    按照上面的设置

    chown albert:sftp /data/sftp/verifyfile

    chmod 755 /data/sftp/verifyfile

    albert 是拥有 / data/sftp/verifyfile 文件的读写权限的

    sftp 组其他用户的权限是 5,即没有写入权限

    如新增用户 jack

    useradd -g sftp -s /sbin/nologin -M jack

    passwd jack

    jack123456

    重复输入两次同一密码

    那么 jack 的权限只有 5

    9、以上只是基本操作,但可基于此依据你自己需求(用户、文件目录、权限)自行设计专属 sftp 文件服务器,对于不断新增特定目录、特定权限用户的操作,可以配合 sheel 脚本使用或基于脚本再开发前端页面方面操作。

    10、rsa 认证方式设置和登录

    以上介绍的 SFTP 用户登录方式是 sshd_config 配置文件默认打开的密码验证方式。

    PasswordAuthentication yes

    再介绍一种实际中使用更多,更安全,更方面的用户登录验证方式,即密钥登录。

    密钥登录无需用户设置密码,通过 rsa 密钥对加解密验证,在客户端和服务器端建立安全的连接,简单地说,public key 放在服务器端,即下面配置的 authorized_keys,private key 放在客户端,客户端发起请求连接,服务器根据请求用户名识别对应客户端公钥,sshd 服务产生一个随机数,用 public key 进行加密后,发回到客户端,客户端用 private key 解密得到该随机数,客户端将解密后的随机数发回服务器端,服务端进行匹配,匹配成功认证通过,允许登录。这种方式避免了密码暴力破解尝试的危险,当然密钥认证因为有加解密和随机数传输验证的过程,连接耗时自然比密码方式长些。

    我们再新增可登录用户 qingniu , 采用密钥验证方式登录

    依旧用 root 操作

    useradd -g sftp -s /sbin/nologin qingniu

    不要再使用 passwd 为其设置密码

    注意这里不要 -M , 因为我们需要 useradd 为新增用户在 / home 目录下自动建立用户的登陆目录, 我们需要再 / home/qingniu 目录下设置密钥文件。

    cd /home/qingniu

    ll -a — 可看到所有隐藏目录

    mkdir .ssh — 存放密钥文件和认证文件

    ssh-keygen -t rsa

    输入 / home/qingniu/.ssh/id_rsa_qingniu

    按回车键,不对密钥加密

    再次按回车确认

    成功在 / home/qingniu/.ssh 目录下生成一对密钥 id_rsa_qingniu 、id_rsa_qingniu.pub

    SFTP搭建(密码认证、密钥认证) - 图1

    cd /home /qingniu/.ssh — 进入密钥对所在目录

    cat id_rsa_qingniu.pub >> authorized_keys — 往 authorized_keys 文件中写入公钥 key

    接下来就是新增目录、密钥的权限和用户组设置,很重要,因为我们是用 root 用户操作这些目录和文件的。至于为什么按下面设置,请自行思考,其实也很简单。

    chmod 600 /home/qingniu/.ssh/authorized_keys

    chmod 700 /home/qingniu/.ssh

    chown -R qingniu:sftp /home/qingniu/.ssh

    为 / etc/ssh/sshd_config 添加配置

    PermitRootLogin yes

    RSAAuthentication yes

    PubkeyAuthentication yes

    AuthorizedKeysFile .ss:h/authorized_keys

    添加完成后保存再重启 sshd 服务

    service sshd restart

    把私钥 id_rsa_qingniu 导出,重新打开 FileZilla 用密钥认证方式登录测试

    如果你只允许用户使用密钥认证登录,可以设置 / etc/ssh/sshd_config 文件

    PasswordAuthentication no

    如果不改,密钥认证和密钥认证两种登录方式都允许。

    二、客户端连接

    FileZilla 下载地址:https://filezilla-project.org/download.php

    按照安装引导安装即可

    使用上面 SFTP 用户登陆测试

    密码认证方式

    输入 主机 IP username password port(默认 22)

    密钥认证方式

    编辑 -> 设置 -> sftp -> 添加密钥文件 -> 确认

    输入 主机 IP username 不填密码 port(默认 22)

    三、java 代码连接

    使用 java 代码语言实现与 sftp 服务器的文件传输,我们可以使用 Jcraft 公司开发的 JSch 包,JSch 使用纯 java 语言实现了 ssh2 协议,感谢 ssh2 标准协议的制定,才使得我们能通过各种形态的客户端与服务器之间建立安全可靠的通信。因此实现了 SSH2 协议的 JSch 能做的也就不仅仅是文件传输,包括 ssh 协议实现的 X11 GUI 转发、端口转发、终端仿真等各种酷炫功能,所以学习 JSch 项目对于 java 程序员是有很必要的,那就从文件传输这个功能开始接触 JSch 这个项目吧。

    首先在项目中引入 JSch 包
    com.jcraft

    jsch

    0.1.53
    基于 JSch 包实现的 SFTP 服务器文件上传和下载功能代码如下:

    1. package com.qing.niu.communication.sftp;import com.jcraft.jsch.*;import org.slf4j.LoggerFactory;import org.springframework.util.Assert;import java.util.HashMap;import java.util.Properties;public static final Logger logger = LoggerFactory.getLogger(SftpTool.class);public SftpTool(String host, String username, int port){this.username = username;public Map<String,Object> loginIn(AuthTypeMode authTypeMode){ JSch.setLogger(new SettleJschLogPrint()); logger.info("获取SFTP服务器连接username:{},host:{},port:{}",username,host,port); session = jsch.getSession(username,host,port);if (AuthTypeEnum.RSA.getCode().equals(authTypeMode.getAuthType())){ jsch.addIdentity(authTypeMode.getAuthValue(),""); session.setPassword(authTypeMode.getAuthValue()); Properties sshConfig = new Properties(); sshConfig.put("StrictHostKeyChecking","no"); sshConfig.put("PreferredAuthentications","publickey,gssapi-with-mic,keyboard-interactive,password"); session.setConfig(sshConfig); logger.info("用户" + username + "成功登陆"); Channel channel = session.openChannel("sftp"); sftp = (ChannelSftp) channel; HashMap<String,Object> loginInfo = new HashMap<>(); loginInfo.put("sftp",sftp); loginInfo.put("session",session); } catch (JSchException e) {throw new RuntimeException("user login SFTP server occur exception:" + e);public void loginOut(ChannelSftp sftp, Session session){if(null != sftp && sftp.isConnected()){if (null != session && session.isConnected()){ logger.warn("用户退出SFTP服务器出现异常:" + e);public void download(String downloadFilePath, String downloadFileName, File saveFile, AuthTypeMode authTypeMode) throws Exception{ Assert.notNull(downloadFilePath,"download file absolute path is not null"); Assert.notNull(downloadFileName,"download file is not null"); Assert.notNull(saveFile,"save file location is not null"); Assert.notNull(authTypeMode,"auth type way is not null"); OutputStream outputStream = null; Map<String,Object> loginInfo = loginIn(authTypeMode); sftp = (ChannelSftp) loginInfo.get("sftp"); session = (Session) loginInfo.get("session"); logger.info("待下载文件地址为:" + downloadFilePath + ",文件名为:" + downloadFileName + ",认证方式:" + authTypeMode.getAuthValue()); sftp.cd(downloadFilePath); sftp.ls(downloadFileName); outputStream = new FileOutputStream(saveFile); sftp.get(downloadFileName,outputStream);if (null != outputStream){public void upload(String uploadPath, String uploadFile, AuthTypeMode authTypeMode) throws Exception{ Assert.notNull(uploadPath,"upload path is not null"); Assert.notNull(uploadFile,"upload file is not null"); Assert.notNull(authTypeMode,"auth type way is not null"); InputStream inputStream = null; Map<String,Object> loginInfo = loginIn(authTypeMode); sftp = (ChannelSftp) loginInfo.get("sftp"); session = (Session) loginInfo.get("session"); logger.info("待上传文件为:" + uploadFile + ",上传SFTP服务器路径:" + uploadPath + ",认证方式:" + authTypeMode.getAuthValue()); File file = new File(uploadFile); inputStream = new FileInputStream(file); } catch (SftpException e) { logger.error("SFTP器服务存放文件路径不存在");throw new RuntimeException("upload path is not exist"); sftp.put(inputStream,file.getName());if (null != inputStream){private String authValue; AuthTypeMode(String authType, String authValue){this.authType = authType;this.authValue = authValue;class SettleJschLogPrint implements com.jcraft.jsch.Logger{public boolean isEnabled(int i) {public void log(int i, String s) { PASSWORD("PASSWORD","密码认证"), AuthTypeEnum(String code, String desc){public static void main(String[] args) throws Exception{ SftpTool sftpTool = new SftpTool("192.168.79.151","albert",22); File saveFile = new File("/data/sftp/verifyfile_01.txt"); sftpTool.download("/verifyfile","verifyfile_01.csv",saveFile,sftpTool.new AuthTypeMode(AuthTypeEnum.PASSWORD.getCode(),"alan123456")); sftpTool.upload("/verifyfile","/data/sftp/verifyfile_01.txt",sftpTool.new AuthTypeMode(AuthTypeEnum.PASSWORD.getCode(),"alan123456")); SftpTool sftpToolTwo = new SftpTool("192.168.79.151","qingniu",22); File saveFileTwo = new File("/data/sftp/verifyfile_01.txt"); sftpToolTwo.download("/verifyfile","verifyfile_01.csv",saveFileTwo,sftpToolTwo.new AuthTypeMode(AuthTypeEnum.RSA.getCode(),"/data/rsa/id_rsa_qingniu")); //密钥认证方式上传文件( 上传会失败Permission denied,因为qingniu这个用户没有写的权限 ) sftpToolTwo.upload("/verifyfile","/data/sftp/verifyfile_01.txt",sftpToolTwo.new AuthTypeMode(AuthTypeEnum.RSA.getCode(),"/data/rsa/id_rsa_qingniu"));

    https://blog.csdn.net/alan_gui/article/details/85220010 ```