幾種方法來實現scp拷貝時無需輸入密碼

幾種方法來實現scp拷貝時無需輸入密碼

2015年01月15日 09:05:04 nfer_cn 閱讀數:52152 標籤: scp sshpass 不須要輸入密碼 expect ssh-keygen 更多
我的分類: shell
 

歡迎轉載!轉載時請註明出處:http://blog.csdn.net/nfer_zhuang/article/details/42646849linux

前言

我在工做中常常要將一些文件傳輸到另一個服務器上,並且都是Linux的命令行環境,那麼對於我來說scp就是最直接有效的方法了,其餘諸如FTP、SMB以及Winscp這些有界面的文件傳輸工具到反而有些多餘了。算法

使用過scp的都知道須要指定遠端服務器的賬號並手動輸入密碼,那麼如何避免每次都須要輸入密碼這個操做呢?下面就給出兩種方案進行解決。shell

方法一:創建SSH的信任關係

在這裏先介紹兩個概念:SSH公鑰(~/.ssh/id_rsa.pub)和公鑰受權文件(~/.ssh/authorized_keys),這兩個文件的做用具體能夠參考ssh的man手冊:安全

 ~/.ssh/id_rsa.pub
         Contains the public key for authentication.  These files are not sensitive and can (but need not) be readable by anyone.

 ~/.ssh/authorized_keys
         Lists the public keys (DSA/ECDSA/RSA) that can be used for logging in as this user.  The format of this file is described in the sshd(8) manual page.  This file is not highly sensitive, but the recommended permissions are read/write for the user, and not accessible by others.
ruby

從描述中咱們能夠知道,~/.ssh/id_rsa.pub文件中包含了認證的公鑰信息,並且該文件能夠被任何人讀取;而~/.ssh/authorized_keys文件中則列舉了登陸用戶的公鑰信息(換句話說就是使用這些公鑰信息能夠登陸當前設備),而爲了安全考慮,該文件通常建議只有本用戶能夠有讀寫權限。bash

公鑰和私鑰

提到公鑰對應的就會有私鑰,在談這兩個概念以前咱們先了解另一組概念:加密認證服務器

  • 加密是對數據進行處理,添加保護信息,若是非法用戶獲得被加密過的數據,也沒法獲取到原始的有效數據內容,因此加密的重點在於數據的安全性。
  • 認證是對數據進行處理,添加鑑權信息,若是在傳輸的過程當中被非法篡改,接收方就會校驗失敗並丟棄該非法數據,因此認證的重點在於數據的合法性。

上面是從業務概念來上描述了加密和認證的區別,可是從具體技術實現上,認證使用的是加密中的非對稱加密算法來實現鑑權和認證的操做。dom

  • 對稱加密算法在加密和解密時使用的是同一個祕鑰;
  • 非對稱加密算法須要兩個密鑰來進行加密和解密,這兩個祕鑰是公開密鑰(public key,簡稱公鑰)和私有密鑰(private key,簡稱私鑰)。

下面就分別描述一下,採用非對稱算法(即便用公鑰和私鑰)的加密和認證各自的過程。ssh

基於公鑰和私鑰的加密過程

有兩個用戶Alice和Bob,Alice想把一段數據加密後發送給Bob(注意這裏強調的是數據的安全性),那麼如何保證除了Bob以外的人即便竊取了數據也沒法解密獲得原始的數據?基於公鑰和私鑰的加密能夠完成這個需求,具體流程以下:ide

  1. Bob將他的公鑰發送給Alice
  2. Alice用Bob的公鑰加密須要傳輸的數據而後發送給Bob
  3. Bob用他的私鑰解密Alice的消息

 

基於公鑰和私鑰的認證過程

仍是Alice和Bob,Alice想把一段數據發送給Bob(注意這裏並不強調數據的安全性),當Bob收到數據時如何判斷該數據確實是Alic發送的且傳輸過程當中沒有被篡改?基於公鑰和私鑰的認證能夠完成這個需求,具體流程以下:

  1. Alice用她的私鑰對數據加密(或者對於數據的哈希值進行加密做爲簽名)
  2. Alice將加密後的數據(或者明文數據+簽名)發送給Bob
  3. Bob用Alice的公鑰解密數據(或校驗簽名),若是解密(校驗)成功則能夠保證數據的發送方確定是Alice

基於公鑰和私鑰的信任關係

瞭解了公鑰/私鑰以及加密/認證這些概念後,咱們就能夠在scp中使用公鑰/私鑰來創建一個信任關係,從而在數據傳輸時完成自動認證而無需輸入密碼。

  1. User在A主機將SCP請求使用本身的私鑰進行加密,而後傳輸給B主機
  2. B主機在收到SCP請求時,使用User的公鑰進行解密
  3. 若是解密成功,則表示該請求確實是User發送的請求,則容許操做;若是解密失敗,則表示該請求無效,直接丟棄

因此這裏的須要作的就是:

  • User在A主機上須要建立一個公私鑰對
  • 在B主機上,將User在A主機的公鑰加入到ssh的信任公鑰列表中(即公鑰受權文件)

建立公私鑰對

在Linux上使用ssh-keygen工具來生成公私鑰對,在man手冊中關於ssh-keygen工具的說明以下:

ssh-keygen : authentication key generation, management and conversion
 -t    type
     Specifies the type    of key to create.  The possible    values are 'rsa1' for protocol version 1 and 'dsa', 'ecdsa', 'ed25519', or 'rsa' for protocol version 2.

在上面提到了ssh-keygen支持rsa一、dsa、ecdsa、ed25519和rsa這幾種非對稱加密算法,其中最經常使用的就是RSA和DSA,好比使用RSA算法來生成公私鑰對的過程以下:

 

 
  1.  
    nfer@nfer-VirtualBox:~$ ssh-keygen -t rsa
  2.  
    Generating public/private rsa key pair.
  3.  
    Enter file in which to save the key (/home/nfer/.ssh/id_rsa):
  4.  
    Created directory '/home/nfer/.ssh'.
  5.  
    Enter passphrase (empty for no passphrase):
  6.  
    Enter same passphrase again:
  7.  
    Your identification has been saved in /home/nfer/.ssh/id_rsa.
  8.  
    Your public key has been saved in /home/nfer/.ssh/id_rsa.pub.
  9.  
    The key fingerprint is:
  10.  
    16:77:45:71:31:7c:67:4f:91:09:07:74:4d:30:83:48 nfer@nfer-VirtualBox
  11.  
    The key's randomart image is:
  12.  
    +--[ RSA 2048]----+
  13.  
    | .E..*@XO|
  14.  
    | . ..oBB|
  15.  
    | . . . o+|
  16.  
    | o . .|
  17.  
    | S |
  18.  
    | . |
  19.  
    | |
  20.  
    | |
  21.  
    | |
  22.  
    +-----------------+
  23.  
    nfer@nfer-VirtualBox:~$
注意上面有三處須要輸入信息,分別是:

 

  1. 存儲公私鑰的文件夾位置,若是不輸入,則默認爲~/.ssh/,文件名則默認是id_rsa和id_rsa.pub
  2. 使用該公私鑰時是否須要密碼,若是不輸入則表示不須要密碼
  3. 再次確認是否須要密碼

將User在A主機的公鑰加入到ssh的信任公鑰列表中

將剛纔建立的~/.ssh/id_rsa.pub文件中的內容拷貝添加到B主機上的~/.ssh/authorized_keys文件中(若是沒有則建立一個),這個時候就創建了一條A-->B的信任關係。注意這個信任關係是有方向性的,若是要創建從B-->A的信任關係,則操做步驟和上面的相似,只不過要反過來。

創建好信任關係後,這個時候使用任何ssh相關的工具則都無需輸入遠端的登錄密碼(若是在建立公私鑰對時輸入了密碼,那麼這個時候還須要輸入這個密碼才能使用公私鑰對)。

方法二:使用sshpass工具來自動輸入密碼

其實上面的創建信任關係的作法是最方便和安全的作法,可是在有些場景下(好比遠端的authorized_keys是不能隨意更改的),那麼這個時候咱們就能夠藉助sshpass這個第三方工具來完成ssh鏈接時的密碼輸入。先看一下sshpass的man手冊中是如何描述的:

       sshpass - noninteractive ssh password provider

從描述上就能夠清晰的瞭解到,sshpass的設計就是爲了使用非交互的場景下輸入ssh鏈接的密碼。

sshpass的使用比較簡單,先看一下幫助文檔:

nfer@nfer-VirtualBox:~$ sshpass
Usage: sshpass [-f|-d|-p|-e] [-hV] command parameters
   -f filename   Take password to use from file
   -d number     Use number as file descriptor for getting password
   -p password   Provide password as argument (security unwise)
   -e            Password is passed as env-var "SSHPASS"
   With no parameters - password will be taken from stdin

   -h            Show help (this screen)
   -V            Print version information
At most one of -f, -d, -p or -e should be used

其中-p是直接指定密碼,-f是從文件中讀取密碼。那麼一個使用sshpass的簡單例子就是:

 

sshpass -p nferzhuang scp a.txt nferzhuang@192.168.1.101:/home/nferzhuang/a.txt

 

使用sshpass的好處就是方便直接,無需瞭解公私鑰、加密認證等相關知識,簡單易懂;可是使用sshpass最大的壞處就是再使用時會涉及到明文密碼,大大下降了安全性。

方法三:使用expect腳原本自動輸入密碼

expect用於自動化地執行linux環境下的命令行交互任務,例如scp、ssh之類須要用戶手動輸入密碼而後確認的任務。有了這個工具,定義在scp過程當中可能遇到的狀況,而後編寫相應的處理語句,就能夠自動地完成scp操做了。

下面就是一個使用expect來完成scp時無需輸入密碼的腳本:

 

 
  1.  
    #!/usr/bin/expect
  2.  
    set timeout 10
  3.  
    set host [lindex $argv 0]
  4.  
    set username [lindex $argv 1]
  5.  
    set password [lindex $argv 2]
  6.  
    set src_file [lindex $argv 3]
  7.  
    set dest_file [lindex $argv 4]
  8.  
    spawn scp $src_file $username@$host:$dest_file
  9.  
    expect {
  10.  
    "(yes/no)?"
  11.  
    {
  12.  
    send "yes\n"
  13.  
    expect "*assword:" { send "$password\n"}
  14.  
    }
  15.  
    "*assword:"
  16.  
    {
  17.  
    send "$password\n"
  18.  
    }
  19.  
    }
  20.  
    expect "100%"
  21.  
    expect eof

 

注意代碼剛開始的第一行,指定了expect的路徑,與shell腳本相同,這一句指定了程序在執行時到哪裏去尋找相應的啓動程序。代碼剛開始還設定了timeout的時間爲10秒,若是在執行scp任務時遇到了代碼中沒有指定的異常,則在等待10秒後該腳本的執行會自動終止。

從以上代碼剛開始的幾行能夠看出,我爲這個腳本設置了5個須要手動輸入的參數,分別爲:目標主機的IP、用戶名、密碼、本地文件路徑、目標主機中的文件路徑。若是將以上腳本保存爲expect_scp文件,則在shell下執行時須要按如下的規範來輸入命令:

./expect_scp 192.168.75.130 root 123456 /root/src_file /root/dest_file
以上的命令執行後,將把本地/root目錄下的src_file文件拷貝到用戶名爲root,密碼爲123456的主機192.168.75.130中的/root下,同時還將這個源文件重命名爲dest_file。

spawn表明在本地終端執行的語句,在該語句開始執行後,expect開始捕獲終端的輸出信息,而後作出對應的操做。expect代碼中的捕獲的(yes/no)內容用於完成第一次訪問目標主機時保存密鑰的操做。有了這一句,scp的任務減小了中斷的狀況。代碼結尾的expect eof與spawn對應,表示捕獲終端輸出信息的終止。

 

使用expect須要瞭解的一點是:用expect速度會比較慢,由於須要等待返回的數據,而後輸入命令執行,沒有ssh密鑰登陸的快速。

注:關於expect部分詳細請參考《shell結合expect寫的批量scp腳本工具

總結

在本文中提供了三種方法來實現scp的時候無需輸入密碼的需求,從安全性和速度上考慮創建信任關係都是最佳的方法,至於在具體的環境中選擇什麼則由你本身來決定。

相關文章
相關標籤/搜索