>운영 및 유지보수 >리눅스 운영 및 유지 관리 >SSH 및 SSH 서비스에 대한 기본 소개(터널 콘텐츠 포함)

SSH 및 SSH 서비스에 대한 기본 소개(터널 콘텐츠 포함)

零下一度
零下一度원래의
2017-07-21 13:47:225729검색

1.1 비대칭 암호화 기본 지식

대칭 암호화: 암호화와 복호화는 동일한 알고리즘을 사용합니다. 복호화 시 암호화된 비밀번호와 일치하면 복호화를 완료할 수 있습니다. 예를 들어 QQ 로그인 비밀번호, 은행 카드 비밀번호 등 비밀번호가 올바른지 확인하세요.

비대칭 암호화: 공개 키와 개인 키를 통해 암호화하고 해독합니다. 공개키로 암호화된 내용은 개인키로 복호화할 수 있고, 개인키로 암호화한 내용은 공개키로 복호화할 수 있다. 일반적으로 공개 키 암호화와 개인 키 암호 해독이 사용되지만 반드시 그런 것은 아닙니다. 예를 들어 CA가 인증서에 서명할 때 암호화를 위해 자체 개인 키를 사용합니다. 다음에 소개할 SSH 서비스에서는 항상 공개키를 배포하는 것을 권장하지만, 개인키도 배포할 수 있습니다.

따라서 A가 (개인 키 A, 공개 키 A)를 생성하고 B가 (개인 키 B, 공개 키 B)를 생성하는 경우 A와 B 간의 비대칭 암호화 세션 상황에는 다음이 포함됩니다.

(1) .A가 배포합니다. B는 공개 키 A를 사용하여 데이터를 암호화하고 암호화된 데이터를 A에게 보냅니다. A는 개인 키 A를 사용하여 데이터를 해독합니다.

(2).A는 공개 키 A를 B에 배포하고 자신의 개인 키 A를 사용하여 데이터를 암호화한 다음 B는 공개 키 A를 사용하여 데이터를 해독합니다.

(3).B는 공개 키 B를 A에게 배포합니다. A는 공개 키 B를 사용하여 데이터를 암호화하고 암호화된 데이터를 B에게 보냅니다. B는 자신의 개인 키 B를 사용하여 데이터를 해독합니다.

(4).B는 공개 키 B를 A에 배포하고 자신의 개인 키 B를 사용하여 데이터를 암호화한 다음 A는 공개 키 B를 사용하여 데이터를 해독합니다.

이론적으로는 4가지 시나리오를 지원하지만 SSH의 인증 단계에서 SSH는 공개 키를 유지하는 서버와 개인 키를 유지하는 클라이언트만 지원합니다. 따라서 클라이언트가 키를 생성하는 두 가지 방법만 있습니다. 예, 공개 키를 서버에 배포합니다. 서버는 키 쌍을 생성하고 개인 키를 클라이언트에 배포합니다. 그러나 보안과 편의를 위해 일반적으로 클라이언트는 키 쌍을 생성하고 공개 키를 배포합니다. 이 두 가지 배포 방법의 예는 다음과 같습니다.

1.2 SSH 개요

(1) SSH는 전송 계층과 애플리케이션 계층의 보안 프로토콜로 두 당사자 간의 세션을 암호화해야만 연결 보안을 보장할 수 있습니다. SSH 연결이 성공하면 클라이언트와 서버 간의 세션이 설정되고, 클라이언트와 서버 간의 모든 후속 통신이 해당 세션을 통해 전송됩니다.

(2) SSH 서비스의 데몬 프로세스는 기본적으로 포트 22에서 수신 대기하는 sshd입니다.

(3) ssh 명령, scp, sftp, ssh-copy-id 및 기타 명령을 포함한 모든 ssh 클라이언트 도구는 ssh 연결을 사용하여 작업을 완료합니다. 즉, 모두 서버의 포트 22에 연결되어 있지만, 연결된 후에는 실행할 해당 명령을 변환하여 원격 호스트에서 실행할 수 있도록 원격 호스트로 전송합니다.

(4) .ssh 클라이언트 명령(ssh, scp, sftp 등)은 두 개의 구성 파일, 즉 전역 구성 파일 /etc/ssh/ssh_config와 사용자 구성 파일 ~/.ssh/config를 읽습니다. 실제로 구성 옵션은 명령줄에서도 전달될 수 있습니다. 적용되는 우선순위는 명령줄 구성 옵션 > ~/.ssh/config > /etc/ssh/ssh_config입니다.

(5).ssh에는 호스트 확인과 사용자 인증이라는 두 가지 확인이 포함됩니다. 호스트 확인을 거쳐 호스트에서 사용자 확인을 통해 사용자의 신원을 고유하게 확인할 수 있습니다. 호스트에는 많은 사용자가 있을 수 있으므로 각 호스트는 한 번만 인증하면 되지만 호스트의 각 사용자는 개별적으로 인증해야 합니다.

(6).ssh는 다중 인증을 지원하며 가장 일반적으로 사용되는 인증 메커니즘은 비밀번호 인증 메커니즘과 공개 키 인증 메커니즘이 일부 시나리오에서 두 시스템 간의 상호 신뢰를 달성하는 데 거의 필요합니다. 위의 두 가지 인증 메커니즘이 일반적으로 사용되지만 인증 중 기본 순서는 gssapi-with-mic, 호스트 기반, 공개 키, 키보드 대화형, 비밀번호입니다. 호스트 인증 메커니즘인 호스트 기반은 호스트 인증이 아니라는 점에 유의하십시오. 호스트 인증은 거의 사용되지 않으므로(읽는 인증 파일은 /etc/hosts.equiv 또는 /etc/shosts.equiv입니다) 네트워크에서는 거의 볼 수 없습니다. . 일반적으로 ssh 구성 파일(sshd 구성 파일 아님)에서 PreferredAuthentications 명령을 사용하여 인증 순서를 변경하는 것은 검증 효율성을 높이는 방법으로 간주할 수 있습니다.

(7) SSH 클라이언트에는 실제로 포트 전달(터널 모드), 프록시 인증, 연결 공유(연결 다중화) 등과 같은 매우 강력한 기능이 많이 있습니다.

(8) SSH 서버 구성 파일은 /etc/ssh/sshd_config입니다. 클라이언트의 전역 구성 파일인 /etc/ssh/ssh_config와 구별됩니다.

(9). 가장 중요한 점은 ssh가 로그인하면 의사 터미널 할당을 요청한다는 것입니다. 그러나 sudo와 같은 일부 인증 프로그램에서는 이러한 유형의 터미널 할당을 금지하여 SSH 연결이 실패할 수 있습니다. 예를 들어, ssh를 사용하여 sudo 명령을 실행하면 sudo는 ssh에 터미널을 할당할지 여부를 확인합니다.


1.3 SSH 인증 프로세스 분석

클라이언트 A(172.16.10.5)에서 서버 B(172.16.10.6)로 연결하면 RSA 비대칭 Take 암호화를 기반으로 호스트 확인과 사용자 인증이라는 두 가지 프로세스가 포함됩니다. 알고리즘을 예로 들 수 있습니다.

[root@xuexi ~]# ssh 172.16.10.6

sshd 서비스 프로그램은 먼저 서버 B에서 시작됩니다. 즉, ssh 서비스가 활성화되고 포트 22가 열립니다(기본값).


1.3.1 호스트 확인 프로세스

클라이언트 A가 B에 연결하려고 하면 먼저 호스트 확인 프로세스를 수행합니다. 즉, 호스트 B가 이전에 연결되었는지 확인합니다.

확인하는 방법은 ~/.ssh/known_hosts 파일과 /etc/ssh/known_hosts 파일을 읽고 172.16.10.6의 호스트 정보를 검색하는 것입니다(호스트 정보를 호스트 키라고 하며, 호스트 ID를 나타냅니다). 해당 주소에 해당하는 호스트 키를 찾지 못하면 호스트 B가 보낸 호스트 키를 저장할지 묻고, 해당 주소의 호스트 키를 찾았으면 호스트 B가 보낸 호스트 키와 비교한다. 완전히 동일하다는 것은 호스트 A가 이전에 호스트 B의 호스트 키를 저장했다는 것을 의미합니다. 이를 다시 저장할 필요가 없으며 정확히 동일하지 않으면 바로 다음 프로세스인 인증으로 이동합니다. 현재 호스트 B가 사용하고 있는 호스트 키를 저장할 것인지 묻는 메시지를 표시합니다.

호스트 키 저장 여부를 묻는 과정은 다음과 같습니다.

[root@xuexi ~]# ssh 172.16.10.6 The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes

또는 Windows에서 그래픽 인터페이스 SSH 클라이언트 도구를 사용하는 경우:

인증 과정을 설명하기 전에 먼저 Known_hosts 파일 형식을 살펴보세요. ~/.ssh/known_hosts를 예로 들어 보겠습니다.

[root@xuexi ~]# cat ~/.ssh/known_hosts172.16.10.6 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz

이 파일에는 각 줄마다 호스트 키가 있고 줄의 시작 부분은 host key를 검색할 때 인덱스인 호스트 이름이고 호스트 이름 뒤의 내용입니다. 호스트 키 부분입니다. 이 파일을 예로 들면 클라이언트 A가 172.16.10.6에서 호스트 B에 연결을 시도한 후 호스트 B의 호스트 키를 저장했음을 나타냅니다. 다음에 호스트 B에 연결할 때 호스트의 호스트 키를 검색합니다. 10.6에서 보낸 호스트 키를 비교하여 일치하면 해당 호스트 키가 실제로 172.16.10.6에서 사용하는 호스트 키와 일치하지 않으면 172.16.10.6이 수정된 것입니다. 호스트 키 또는 이 파일의 호스트 키가 수정되었습니다.

그럼 현재 호스트 B가 사용하는 호스트 키는 어디에 저장되어 있나요? /etc/ssh/ssh_host* 파일에는 서버(여기서는 호스트 B)의 sshd 서비스 프로그램이 시작되면 이러한 파일이 다시 빌드됩니다. rsa 알고리즘을 예로 들면 /etc/ssh/ssh_host_rsa_key 및 /etc/ssh/ssh_host_rsa_key.pub에 저장됩니다. 공개 키 파일 /etc/ssh/ssh_host_rsa_key.pub에는 호스트 키가 저장됩니다.

[root@xuexi ~]# cat /etc/ssh/ssh_host_rsa_key.pub   # 在主机B上查看ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC675dv1w+GDYViXxqlTspUHsQjargFPSnR9nEqCyUgm5/32jXAA3XTJ4LUGcDHBuQ3p3spW/eO5hAP9eeTv5HQzTSlykwsu9He9w3ee+TV0JjBFulfBR0weLE4ut0PurPMbthE7jIn7FVDoLqc6o64WvN8LXssPDr8WcwvARmwE7pYudmhnBIMPV/q8iLMKfquREbhdtGLzJRL9DrnO9NNKB/EeEC56GY2t76p9ThOB6ES6e/87co2HjswLGTWmPpiqY8K/LA0LbVvqRrQ05+vNoNIdEfk4MXRn/IhwAh6j46oGelMxeTaXYC+r2kVELV0EvYV/wMa8QHbFPSM6nLz

/etc/ssh/ssh_host_rsa_key.pub 파일의 내용이 호스트보다 더 많은 것을 제외하고 ~/.ssh/known_hosts에 있는 호스트의 호스트 키 부분과 정확히 동일하다는 것을 발견했습니다. ~/.ssh/known_hosts의 핵심 부분 호스트를 검색할 때 색인화되는 호스트 이름이 지정됩니다.

요약하자면, 호스트 확인 단계에서는 서버가 개인 키를 보유하고 클라이언트는 서버에서 공개 키를 저장합니다. 이는 인증 단계에서 누가 키를 보유하는지와 반대입니다.

사실 ssh에서는 호스트 키가 너무 길어서 비교 효율이 낮기 때문에 호스트 키를 직접 비교하지 않습니다. 따라서 ssh는 호스트 키를 호스트 키 지문으로 변환한 다음 양쪽의 호스트 키 지문을 비교합니다. 지문 형식은 다음과 같습니다.

[root@xuexi ~]# ssh 172.16.10.6 The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
Are you sure you want to continue connecting (yes/no)? yes

호스트 키의 지문은 ssh-kegen으로 계산할 수 있습니다. 예를 들어, 다음은 호스트 A(172.16.10.5)가 저장한 호스트 키 지문과, 호스트 B(172.16.10.6)가 현재 사용하고 있는 호스트 키의 지문이다. 그것들은 완전히 동일하다는 것을 알 수 있습니다.

[root@xuexi ~]# ssh-keygen -l -f ~/.ssh/known_hosts2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf 172.16.10.6 (RSA)

[root@xuexi ~]# ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf   (RSA)

실제로 SSH는 호스트 키를 그래픽 지문으로 변환하는 호스트 키 퍼지 비교도 지원합니다. 이런 식으로 크게 다른 그래픽 결과를 쉽게 비교할 수 있습니다. 이를 퍼지 비교라고 부르는 이유는 ssh가 매우 유사한 그래픽 지문을 잘못 판단할 수 있기 때문입니다. 그래픽 지문은 다음과 같이 생성됩니다. 자세한 정보 표시 모드로 들어가려면 위 명령에 "-v" 옵션을 추가하기만 하면 됩니다.

[root@xuexi ~]# ssh-keygen -lv -f ~/.ssh/known_hosts2048 f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf 172.16.10.6 (RSA)+--[ RSA 2048]----+
|                 |
|                 |
|           .     |
|          o      |
|        S. . +   |
|      . +++ + .  |
|       B.+.= .   |
|      + B.  +.   |
|       o.+.  oE  |
+-----------------+


1.3.2 身份验证过程

主机验证通过后,将进入身份验证阶段。SSH支持多种身份验证机制,它们的验证顺序如下:gssapi-with-mic,hostbased,publickey,keyboard-interactive,password,但常见的是密码认证机制(password)和公钥认证机制(public key)。当公钥认证机制未通过时,再进行密码认证机制的验证。这些认证顺序可以通过ssh配置文件(注意,不是sshd的配置文件)中的指令PreferredAuthentications改变。

如果使用公钥认证机制,客户端A需要将自己生成的公钥(~/.ssh/id_rsa.pub)发送到服务端B的~/.ssh/authorized_keys文件中。当进行公钥认证时,客户端将告诉服务端要使用哪个密钥对,并告诉服务端它已经访问过密钥对的私钥部分~/.ssh/id_rsa(不能直接提供给服务端匹配检测,因为私钥不能泄露),然后服务端将检测密钥对的公钥部分,判断该客户端是否允许通过认证。如果认证不通过,则进入下一个认证机制,以密码认证机制为例。

当使用密码认证时,将提示输入要连接的远程用户的密码,输入正确则验证通过。


1.3.3 验证通过

当主机验证和身份验证都通过后,分两种情况:直接登录或执行ssh命令行中给定某个命令。如:

[root@xuexi ~]# ssh 172.16.10.6 [root@xuexi ~]# ssh 172.16.10.6  'echo "haha"'

(1) 이전 ssh 명령줄에는 명령 매개변수가 포함되어 있지 않습니다. 즉, 원격 호스트의 사용자(여기서는 루트 사용자)가 원격 호스트 172.16.10.6에 로그인하는 데 사용되므로 원격 호스트는 ssh에 의사 터미널을 할당하고 bash 환경으로 들어갑니다.

(2) 후자의 ssh 명령줄에는 명령 매개변수가 있는데, 이는 원격 호스트에서 주어진 명령 [echo "haha"]을 실행한다는 의미입니다. ssh 명령줄의 원격 명령은 fork ssh-agent에서 얻은 하위 프로세스를 통해 실행됩니다. 명령이 실행되면 하위 프로세스가 사라지고 ssh도 종료되며 설정된 세션과 연결도 닫힙니다. (여기서 원격 명령의 실행 과정을 명확하게 설명해야 하는 이유는 나중에 소개할 ssh로 포트 포워딩을 구현할 때 주의 사항을 설명하기 위함입니다.)

사실 ssh 연결이 성공하기 전에 로그인을 하거나 명령을 실행하는 것이 명령줄에서 원격으로 실행할 명령을 지정할 수 있습니다. 즉, ssh 연결이 설정된 후 가장 먼저 수행할 작업은 ~/.ssh/rc 또는 /etc/ssh/rc 파일에 있습니다. 두 파일의 원격 호스트에서 이러한 명령을 실행하는 것입니다.


1.4 다양한 파일 배포

호스트 B에 연결하는 호스트 A를 예로 들어 보겠습니다. 호스트 A는 SSH 클라이언트이고 호스트 B는 SSH 서버입니다.

서버에서 호스트 B:

  • /etc/ssh/sshd_config: SSH 서비스 프로그램 sshd의 구성 파일.

  • /etc/ssh/ssh_host_* : 서비스 프로그램 sshd가 시작될 때 생성되는 서버 공개 키 및 개인 키 파일입니다. ssh_host_rsa_key 및 ssh_host_rsa_key.pub 등이 있습니다. B: .pub 파일은 호스트 확인 시 호스트 키로, 클라이언트 ~/.ssh/known_hosts 파일에 기록됩니다.私: 中 개인 키 파일의 엄격한 요구 사항은 600입니다. 그렇지 않은 경우 SSHD 서비스 시작을 거부할 수 있습니다.

  • ~/.ssh/authorized_keys: 공개 키 인증 메커니즘을 기반으로 클라이언트의 공개 키를 저장합니다. 공개 키 인증 메커니즘을 기반으로 인증할 때 서버는 이 파일을 읽습니다.
  • 클라이언트에서 호스트 A:

  • /etc/ssh/ssh_config : 클라이언트의 전역 구성 파일입니다.

~/.ssh/config : 클라이언트의 사용자 구성 파일은 전역 구성 파일보다 우선순위가 높습니다. 일반적으로 이 파일은 기본적으로 존재하지 않습니다. 파일은 권한이 엄격합니다. 그리드는 소유자에게만 읽기/쓰기 권한이 있어야 하며 다른 사람에게는 쓰기 권한을 완전히 거부합니다.

    ~/.ssh/known_hosts: 호스트 검증 시 서버 호스트 호스트 키를 저장하는 파일. 파일 내용은 서버 측의 ssh_host_rsa_key.pub 파일에서 가져옵니다.
  • /etc/ssh/known_hosts: 글로벌 호스트 키 저장 파일. 이 함수는 ~/.ssh/known_hosts와 동일합니다.
  • ~/.ssh/id_rsa : 클라이언트가 생성한 개인 키입니다. SSH-keygen에 의해 생성되었습니다.
  • 이 파일에는 다른 사용자가 이 파일에 대해 읽기 가능한 권한이 있는 경우

  •                                       : ssh는 파일을 직접 무시합니다.

  • ~/.ssh/id_rsa.pub : 개인키 id_rsa와 짝을 이루는 공개키. 권한에 민감하지 않습니다. 공개 키 인증 메커니즘을 사용할 때 이 파일의 내용을 서버의

  •                                : ~/.ssh/authorized_keys 파일에 복사해야 합니다. /~/.Sh/rc: 명령 목록은 원격 호스트에 대한 SSH 연결이 성공하자마자 실행됩니다. S/ETC/SSH/RC: 역할은 ~/.ssh/rc와 동일합니다.
  • 1.5 구성 파일에 대한 간략한 소개
  • 서버 구성 파일 /etc/ssh/sshd_config와 클라이언트 구성 파일 /etc/ssh/ssh_config(전역) 또는 ~/.ssh/config(사용자)로 구분됩니다. ) .

    虽然服务端和客户端配置文件默认已配置项虽然非常少非常简单,但它们可配置项非常多。sshd_config完整配置项参见金步国翻译的sshd_config中文手册,ssh_config也可以参考sshd_config的配置,它们大部分配置项所描述的内容是相同的。


    1.5.1 sshd_config

    简单介绍下该文件中比较常见的指令。

    [root@xuexi ~]#  /etc//.  # 监听的IP地址。. protocol version /etc//ssh_host_key      # SSH 1保存位置/etc// protocol version /etc//ssh_host_rsa_key  # SSH 2保存RSA位置/etc///etc//ssh_host_dsa_key  # SSH 2保存DSA位置/etc///var/run//var/log//

    一般来说,如非有特殊需求,只需修改下监听端口和UseDNS为no以加快主机验证阶段的速度即可。

    配置好后直接重启启动sshd服务即可。

    [root@xuexi ~]# service sshd restart


    1.5.2 ssh_config

    需要说明的是,客户端配置文件有很多配置项和服务端配置项名称相同,但它们一个是在连接时采取的配置(客户端配置文件),一个是sshd启动时开关性的设置(服务端配置文件)。例如,两配置文件都有GSSAPIAuthentication项,在客户端将其设置为no,表示连接时将直接跳过该身份验证机制,而在服务端设置为no则表示sshd启动时不开启GSSAPI身份验证的机制。即使客户端使用了GSSAPI认证机制,只要服务端没有开启,就绝对不可能认证通过。

    下面也简单介绍该文件。

    # Host *                              # Host指令是ssh_config中最重要的指令,只有ssh连接的目标主机名能匹配此处给定模式时,
                                          # 下面一系列配置项直到出现下一个Host指令才对此次连接生效
    #   ForwardAgent no
    #   ForwardX11 no
    #   RhostsRSAAuthentication no
    #   RSAAuthentication yes
    #   PasswordAuthentication yes     # 是否启用基于密码的身份认证机制
    #   HostbasedAuthentication no     # 是否启用基于主机的身份认证机制
    #   GSSAPIAuthentication no        # 是否启用基于GSSAPI的身份认证机制
    #   GSSAPIDelegateCredentials no
    #   GSSAPIKeyExchange no
    #   GSSAPITrustDNS no
    #   BatchMode no                   # 如果设置为"yes",将禁止passphrase/password询问。比较适用于在那些不需要询问提供密
                                       # 码的脚本或批处理任务任务中。默认为"no"。
    #   CheckHostIP yes
    #   AddressFamily any
    #   ConnectTimeout 0#   StrictHostKeyChecking ask        # 设置为"yes",ssh将从不自动添加host key到~/.ssh/known_hosts文件,
                                         # 且拒绝连接那些未知的主机(即未保存host key的主机或host key已改变的主机)。
                                         # 它将强制用户手动添加host key到~/.ssh/known_hosts中。
                                         # 设置为ask将询问是否保存到~/.ssh/known_hosts文件。
                                         # 设置为no将自动添加到~/.ssh/known_hosts文件。
    #   IdentityFile ~/.ssh/identity     # ssh v1版使用的私钥文件
    #   IdentityFile ~/.ssh/id_rsa       # ssh v2使用的rsa算法的私钥文件
    #   IdentityFile ~/.ssh/id_dsa       # ssh v2使用的dsa算法的私钥文件
    #   Port 22                          # 当命令行中不指定端口时,默认连接的远程主机上的端口
    #   Protocol 2,1#   Cipher 3des                      # 指定ssh v1版本中加密会话时使用的加密协议
    #   Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc  # 指定ssh v1版本中加密会话时使用的加密协议
    #   MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160
    #   EscapeChar ~#   Tunnel no
    #   TunnelDevice any:any
    #   PermitLocalCommand no    # 功能等价于~/.ssh/rc,表示是否允许ssh连接成功后在本地执行LocalCommand指令指定的命令。
    #   LocalCommand             # 指定连接成功后要在本地执行的命令列表,当PermitLocalCommand设置为no时将自动忽略该配置
                                 # %d表本地用户家目录,%h表示远程主机名,%l表示本地主机名,%n表示命令行上提供的主机名,
                                 # p%表示远程ssh端口,r%表示远程用户名,u%表示本地用户名。
    #   VisualHostKey no         # 是否开启主机验证阶段时host key的图形化指纹
    Host *GSSAPIAuthentication yes

     

    如非有特殊需求,ssh客户端配置文件一般只需修改下GSSAPIAuthentication的值为no来改善下用户验证的速度即可,另外在有非交互需求时,将StrictHostKeyChecking设置为no以让主机自动添加host key。


    1.6 ssh命令简单功能

    此处先介绍ssh命令的部分功能,其他包括端口转发的在后文相关内容中解释,关于连接复用的选项本文不做解释。

    语法:

    ssh [options] [user@]hostname [command]
     
    参数说明:-b bind_address :在本地主机上绑定用于ssh连接的地址,当系统有多个ip时才生效。-E log_file     :将debug日志写入到log_file中,而不是默认的标准错误输出stderr。-F configfile   :指定用户配置文件,默认为~/.ssh/config。-f              :请求ssh在工作在后台模式。该选项隐含了"-n"选项,所以标准输入将变为/dev/null。-i identity_file:指定公钥认证时要读取的私钥文件。默认为~/.ssh/id_rsa。-l login_name   :指定登录在远程机器上的用户名。也可以在全局配置文件中设置。-N              :显式指明ssh不执行远程命令。一般用于端口转发,见后文端口转发的示例分析。-n              :将/dev/null作为标准输入stdin,可以防止从标准输入中读取内容。ssh在后台运行时默认该项。-p port         :指定要连接远程主机上哪个端口,也可在全局配置文件中指定默认的连接端口。-q              :静默模式。大多数警告信息将不输出。-T              :禁止为ssh分配伪终端。-t              :强制分配伪终端,重复使用该选项"-tt"将进一步强制。-v              :详细模式,将输出debug消息,可用于调试。"-vvv"可更详细。-V              :显示版本号并退出。-o              :指定额外选项,选项非常多。
    user@hostname   :指定ssh以远程主机hostname上的用户user连接到的远程主机上,若省略user部分,则表示使用本地当前用户。
                    :如果在hostname上不存在user用户,则连接将失败(将不断进行身份验证)。
    command         :要在远程主机上执行的命令。指定该参数时,ssh的行为将不再是登录,而是执行命令,命令执行完毕时ssh连接就关闭。

    例如,以172.16.10.6主机上的longshuai用户登录172.16.10.6。

    [root@xuexi ~]# ssh longshuai@172.16.10.6The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.ECDSA key fingerprint is 18:d1:28:1b:99:3b:db:20:c7:68:0a:f8:9e:43:e8:b4.Are you sure you want to continue connecting (yes/no)? yes       # 主机验证Warning: Permanently added '172.16.10.6' (ECDSA) to the list of known hosts.longshuai@172.16.10.6's password:                      # 用户验证Last login: Wed Jul  5 12:27:29 2017 from 172.16.10.6

    此时已经登录到了172.16.10.6主机上。

    [longshuai@xuexi ~]$ hostname -I172.16.10.6

    要退出ssh登录,使用logout命令或exit命令即可返回到原主机环境。

    使用ssh还可以实现主机跳转,即跳板功能。例如主机B能和A、C通信,但A、C之间不同通信,即A71fb34173e4ee87dab1f85dc1c283a44B71fb34173e4ee87dab1f85dc1c283a44Cfe36de6936ad20bec13da33b00c99495A的情形。如果要从A登陆到C,则可以借助B这个跳板登录到C。此处一个简单示例为:从172.16.10.5登录到172.16.10.6,再以此为基础登录到172.16.100.3上。

    [root@xuexi ~]# ssh 172.16.10.6The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts.
    Last login: Wed Jul  5 12:36:51 2017 from 172.16.10.6
    [root@xuexi ~]# ssh 172.16.10.3The authenticity of host '172.16.10.3 (172.16.10.3)' can't be established.ECDSA key fingerprint is 18:d1:28:1b:99:3b:db:20:c7:68:0a:f8:9e:43:e8:b4.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added '172.16.10.3' (ECDSA) to the list of known hosts.
    root@172.16.10.3's password:Last login: Thu Jun 29 12:38:56 2017 from 172.16.10.6
    [root@xuexi ~]# hostname -I172.16.10.3 172.16.10.4

    同样,在退出时,也是一层一层退出的。

    [root@xuexi ~]# exit
    logout
    Connection to 172.16.10.3 closed.
    
    [root@xuexi ~]# hostname -I   
    172.16.10.6[root@xuexi ~]# exit
    logout
    Connection to 172.16.10.6 closed.

    注意,由于在借助172.16.10.6当跳板连接到172.16.10.3,所以172.16.10.3的host key是添加到172.16.10.3上而非172.16.10.5上的。

    如果在命令行给出了要执行的命令,默认ssh将工作在前台,如果同时给定了"-f"选项,则ssh工作在后台。但尽管是工作在后台,当远程执行的命令如果有消息返回时,将随时可能显示在本地。当远程命令执行完毕后,ssh连接也将立即关闭。

    [root@xuexi ~]# ssh 172.16.10.6 'sleep 5'     # 在前台睡眠5秒钟
    
    [root@xuexi ~]# ssh 172.16.10.6 -f 'sleep 5;echo over'   # 在后台睡眠5秒,睡眠完成后echo一段信息

    由于第二条命令是放在后台执行的,所以该ssh一建立完成ssh会话就立即返回本地bash环境,但当5秒之后,将在本地突然显示"over"。

    ssh执行远程命令默认允许从标准输入中读取数据然后传输到远程。可以使用"-n"选项,使得标准输入重定向为/dev/null。例如:

    [root@xuexi ~]# echo haha | ssh 172.16.10.6 'cat'haha
    
    [root@xuexi ~]# ssh 172.16.10.6 'cat' c63e8327f4334772e0cd0645af928a6f> ~/.ssh/authorized_keys"

    该命令首先建立ssh连接,并在远程执行"umask 077"临时修改远程的umask值,使得远程创建的目录权限为700,然后判断远程主机上是否有~/.ssh目录,如果没有则创建,最后从标准输入中读取本地公钥文件~/.ssh/id_rsa.pub的内容并将其追加到~/.ssh/authorized_keys文件中。

    如果将此命令改为如下命令,使用ssh的"-n"选项,并将追加重定向改为覆盖重定向符号。

    [root@xuexi ~]# cat ~/.ssh/id_rsa.pub | ssh -n 172.16.10.6 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat > ~/.ssh/authorized_keys"

    该命令的结果是清空远程主机172.16.10.6上的~/.ssh/authorized_keys文件,因为ssh的"-n"选项强行改变了ssh读取的标准输入为/dev/null。


    1.7 scp命令及过程分析

    scp是基于ssh的远程拷贝命令,也支持本地拷贝,甚至支持远程到远程的拷贝。

    scp由于基于ssh,所以其端口也是使用ssh的端口。其实,scp拷贝的实质是使用ssh连接到远程,并使用该连接来传输数据。下文有scp执行过程的分析。

    另外,scp还非常不占资源,不会提高多少系统负荷,在这一点上,rsync远不及它。虽然 rsync比scp会快一点,但rsync是增量拷贝,要判断每个文件是否修改过,在小文件众多的情况下,判断次数非常多,导致rsync效率较差,而scp基本不影响系统正常使用。

    scp每次都是全量拷贝,在某些情况下,肯定是不及rsync的。

    scp [-12BCpqrv] [-l limit] [-o ssh_option] [-P port] [[user@]host1:]src_file ... [[user@]host2:]dest_file
    
    选项说明:-1:使用ssh v1版本,这是默认使用协议版本-2:使用ssh v2版本-C:拷贝时先压缩,节省带宽-l limit:限制拷贝速度,Kbit/s,1Byte=8bit,所以"-l 800"表示的速率是100K/S-o ssh_option:指定ssh连接时的特殊选项,一般用不上。-P port:指定目标主机上ssh端口,大写的字母P,默认是22端口-p:拷贝时保持源文件的mtime,atime,owner,group,privileges-r:递归拷贝,用于拷贝目录。注意,scp拷贝遇到链接文件时,会拷贝链接的源文件内容填充到目标文件中(scp的本质就是填充而非拷贝)-v:输出详细信息,可以用来调试或查看scp的详细过程,分析scp的机制

    src_file是源位置,dest_file是目标位置,即将src_file复制到dest_file,其中src_file可以指定多个。由于源位置和目标位置都可以使用本地路径和远程路径,所以scp能实现本地拷贝到远程、本地拷贝到本地、远程拷贝到本地、远程拷贝到另一个远程。其中远程路径的指定格式为"user@hostname:/path",可以省略user,也可以省略":/path",省略":/path"时表示拷贝到目的用户的家目录下。

    注意:scp拷贝是强制覆盖型拷贝,当有重名文件时,不会进行任何询问。

    例如:

    (1).本地拷贝到本地:/etc/fstab-->/tmp/a.txt。

    [root@xuexi ~]# scp /etc/fstab /tmp/a.txt

    (2).本地到远程:/etc/fstab-->172.16.10.6:/tmp/a.txt。

    [root@xuexi ~]# scp /etc/fstab 172.16.10.6:/tmp
    fstab                                          100%  805     0.8KB/s   00:00

    (3).远程到本地:172.16.10.6:/etc/fstab-->/tmp/a.txt。

    [root@xuexi ~]# scp 172.16.10.6:/etc/fstab /tmp/a.txt
    fstab                                          100%  501     0.5KB/s   00:00

    (4).远程路径1到远程路径2:172.16.10.6:/etc/fstab-->/172.16.10.3:/tmp/a.txt。

    [root@xuexi ~]# scp 172.16.10.6:/etc/fstab 172.16.10.3:/tmp/a.txt
    fstab                                          100%  501     0.5KB/s   00:00   Connection to 172.16.10.6 closed.


    1.7.1 scp拷贝机制分析

    scp的拷贝实质是建立ssh连接,然后通过此连接来传输数据。如果是远程1拷贝到远程2,则是将scp命令转换后发送到远程1上执行,在远程1上建立和远程2的ssh连接,并通过此连接来传输数据。

    在远程复制到远程的过程中,例如在本地(172.16.10.5)执行scp命令将A主机(172.16.10.6)上的/tmp/copy.txt复制到B主机(172.16.10.3)上的/tmp目录下,如果使用-v选项查看调试信息的话,会发现它的步骤类似是这样的。

    # 以下是从结果中提取的过程
    # 首先输出本地要执行的命令
    Executing: /usr/bin/ssh -v -x -oClearAllForwardings yes -t -l root 172.16.10.6 scp -v /tmp/copy.txt root@172.16.10.3:/tmp
     
    # 从本地连接到A主机
    debug1: Connecting to 172.16.10.6 [172.16.10.6] port 22.
    debug1: Connection established.
     
    # 要求验证本地和A主机之间的连接
    debug1: Next authentication method: password
    root@172.16.10.6's password: # 将scp命令行修改后发送到A主机上
    debug1: Sending command: scp -v /tmp/copy.txt root@172.16.10.3:/tmp
     
    # 在A主机上执行scp命令
    Executing: program /usr/bin/ssh host 172.16.10.3, user root, command scp -v -t /tmp
     
    # 验证A主机和B主机之间的连接
    debug1: Next authentication method: password
    root@172.16.10.3's password: # 从A主机上拷贝源文件到最终的B主机上
    debug1: Sending command: scp -v -t /tmp
    Sending file modes: C0770 24 copy.txt
    Sink: C0770 24 copy.txt
    copy.txt                                                           100%   24     0.0KB/s  
     
    # 关闭本地主机和A主机的连接
    Connection to 172.16.10.6 closed.

    也就是说,远程主机A到远程主机B的复制,实际上是将scp命令行从本地传输到主机A上,由A自己去执行scp命令。也就是说,本地主机不会和主机B有任何交互行为,本地主机就像是一个代理执行者一样,只是帮助传送scp命令行以及帮助显示信息。

    其实从本地主机和主机A上的~/.ssh/know_hosts文件中可以看出,本地主机只是添加了主机A的host key,并没有添加主机B的host key,而在主机A上则添加了主机B的host key。

     

    1.8 基于公钥认证机制实现双机互信

    在身份验证阶段,由于默认情况下基于公钥认证的机制顺序优先于基于密码认证的机制,所以基于公钥认证身份,就可以免输入密码,即实现双机互信(实际上只是单方向的信任)。

    基于公钥认证机制的认证过程在前文已经详细说明过了,如还不清楚,请跳回上文。


    1.8.1 实现步骤

    以下是实现基于公钥认证的实现步骤:

    (1).在客户端使用ssh-keygen生成密钥对,存放路径按照配置文件的指示,默认是在~/.ssh/目录下。

    [root@xuexi ~]# ssh-keygen -t rsa    # -t参数指定算法,可以是rsa或dsa
    Generating public/private rsa key pair.
    Enter file in which to save the key (/root/.ssh/id_rsa):  # 询问私钥保存路径
    Enter passphrase (empty for no passphrase):               # 询问是否加密私钥文件
    Enter same passphrase again:            
    Your identification has been saved in /root/.ssh/id_rsa. 
    Your public key has been saved in /root/.ssh/id_rsa.pub.

    如果不想被询问,则可以使用下面一条命令完成:"-f"指定私钥文件,"-P"指定passphrase,或者"-N"也一样。

    [root@xuexi ~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ''   # 指定加密私钥文件的密码为空密码,即不加密
    
    [root@xuexi ~]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ''   # 同上

    查看~/.ssh/目录下私钥的权限。私钥文件有严格的权限要求,当私钥文件的非所有者有可读权限时,将直接忽略该私钥文件导致公钥认证失败。

    [root@xuexi ~]# ls -l ~/.sshtotal 12-rw------- 1 root root 1671 Jun 29 00:18 id_rsa      # 私钥权限必须600,属主为自己-rw-r--r-- 1 root root  406 Jun 29 00:18 id_rsa.pub-rw-r--r-- 1 root root  393 Jun 29 05:56 known_hosts

    (2).将上面生成的公钥使用ssh-copy-id分发(即复制)到远程待信任主机上。

    ssh-copy-id用法很简单,只需指定待信任主机及目标用户即可。如果生成的公钥文件,路径不是~/.ssh/id_rsa.pub,则使用"-i"选项指定要分发的公钥。

    ssh-copy-id [-i [identity_file]] [user@]machine

    例如,将公钥分发到172.16.10.6上的root用户家目录下:

    [root@xuexi ~]# ssh-copy-id 172.16.10.6

    ssh-copy-id唯一需要注意的是,如果ssh服务端的端口不是22,则需要给ssh-copy-id传递端口号,传递方式为"-p port_num [user@]hostname",例如"-p 22222 root@172.16.10.6"。之所以要如此传递,见下面摘自ssh-copy-id中公钥分发的命令部分。

    { eval "$GET_ID" ; } | ssh $1 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys && (test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)" || exit 1

    其中"{ eval "$GET_ID" ; }"可理解为待分发的本地公钥内容,"(test -x /sbin/restorecon && /sbin/restorecon ~/.ssh ~/.ssh/authorized_keys >/dev/null 2>&1 || true)"和selinux有关,不用管,所以上述命令简化为:

    cat ~/.ssh/id_rsa.pub | ssh $1 "umask 077; test -d ~/.ssh || mkdir ~/.ssh ; cat >> ~/.ssh/authorized_keys || exit 1

    可见,ssh-copy-id的所有参数都是存储在位置变量$1中传递给ssh,所以应该将ssh的端口选项"-p port_num"和user@hostname放在一起传递。

    通过分析上面的命令,也即知道了ssh-copy-id的作用:在目标主机的指定用户的家目录下,检测是否有~/.ssh目录,如果没有,则以700权限创建该目录,然后将本地的公钥追加到目标主机指定用户家目录下的~/.ssh/authorized_keys文件中。


    1.8.2 一键shell脚本

    就这样简单的两步就实现了基于公钥的身份认证。当然,不使用ssh-copy-id,也一样能实现上述过程。更便捷地,可以写一个简单的脚本,简化上述两个步骤为1个步骤。

    #!/bin/bash
     
    ###########################################################
    #  description: public key authentication in one step     #
    #  author     : 骏马金龙                                   #
    #  blog       : http://www.cnblogs.com/f-ck-need-u/       ############################################################
     
    privkey="$HOME/.ssh/id_rsa"publickey="$HOME/.ssh/id_rsa.pub"
     # Usage helpif [ $# -ne 1 ];then
       echo "Usage:$0 [user@]hostname"
       exit 1fi
     # test private/publick key exist or not, and the privilege 600 or notif [ -f "$privkey" -a -f "$publickey" ];then
       privkey_priv=`stat -c %a $privkey`   if [ "$privkey_priv" -ne 600 ];then   echo "The privilege of private key ~/.ssh/id_rsa is not 600, exit now."   exit 1
       fielse
       echo "private/public key is not exist, it will create it"
       ssh-keygen -t rsa -f $privkey -N ''
       echo "keys created over, it located on $HOME/.ssh/"fi
     ssh-copy-id "-o StrictHostKeyChecking=no $1"
     if [ $? -eq 0 ];then
       echo -e "\e[31m publickey copy over \e[0m"else
       echo "ssh can't to the remote host"
       exit 1fi

    该脚本将检查本地密钥对~/.ssh/{id_rsa,id_rsa.pub}文件是否存在,还检查私钥文件的权限是否为600。如果缺少某个文件,将自动新创建密钥对文件,最后分发公钥到目标主机。


    1.8.3 公钥认证之——服务端分发私钥

    对于基于公钥认证的身份验证机制,除了上面客户端分发公钥到服务端的方法,还可以通过分发服务端私钥到客户端来实现。

    先理清下公钥认证的原理:客户端要连接服务端,并告诉服务端要使用那对密钥对,然后客户端访问自己的私钥,服务端检测对应的公钥来决定该公钥所对应的客户端是否允许连接。所以对于基于公钥认证的身份验证,无论是客户端分发公钥,还是服务端分发私钥,最终客户端保存的一定是私钥,服务端保存的一定是公钥。

    那么服务端分发私钥实现公钥认证是如何实现的呢?步骤如下:假如客户端为172.16.10.5,服务端为172.16.10.6。

    (1).在服务端使用ssh-keygen生成密钥对。

    [root@xuexi ~]# ssh-keygen -f ~/.ssh/id_rsa -P ''

    (2).将上面生成的公钥追加到自己的authorized_keys文件中。

    [root@xuexi ~]# ssh-copy-id 172.16.10.6

    (3).将私钥拷贝到客户端,且路径和文件名为~/.ssh/id_rsa。

    [root@xuexi ~]# scp -p ~/.ssh/id_rsa* 172.16.10.5:/root/.ssh/

    注意,第三步中也拷贝了公钥,原因是客户端连接服务端时会比较自己的公钥和私钥是否配对,如果不配对将直接忽略公钥认证机制,所以会要求输入密码。可以将客户端的公钥删除掉,或者将服务端生成的公钥覆盖到客户端的公钥上,都能完成公钥认证。

    虽说,服务端分发私钥的方式很少用,但通过上面的步骤,想必对ssh基于公钥认证的身份验证过程有了更深入的理解。


    1.9 expect实现ssh/scp完全非交互(批量)

    expect工具可以在程序发出交互式询问时按条件传递所需的字符串,例如询问yes/no自动传递y或yes,询问密码时自动传递指定的密码等,这样就能让脚本完全实现非交互。

    显然,ssh等客户端命令基于密码认证时总是会询问密码,即使是基于公钥认证,在建立公钥认证时也要询问一次密码。另外,在ssh主机验证时还会询问是否保存host key。这一切都可以通过expect自动回答。

    关于expect工具,它使用的是tcl语言,虽说应用在expect上的tcl语言并非太复杂,但这并非本文内容,如有兴趣,可网上搜索或直接阅读man文档。

    首先安装expect工具。

    [root@xuexi ~]# yum -y install expect


    1.9.1 scp自动应答脚本

    以下是scp自动问答的脚本。

    [root@xuexi ~]# !/usr/bin/ { send

    用法:autoscp.exp [user@]hostname src_file dest_file [password]

    该自动回答脚本可以自动完成主机验证和密码认证,即使已经是实现公钥认证的机器也没问题,因为公钥认证机制默认优先于密码认证,且此脚本的password项是可选的,当然,在没有实现公钥认证的情况下,password是必须项,否则expect实现非交互的目的就失去意义了。

    以下是几个示例:

    [root@xuexi ~]# ./autoscp.exp 172.16.10.6 /etc/fstab /tmp 123456spawn scp /etc/fstab 172.16.10.6:/tmp
    The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
    Are you sure you want to continue connecting (yes/no)? yes          # 主机验证时询问是否保存host key,自动回答yes
    Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts.
    root@172.16.10.6's password:                                        # 密码认证过程,自动回答指定的密码"123456"fstab                                                        100%  805     0.8KB/s   00:00

    也可以指定完成的用户名和主机名。

    [root@xuexi ~]# ./autoscp.exp root@172.16.10.6 /etc/fstab /tmp 123456spawn scp /etc/fstab root@172.16.10.6:/tmp
    root@172.16.10.6's password:         fstab                                 100%  805     0.8KB/s   00:00


    1.9.2 ssh-copy-id自动应答脚本

    以下是在建立公钥认证机制时,ssh-copy-id拷贝公钥到服务端的自动应答脚本。

    [root@xuexi ~]# cat /tmp/autocopy.exp
    #!/usr/bin/expect
    
    ###########################################################
    #  description: scp without interactive                   #
    #  author     : 骏马金龙                                   #
    #  blog       : http://www.cnblogs.com/f-ck-need-u/       ############################################################
    
    set timeout 10set user_hostname [lindex $argv 0]
    set password [lindex $argv 1]
    spawn ssh-copy-id $user_hostname
        expect {"(yes/no)?"{
                send "yes\n"expect "*assword:" { send "$password\n"}
            }"*assword:"{
                send "$password\n"}
        }
    expect eof

    用法:autocopy.exp [user@]hostname password

    以下是一个示例,

    [root@xuexi ~]# /tmp/autocopy.exp root@172.16.10.6 123456spawn ssh-copy-id root@172.16.10.6The authenticity of host '172.16.10.6 (172.16.10.6)' can't be established.RSA key fingerprint is f3:f8:e2:33:b4:b1:92:0d:5b:95:3b:97:d9:3a:f0:cf.
    Are you sure you want to continue connecting (yes/no)? yes      # 主机认证时,自动应答yes
    Warning: Permanently added '172.16.10.6' (RSA) to the list of known hosts.
    root@172.16.10.6's password:                                    # 密码认证时自动输入密码"123456"Now try logging into the machine, with "ssh 'root@172.16.10.6'", and check in:
     
      .ssh/authorized_keys
     
    to make sure we haven't added extra keys that you weren't expecting.

    如果要实现批量非交互,则可以写一个shell脚本调用该expect脚本。例如:

    [root@xuexi ~]# cat /tmp/sci.sh#!/bin/bash
    
    ###########################################################
    #  description: scp without interactive                   #
    #  author     : 骏马金龙                                   #
    #  blog       : http://www.cnblogs.com/f-ck-need-u/       ############################################################ 
    passwd=123456               # 指定要传递的密码为123456
    user_host=`awk '{print $3}' ~/.ssh/id_rsa.pub`   # 此变量用于判断远程主机中是否已添加本机信息成功 
    for i in $@  
    do/tmp/autocopy.exp $i $passwd >&/dev/nullssh $i "grep "$user_host" ~/.ssh/authorized_keys" >&/dev/null  # 判断是否添加本机信息成功if [ $? -eq 0 ];thenecho "$i is ok"elseecho "$i is not ok"fidone

    用法:/tmp/sci.sh [user@]hostname

    其中hostname部分可以使用花括号展开方式枚举。但有个bug,最好ssh-copy-id的目标不要是脚本所在的本机,可能会强制输入本机密码,但批量脚本autocopy.exp则没有此bug。

    例如:

    [root@xuexi tmp]# /tmp/sci.sh 172.16.10.3 172.16.10.6172.16.10.3 is ok172.16.10.6 is ok
    [root@xuexi tmp]# /tmp/sci.sh 172.16.10.{3,6}172.16.10.3 is ok172.16.10.6 is ok
    [root@xuexi tmp]# /tmp/sci.sh root@172.16.10.3 172.16.10.6root@172.16.10.3 is ok172.16.10.6 is ok


    1.10 ssh连接速度慢的几个原因和解决办法

    ssh连接包括两个阶段:主机验证阶段和身份验证阶段。这两个阶段都可能导致连接速度慢。

    具体是哪个阶段的速度慢,完全可以通过肉眼看出来:

    (1).卡着很久才提示保存host key肯定是主机验证过程慢。

    (2).主机验证完成后卡着很久才提示输入密码,肯定是身份验证过程慢。

    其中主机验证过程慢的原因,可能是网络连接慢、DNS解析慢等原因。网络连接慢,ssh对此毫无办法,而DNS解析慢,ssh是可以解决的,解决方法是将ssh服务端的配置文件中UseDNS设置为no(默认为yes)。

    而身份验证慢的原因,则考虑ssh的身份验证顺序:gssapi,host-based,publickey,keyboard-interactive,password。其中gssapi认证顺序是比较慢的,所以解决方法一是在ssh客户端配置文件中将GSSAPI认证机制给关掉,解决方法二是在ssh客户端配置文件中使用PreferredAuthentications指令修改身份验证顺序。

    方法一修改:GSSAPIAuthentication yes

    方法二修改:PreferredAuthentications publickey,password,gssapi,host-based,keyboard-interactive

    如果感受不到哪个阶段导致速度变慢,可以使用ssh或scp等客户端工具的"-vvv"选项进行调试,看看是卡在哪个地方,不过,想看懂"-vvv"的过程,还是比较考验耐心的。


    1.11 SSH安全隧道(ssh跃墙之术)


    1.11.1 ssh安全隧道(一):本地端口转发

    如下图,假如host3和host1、host2都同互相通信,但是host1和host2之间不能通信,如何从host1连接上host2?

    对于实现ssh连接来说,实现方式很简单,从host1 ssh到host3,再ssh到host2,也就是将host3作为跳板的方式。但是如果不是ssh,而是http的80端口呢?如何让host1能访问host2的80端口?

    ssh支持本地端口转发,语法格式为:

    ssh -L [bind_addr:]local_port:remote:remote_port middle_host

    以上图为例,实现方式是在host1上执行:

    [root@xuexi ~]# ssh -g -L 2222:host2:80 host3

    其中"-L"选项表示本地端口转发,其工作方式为:在本地指定一个由ssh监听的转发端口(2222),将远程主机的端口(host2:80)映射为本地端口(2222),当有主机连接本地映射端口(2222)时,本地ssh就将此端口的数据包转发给中间主机(host3),然后host3再与远程主机的端口(host2:80)通信。

    现在就可以通过访问host1的2222端口来达到访问host2:80的目的了。例如:

    再来解释下"-g"选项,指定该选项表示允许外界主机连接本地转发端口(2222),如果不指定"-g",则host4将无法通过访问host1:2222达到访问host2:80的目的。甚至,host1自身也不能使用172.16.10.5:2222,而只能使用localhost:2222或127.0.0.1:2222这样的方式达到访问host2:80的目的,之所以如此,是因为本地转发端口默认绑定在回环地址上。可以使用bind_addr来改变转发端口的绑定地址,例如:

    [root@xuexi ~]# ssh -L 172.16.10.5:2222:host2:80 host3

    这样,host1自身就能通过访问172.16.10.5:2222的方式达到访问host2:80的目的。

    一般来说,使用转发端口,都建议同时使用"-g"选项,否则将只有自身能访问转发端口。

    再来分析下转发端口通信的过程。

    当host4发起172.16.10.5:2222的连接时(即步骤①),数据包的目标地址和端口为"172.16.10.5:2222"。由于host1上ssh已经监听了2222端口,并且知道该端口映射自哪台主机哪个端口,所以将会把该数据包目标地址和端口替换为"172.16.10.3:80",并将此数据包通过转发给host3。当host3收到该数据包时,发现是host1转发过来请求访问host2:80的数据包,所以host3将代为访问host2的80端口。

    所以,host1和host3之间的通信方式是SSH协议,这段连接是安全加密的,因此称为"安全隧道",而host3和host2之间通信协议则是HTTP而不是ssh。

    现在再来考虑下,通过本地端口转发的方式如何实现ssh跳板的功能呢?仍以上图为例:

    [root@xuexi ~]# ssh -g -L 22333:host2:22 host3

    这样只需使用ssh连上host1的22333端口就等于连接了host2的22端口。

    甚至还可以在host3上执行:

    [root@xuexi ~]# ssh -L 172.16.10.5:22333:host2:80 host2
    
    或:
    
    [root@xuexi ~]# ssh -L 172.16.10.5:22333:host2:80 host3

    这样在host3就开启了一个转发端口22333供host1连接。当host1连接到host3:22333时,host3将转发给host2或host3自身,再由host2或host3自身与host2通信。

    最后,关于端口转发有一个需要注意的问题:ssh命令中带有要执行的命令。考虑了下面的三条在host1上执行的命令的区别。

    [root@xuexi ~]# ssh -g -L 22333:host2:22 host3
    
    [root@xuexi ~]# ssh -g -L 22333:host2:22 host3 "ifconfig"[root@xuexi ~]# ssh -g -L 22333:host2:22 host3 "sleep 10"

    第一条命令开启了本地端口转发,且是以登录到host3的方式开启的,所以执行完该命令后,将跳到host3主机上,当退出host3时,端口转发功能将被关闭。另外,host1上之所以要开启端口转发,目的是为了与host2进行通信,而不是跳到host3上,所以应该在ssh命令行上加上"-f"选项让ssh在本机host1上以后台方式提供端口转发功能,而不是跳到host3上来提供端口转发功能。

    第二条命令在开启本地转发的时候还指定了要在host3上执行"ifconfig"命令,但是ssh的工作机制是远程命令执行完毕的那一刻,ssh关闭连接,所以此命令开启的本地端口转发功能有效期只有执行ifconfig命令的一瞬间。

    第三条命令和第二条命令类似,只不过指定的是睡眠10秒命令,所以此命令开启的本地转发功能有效期只有10秒。

    结合上面的分析,开启端口转发功能时,建议让ssh以后台方式提供端口转发功能,且明确指示不要执行任何ssh命令行上的远程命令。即最佳开启方式为:

    [root@xuexi ~]# ssh -f -N -g -L 22333:host2:22 host3


    1.11.2 ssh安全隧道(二):远程端口转发

    ssh除了支持本地端口转发,还支持远程端口转发。顾名思义,远程端口转发表示的是将远程端口的数据转发到本地。

    如下图:假如host3是内网主机,它能和host2互相通信,也能和host1通信,但反过来,host1不能和host3通信。这时要让host1访问host3或host2就没办法通过本地端口转发了,因为要在host1上开启本地端口转发,必须要和host3通信请求建立隧道。

    可以通过在host3上发起远程端口转发来实现,因为host3能和host1通信,host3可以请求在host1和host3之间建立隧道。

    语法如下:

    ssh -R [bind_addr:]remote1_port:host:port remote1

    以上图为例,实现方式是在host3上执行:

    [root@xuexi ~]# ssh -R 22333:host2:80 host1

    这表示host3请求host1上的sshd服务,在host1上建立一个套接字监听22333端口,它是host2端口的映射,当有主机连接host1:22333时,此连接中的数据全部都通过host1和host3之间的安全隧道转发给host3,再由host3向host2的80端口发起访问。由于host3请求开启的转发端口是在远程主机host1上的,所以称为"远程端口转发"。

    再考虑下面这条命令所开启的远程转发端口,它是在host3上执行的。

    [root@xuexi ~]# ssh -R 22333:host3:80 host1

    该命令将自身的host3:80映射到host1:22333上,这也能让host1和host2、host3通信,因为隧道是建立在host1:2233371fb34173e4ee87dab1f85dc1c283a44host3:80上的。

    但是,远程端口转发和本地端口转发最大的一个区别是,远程转发端口是由host1上的sshd服务控制的,默认配置情况下,sshd服务只允许本地开启的远程转发端口(22333)绑定在环回地址(127.0.0.1),即使显式指定了bind_addr也无法覆盖。例如:

    [root@xuexi ~]# ssh -R *:22333:host2:80 host1
    
    [root@xuexi ~]# netstat -tnlp
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name  
    tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      8405/sshd          
    tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1422/master        
    tcp        0      0 127.0.0.1:22333             0.0.0.0:*                   LISTEN      8407/sshd          
    tcp        0      0 :::22                       :::*                        LISTEN      8405/sshd          
    tcp        0      0 ::1:25                      :::*                        LISTEN      1422/master         
    tcp        0      0 ::1:22333                   :::*                        LISTEN      8407/sshd

    要允许本地的远程转发端口绑定在非环回地址上,需要在host1的sshd配置文件中启用"GatewayPorts"项它的默认值为no。启动该选项后,不给定bind_addr或bind_addr设置为"*"都表示绑定在所有地址上。如下:

    [root@xuexi ~]# ssh -g -R *:22333:host2:80 host1
    
    [root@xuexi ~]# netstat -tnlp
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name  
    tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      8466/sshd          
    tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      1422/master        
    tcp        0      0 0.0.0.0:22333               0.0.0.0:*                   LISTEN      8468/sshd           
    tcp        0      0 :::22                       :::*                        LISTEN      8466/sshd          
    tcp        0      0 ::1:25                      :::*                        LISTEN      1422/master        
    tcp        0      0 :::22333                    :::*                        LISTEN      8468/sshd

    和前面的本地转发端口一样,建议的几个选项是:"-g"、"-f"、"-N"。即推荐的命令写法是:

    [root@xuexi ~]# ssh -fgN -R 22333:host2:80 host1

    现在,就可以通过访问host1:22333达到访问host2:80的目的了。如下图所示。

     

    1.11.3 ssh安全隧道(三):动态端口转发(SOCKS代理)

    无论是本地端口转发还是远程端口转发,都是将某固定主机及其端口映射到本地或远程转发端口上,例如将host2:80映射到host1:2222。也就是说,本地或远程转发端口和目标端口所代表的应用层协议是一对一的关系,2222端口必须对应的是http的80端口,使用浏览器向host1:2222端口发起http请求当然没问题,但是使用ssh工具向host1:2222发起连接将会被拒绝,因为host2上http服务只能解析http请求,不能解析ssh连接请求。

    ssh支持动态端口转发,由ssh来判断发起请求的工具使用的是什么应用层协议,然后根据判断出的协议结果决定目标端口。

    以下图为例进行说明,host1处在办公内网,能和host3互相通信,但它无法直接和互联网和host2通信,而host3则可以和host2以及互联网通信。

    要让host1访问互联网,又能和host2的22端口即ssh服务通信,显然在host1上仅设置一个本地端口转发是不够的,虽然可以设置多个本地转发端口分别映射不同的端口,但这显然比较笨重和麻烦。使用动态端口转发即可。

    语法格式为:

    ssh -D [bind_addr:]port remote

    以上图为例,在host1上执行:

    [root@xuexi ~]# ssh -Nfg -D 2222 host3

    위 명령을 실행한 후, 호스트1은 SOCKS4 또는 SOCKS5 서비스를 로컬로 시작하여 포트 2222를 수신합니다. 클라이언트 프로그램 도구(사용된 애플리케이션 계층 프로토콜 유형 암시)가 자체 프록시를 호스트1:2222로 설정하는 한, 프로그램에서 생성된 모든 데이터는 호스트1:2222로 전달된 다음 호스트1:2222가 데이터를 터널을 통해 호스트 3으로 전달되고, 최종적으로 호스트 3은 호스트 2의 클라이언트 도구에 해당하는 인터넷 또는 응용 계층 프로토콜의 포트와 통신합니다.

    실제로, 호스트4가 IE 브라우저를 클라이언트 도구로 사용하고 IE 브라우저의 프록시를 호스트1:2222로 설정하는 경우 IE 브라우저에서 시작된 요청은 http 프로토콜(여기에서는 다른 가능성은 고려되지 않음)을 사용하기 때문에 매우 간단합니다. ), 그러면 IE 브라우저에서 생성된 데이터가 호스트1:2222로 전달되고, 그런 다음 호스트1:2222가 터널을 통해 이를 호스트3으로 전달합니다. 따라서 호스트3은 인터넷에 연결할 수 있으므로 호스트4는 네트워킹 기능을 실현합니다. 설정은 아래와 같습니다:

    또 다른 예는 호스트4의 QQ 클라이언트가 프록시를 설정할 수도 있다는 것입니다. 이런 방식으로 QQ에서 생성된 데이터는 호스트1:2222를 통해 전달되고, 호스트1:2222는 QQ 데이터를 호스트3에 전달합니다. Host3는 이러한 데이터가 사용하는 프로토콜이 oicq라는 것을 알고 있으므로 호스트3은 Tencent의 QQ 서버에 연결됩니다( oicq 서비스 포트에 해당).

    ssh는 양말4 및 양말5 프록시만 지원합니다. 일부 클라이언트 도구는 프록시 유형을 명확하게 표시해야 합니다.

    로컬 및 원격 포트 포워딩과 마찬가지로 권장 옵션은 "-f", "-N" 및 "-g"입니다.

    Ssh 동적 포트 전달은 SSH 클라이언트의 기능이므로 SSH 명령을 사용하지 않고 SecurtCRT 및 Putty와 같은 SSH 클라이언트 도구를 사용하여 프록시 인터넷 액세스를 달성할 수 있습니다. 예를 들어 로컬 호스트가 인터넷에 액세스할 수 없지만 172.16.10.6의 SSH 서비스와 통신할 수 있고 172.16.10.6이 인터넷에 액세스할 수 있는 경우 먼저 SecurtCRT를 사용하여 로컬 호스트의 172.16.10.6에 연결할 수 있으며, 그런 다음 해당 세션 옵션에서 다음 설정을 지정하면 로컬 호스트도 인터넷에 액세스할 수 있습니다. (참고: FQ를 할 수 있다고 말하지 않았는데 선량한 시민은 FQ를 하지 않습니다!!!)

    그런 다음 SecurtCRT에 지정된 8888 동적 전달 포트가 모니터링되는지 로컬 호스트에서 확인하세요.

    이제 이 기계의 모든 데이터 패킷은 SecurtCRT에 연결된 172.16.10.6을 통해 외부 세계로 흐릅니다.

위 내용은 SSH 및 SSH 서비스에 대한 기본 소개(터널 콘텐츠 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.