檢視原始碼 SSH 設定

簡介

OTP SSH 應用程式可以透過大量的選項進行設定。本章不會深入探討每個選項的作用。但是,它將描述和定義輸入它們的不同方式。

關於安全強化的選項在強化 SSH章節中描述。關於演算法設定選項如何互動則在在 SSH 中設定演算法章節中描述。

選項設定

從 OTP-23.0 開始,主要有兩種設定選項的方式

  • 如同以往,在 Erlang 程式碼中呼叫例如 ssh:daemon/3ssh:connect/3 或其任何變體的 Options 參數中。範例:

    ssh:connect(22, [{user,"foo"}])
  • OTP 設定參數

    • 在 erl 命令列中

      erl -ssh user \"foo\"
    • ssh.app 檔案的 env 部分

      {application, ssh,
       [{description, "SSH-2 for Erlang/OTP"},
        {vsn, "4.9"},
        {modules, [ssh,
              ...
               ssh_xfer]},
        {registered, []},
        {applications, [kernel, stdlib, crypto, public_key]},
        {env, [{user, "bar"]}, % <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HERE
        {mod, {ssh_app, []}},
             ...
    • 在 .config 檔案中

      erl -config ex1

      其中 ex1.config 包含

      [
      {ssh, [{user, "foo"}]}
      ].

    如果選項僅適用於伺服器或客戶端,可以這樣設定

    [
    {ssh, [{server_options,[{user, "foo"}]},
           {client_options,[{user, "bar"}]}
    ].

    伺服器(守護進程)將使用使用者名稱 foo,而客戶端將使用名稱 bar

優先順序

如果選項以多種方式設定,會發生什麼事?

有一個順序,即

  • 層級 0:OTP SSH 原始碼中的硬編碼預設值
  • 層級 1:OTP 設定參數
  • 層級 2:OTP 設定參數 中的 server_optionsclient_options 中的選項
  • 層級 3:函式引數清單中的選項

如果同一個選項在兩個不同的層級設定,則使用較高層級的選項。

唯一的例外是 modify_algorithms 通用選項。它們全部按照層級升序應用於演算法集合。因此,第一層級的 modify_algorithms 會在第二層級的之前應用,依此類推。

如果在某個層級有 preferred_algorithms 選項,則整個集合將被該選項中的內容替換,並且所有 modify_algorithms 都會按層級順序應用

按層級順序應用所有 modify_algorithms 的原因是,讓使用者能夠添加一個已從預設集合中刪除的演算法,而無需更改程式碼,只需在設定檔中添加一個選項即可。這可以用來與仍然使用不再被認為足夠安全而預設不支援的演算法的舊系統進行互通。

演算法設定

關於 preferred_algorithmsmodify_algorithms 如何協作,有一個獨立的章節。不同的設定層級如何影響它們,將在本節中描述。

ssh:start/0 函式

如果應用程式 SSH 沒有啟動,則命令 ssh:default_algorithms/0 會根據目前 cryptolib 中的支援情況,傳回預設(硬編碼)演算法的清單。

如果應用程式 SSH 啟動,則命令 ssh:default_algorithms/0 會在應用層級 0 和層級 1 設定後,傳回演算法的清單。

這裡有一個範例。設定檔的內容如下

$ cat ex2.config
[
 {ssh, [{preferred_algorithms, [{cipher, ['aes192-ctr']},
       			        {public_key, ['ssh-rsa']},
                                {kex, ['ecdh-sha2-nistp384']},
                                {mac, ['hmac-sha1']}]}]}
].

Erlang 以 ex2.config 作為設定啟動,我們在啟動 ssh 之前檢查預設的演算法集合

$ erl -config ex2
Erlang/OTP 23 [RELEASE CANDIDATE 1] [erts-10.6.4] [source-96a0823109] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Eshell V10.6.4  (abort with ^G)
1> ssh:default_algorithms().
[{kex,['ecdh-sha2-nistp384','ecdh-sha2-nistp521',
       'ecdh-sha2-nistp256','diffie-hellman-group-exchange-sha256',
       'diffie-hellman-group16-sha512',
       'diffie-hellman-group18-sha512',
       'diffie-hellman-group14-sha256','curve25519-sha256',
       'curve25519-sha256@libssh.org','curve448-sha512',
       'diffie-hellman-group14-sha1',
       'diffie-hellman-group-exchange-sha1']},
 {public_key,['ecdsa-sha2-nistp384','ecdsa-sha2-nistp521',
              'ecdsa-sha2-nistp256','ssh-ed25519','ssh-ed448','ssh-rsa',
              'rsa-sha2-256','rsa-sha2-512','ssh-dss']},
 {cipher,[{client2server,['chacha20-poly1305@openssh.com',
                          'aes256-gcm@openssh.com','aes256-ctr','aes192-ctr',
                          'aes128-gcm@openssh.com','aes128-ctr','aes256-cbc',
                          'aes192-cbc','aes128-cbc','3des-cbc']},
          {server2client,['chacha20-poly1305@openssh.com',
                          'aes256-gcm@openssh.com','aes256-ctr','aes192-ctr',
                          'aes128-gcm@openssh.com','aes128-ctr','aes256-cbc',
                          'aes192-cbc','aes128-cbc','3des-cbc']}]},
 {mac,[{client2server,['hmac-sha2-256','hmac-sha2-512',
                       'hmac-sha1']},
       {server2client,['hmac-sha2-256','hmac-sha2-512',
                       'hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com',zlib]},
               {server2client,[none,'zlib@openssh.com',zlib]}]}]

請注意,檔案 ex2.config 中的演算法尚未應用。當我們啟動 ssh 時,它們才會被應用

2> ssh:start().
ok
3> ssh:default_algorithms().
[{kex,['ecdh-sha2-nistp384']},
 {public_key,['ssh-rsa']},
 {cipher,[{client2server,['aes192-ctr']},
          {server2client,['aes192-ctr']}]},
 {mac,[{client2server,['hmac-sha1']},
       {server2client,['hmac-sha1']}]},
 {compression,[{client2server,[none,'zlib@openssh.com',zlib]},
               {server2client,[none,'zlib@openssh.com',zlib]}]}]
4>

我們看到演算法集合已變更為 ex2.config 中的演算法集合。由於檔案中未指定 compression,因此該條目仍使用硬編碼的預設值。

建立連線(ssh:connect 等)或啟動守護進程(ssh:daemon)

當客戶端使用 ssh:connect 或其他函式建立連線,或者使用 ssh:daemon 啟動守護進程時,函式呼叫中的選項清單也會被使用。

如果啟動客戶端(ssh:connect 等),則會使用環境變數 client_options。同樣,對於守護進程,會處理 server_options 變數。

如果存在任何 preferred_algorithms,則會使用最高層級的演算法,也就是說,Option 清單參數具有最高的優先順序。然後,按順序從層級 0 開始,應用所有層級的 modify_algorithms

我們繼續上面的範例,連線到伺服器並修改 kex 演算法集合。我們移除唯一的演算法 ('ecdh-sha2-nistp384'),並將 'curve25519-sha256@libssh.org' 附加到現在為空的清單中

4> {ok,C} = ssh:connect(loopback, 22,
                        [{modify_algorithms,
                                 [{rm,
                                     [ {kex,['ecdh-sha2-nistp384']} ]
				  },
                                  {append,
			             [ {kex,['curve25519-sha256@libssh.org']} ]
				  }
				 ]
	                 }
                        ]).
{ok,>0.118.0>}

我們檢查客戶端和伺服器協商了哪些演算法,並注意到已選擇(唯一)的 kex 演算法 'curve25519-sha256@libssh.org'

5> ssh:connection_info(C, algorithms).
{algorithms,[{kex,'curve25519-sha256@libssh.org'},
             {hkey,'ssh-rsa'},
             {send_mac,'hmac-sha1'},
             {recv_mac,'hmac-sha1'},
             {encrypt,'aes192-ctr'},
             {decrypt,'aes192-ctr'},
             {compress,none},
             {decompress,none},
             {send_ext_info,false},
             {recv_ext_info,true}]}

modify_algorithms 處理範例

現在我們將檢查較低層級的 modify_algorithms 是否應用於較高層級的 preferred_algorithms。我們將透過啟用支援但不在預設集合中的 ssh-dss 演算法來完成此操作。

設定檔 ex3.config 的內容如下

[
 {ssh, [{modify_algorithms,
         [ {prepend, [{public_key, ['ssh-dss']}]} ]
        }]}
].

新啟動的 erlang shell 顯示 public_key 條目中不存在 'ssh-dss'

1> proplists:get_value(public_key, ssh:default_algorithms()).
['ecdsa-sha2-nistp384','ecdsa-sha2-nistp521',
 'ecdsa-sha2-nistp256','ssh-ed25519','ssh-ed448',
 'rsa-sha2-256','rsa-sha2-512','ssh-rsa']
2>

呼叫 ssh:connect/3 會移除除每一種型別的其中一個演算法之外的所有演算法

2> ssh:start().
ok
3> {ok,C} = ssh:connect(loopback, 22,
                        [{preferred_algorithms,
                         [{public_key, ['ecdsa-sha2-nistp256']},
			  {kex, ['ecdh-sha2-nistp256']},
		          {cipher, ['chacha20-poly1305@openssh.com']},
			  {mac, ['hmac-sha2-256']},
			  {compression, [none]}
			  ]}
			 ]).
{ok,<0.101.0>}
4> ssh:connection_info(C,algorithms).
{algorithms,[{kex,'ecdh-sha2-nistp256'},
             {hkey,'ssh-dss'},
             {send_mac,'chacha20-poly1305@openssh.com'},
             {recv_mac,'chacha20-poly1305@openssh.com'},
             {encrypt,'chacha20-poly1305@openssh.com'},
             {decrypt,'chacha20-poly1305@openssh.com'},
             {compress,none},
             {decompress,none},
             {send_ext_info,false},
             {recv_ext_info,true}]}
5>

但是 'ssh-dss' 被選擇了,即使呼叫僅插入了 'ecdsa-sha2-nistp256' 作為可接受的演算法。

此範例顯示我們可以透過設定檔擴充演算法集合,而無需變更實際的呼叫。

為了演示目的,我們使用 prepend 而不是 append。這會強制協商選擇 ssh-dss,因為完整的公鑰演算法清單是 ['ssh-dss','ecdsa-sha2-nistp256']。通常,附加非預設演算法更安全。