SSH 的一些安全小技巧

出自sebug security vulnerability(SSV) DB
跳转到: 导航, 搜索

SSH 的一些安全小技巧


目录

前言

关于 ssh 的好处, 相信不用我多说了吧? 簡而言之, 之前的 rpc command 于 telnet 都全可用 ssh 代替. 比方如下的這些常見功能:

- 远程登录
	ssh user@remote.machine
- 远程执行
	ssh user@remote.machine 'command ...'
- 远程复制
	scp user@remote.machine:/remote/path /local/path
	scp /local/path user@remote.machine:/remote/path
- X forward
	ssh -X user@remote.machine
	xcommand ...
- Tunnel / Portforward
	ssh -L 1234:remote.machine:4321 user@remote.machine
	ssh -R 1234:local.machine:4321 user@remote.machine
	ssh -L 1234:other.machine:4321 user@remote.machine

至於详细的用法, 我這就不說了. 请读者自行研究吧.

我这里要说的, 是针对 ssh 服务为大家介绍一些安全技巧, 希望大家用得更安心些


实例

(以 RedHat 9 为例)

轉往 client 端:
$ ssh-keygen -t rsa
* 按三下 enter 完成﹔不需設密碼,除非您會用 ssh-agent .
$ scp ~/.ssh/id_rsa.pub user1@server.machine:id_rsa.pub
* 若是 windows client, 可用 puttygen.exe 產生 public key, 
   然後複制到 server 端後修改之, 使其內容成為單一一行.
* 如果 server 端已經禁止密碼登入, 那請用其它放法復製 publick key.

登入 server 端:

  1. # vi /etc/ssh/sshd_config
  2. 	PermitRootLogin no
  1. # vi /etc/ssh/sshd_config
  2. 	RSAAuthentication yes
  3. 	PubkeyAuthentication yes
  4. 	AuthorizedKeysFile     .ssh/authorized_keys
  5. 	PasswordAuthentication no
  6. # service sshd restart
  7. # su - user1
  8. $ mkdir ~/.ssh 2>/dev/null
  9. $ chmod 700 ~/.ssh
  10. $ touch ~/.ssh/authorized_keys
  11. $ chmod 644 ~/.ssh/authorized_keys
  12. $ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
  13. $ rm ~/id_rsa.pub
  14. $ exit
  1. # vi /etc/pam.d/su
  2. 	auth       required     /lib/security/$ISA/pam_wheel.so use_uid
  3. # visudo
  4. 	%wheel  ALL=(ALL)       ALL
  5. # gpasswd -a user1 wheel
  1. # vi /etc/pam.d/sshd
  2. 	auth       required     pam_listfile.so item=user sense=allow file=/etc/ssh_users onerr=fail
  3. # echo user1 >> /etc/ssh_users
  1. # iptables -I INPUT -p tcp --dport 22 -j DROP
  2. # mkdir /var/www/html/ssh_open
  3. # cat > /var/www/html/ssh_open/.htaccess <<END
  4. AuthName "ssh_open"
  5. AuthUserFile /var/www/html/ssh_open/.htpasswd
  6. AuthType basic
  7. require valid-user
  8. END
  9. # htpasswd -c /var/www/html/ssh_open/.htpasswd user1

(最好還將 SSL 設起來, 或只限 https 連線更佳, 我這裡略過 SSL 設定, 請讀者自補.) (如需控制連線來源, 那請再補 Allow/Deny 項目, 也請讀者自補.)

  1. # cat > /var/www/html/ssh_open/ssh_open.php <<END
  2. <?
  3. //Set dir path for ip list
  4. $dir_path=".";
  5.  
  6. //Set filename for ip list
  7. $ip_list="ssh_open.txt";
  8.  
  9. //Get client ip
  10. $user_ip=$_SERVER['REMOTE_ADDR'];
  11.  
  12. //allow specifying ip if needed
  13. if (@$_GET['myip']) {
  14. $user_ip=$_GET['myip'];
  15. }
  16.  
  17. //checking IP format
  18. if ($user_ip==long2ip(ip2long($user_ip))) {
  19.  
  20. //Put client ip to a file
  21. if(@!($file = fopen("$dir_path/$ip_list","w+")))
  22. {
  23.         echo "Permission denied!!<br>";
  24.         echo "Pls Check your rights to dir $dir_path or file $ip_list";
  25. }
  26. else
  27. {
  28.         fputs($file,"$user_ip");
  29.         fclose($file);
  30.         echo "client ip($user_ip) has put into $dir_path/$ip_list";
  31. }
  32. } else {
  33. echo "Invalid IP format!!<br>ssh_open.txt was not changed.";
  34. }
  35. ?>
  1. END
  2. # touch /var/www/html/ssh_open/ssh_open.txt
  3. # chmod 640 /var/www/html/ssh_open/*
  4. # chgrp apache /var/www/html/ssh_open/*
  5. # chmod g+w /var/www/html/ssh_open/ssh_open.txt
  6. # chmod o+t /var/www/html/ssh_open
  7. # service httpd restart
  8. # mkdir /etc/iptables
  9. # cat > /etc/iptables/sshopen.sh <<END
  10. #!/bin/bash
  11.  
  12. PATH=/sbin:/bin:/usr/sbin:/usr/bin
  13.  
  14. list_dir=/var/www/html/ssh_open
  15. list_file=$list_dir/allow_ssh.txt
  16. bad_list=$list_dir/bad_ip.txt
  17. auth_log=$list_dir/xinetd.log
  18. trusted_ip="127.0.0.1 4.3.2.1"
  19. chain_name=ssh_rules
  20.  
  21. mail_to=root
  22.  
  23. # clear chain if exits, or create chain.
  24. iptables -L -n | /bin/grep -q "^Chain $chain_name" && {
  25.         iptables -F $chain_name
  26.         true
  27. } || {
  28.         iptables -N $chain_name
  29.         iptables -I INPUT -p tcp --dport 22 -j $chain_name
  30. }
  31.  
  32. # clear chain on demand
  33. [ "$1" = clear ] && {
  34.         iptables -F $chain_name
  35. 	cat /dev/null > $list_file
  36.         exit 0
  37. }
  38.  
  39. # do nothing while list is empty
  40. [ -s $list_file ] || exit 1
  41.  
  42. # deny connection if host dosn't math to list
  43. host_ip=$(grep 'myssh from=' $auth_log | tail -1 | awk -F'=' '{print $NF}')
  44. list_ip=$(cat $list_file)
  45. if [ -n "$host_ip" -a "$host_ip" != "$list_ip" ]; then
  46.     echo -e "${trusted_ip/ /\n}" | grep -q "$host_ip" || {
  47.         /sbin/iptables-save | grep -q "INPUT -s $host_IP -j DROP$" || {
  48.                 /sbin/iptables -I INPUT -s $host_ip -j DROP
  49.                 echo $host_ip >> $bad_list
  50.                 echo "$host_ip is blocked by $0 on $(date)" | mail -s "block 
  51. ip" $mail_to
  52.         }
  53.     }
  54.     exit 2
  55. fi
  56.  
  57. # add rule
  58. iptables -A $chain_name -p tcp --dport 22 -s $(< $list_file) -j ACCEPT && \
  59. 	echo "ssh opened to $(< $list_file) on $(date)" | \
  60. 	mail -s "sshopen" $mail_to
  61. exit 0
  62. END
  63. # chmod +x /etc/iptables/sshopen.sh
  64. # echo -e 'sshopen\t\t1234/tcp' >> /etc/services
  65. # cat > /etc/xinetd.d/sshopen <<END
  66. service sshopen
  67. {
  68.         log_type        = FILE /studyarea/www/phorum/xinetd.log
  69.         log_on_success  = HOST
  70.         log_on_failure  = HOST
  71.         disable = no
  72.         socket_type     = stream
  73.         protocol        = tcp
  74.         wait            = no
  75.         user            = root
  76.         server          = /etc/iptables/sshopen.sh
  77. }
  78. # iptables -I INPUT -p tcp --dport 1234 -j ACCEPT
  79. # cat > /etc/cron.d/sshopen <<END
  80. */5 * * * *     root    /etc/iptables/sshopen.sh clear
  81. END
轉往 client 端
在 browser URL 輸入:
	http://server.machine/ssh_open/ssh_open.php?myip=1.2.3.4
(若不指定 ?myip=1.2.3.4 則以 client 當時 IP 為準, 若沒經 proxy 的話.)
如此, server 端的 ssh_open.txt 只有單一記錄, 每次蓋寫. 
接著:
	$ telnet server.machine 1234
然後你有最多 5 分鐘時間用 ssh 連線 server !

此步驟的基本構思如下:


  1. # cat > /etc/iptables/sshblock.sh <<END
  2. #!/bin/bash 
  3.  
  4. PATH=/sbin:/bin:/usr/sbin:/usr/bin 
  5.  
  6. LOG_FILE=/var/log/secure 
  7. KEY_WORD="Illegal user" 
  8. KEY_WORD1="Failed password for root" 
  9. PERM_LIST=/etc/firewall/bad.list.perm 
  10. LIMIT=5 
  11. MAIL_TO=root 
  12. IPT_SAV="$(iptables-save)" 
  13. bad_list=$(egrep "$KEY_WORD" $LOG_FILE | awk '{print $NF}' | xargs) 
  14. bad_list1=$(egrep "$KEY_WORD1" $LOG_FILE | awk '{print $11}' | xargs) 
  15. bad_list="$bad_list $bad_list1" 
  16.  
  17. for i in $(echo -e "${bad_list// /\n}" | sort -u) 
  18. do 
  19.         hit=$(echo $bad_list | egrep -o "$i" | wc -l) 
  20.         [ "$hit" -ge "$LIMIT" ] && { 
  21.                 echo "$IPT_SAV" | grep -q "$i .*-j DROP" || { 
  22.                         echo -e "\n$i was dropped on $(date)\n" | mail -s "DROP by ${0##*/}: $i" $MAIL_TO 
  23.                         iptables -I INPUT -s $i -j DROP 
  24.                 } 
  25.                 egrep -q "^$i$" $PERM_LIST || echo $i >> $PERM_LIST 
  26.         } 
  27. done
  28. END
  29. # chmod +x /etc/firewall/sshblock.sh
  30. # cat >> /etc/hosts.allow <<END
  31. sshd: ALL: spawn ( /etc/firewall/sshblock.sh )& : ALLOW
  32. END

這樣, 那些亂 try SSH 的家夥, 頂多能試 5 次(LIMIT 可調整), 然後就給 BLOCK 掉了. 此外, 在 PERM_LIST 的 ip, 也可提供給 iptables 的初始 script , 來個永久性封閉:

  1. for i in $(< $PERM_LIST) 
  2. do 
  3. 	/sbin/iptables -I INPUT -s $i -j DROP 
  4. done
  1. # iptables -I INPUT -p tcp --dport 79 -j ACCEPT 
  2. cat > /etc/xinetd.d/finger <<END
  3. service finger 
  4. { 
  5.         socket_type     = stream 
  6.         wait            = no 
  7.         user            = nobody 
  8.         server          = /usr/sbin/in.fingerd 
  9.         disable         = no 
  10. } 
  11. END 
  12. # cat >> /etc/hosts.allow <<END
  13. in.fingerd: ALL : spawn ( echo -e "\nWARNING %a was trying finger.\n$(date)" | mail -s "finger from %a" root ) & : DENY 
  14. END

這裡, 我只是設為發信給 root.

事實上, 你可修改為起動 firewall 將 %a 這個傳回值給 ban 掉也行.

不過, 對方要是有選擇性的做 port scan , 沒掃到 finger 的話, 那當然就沒用了...


总结

security 有蠻多挺好玩的小技巧, 有空再跟大家做分享... ^_^


参考


版本:v0.03
日期:2007-11-26
netman@study-area.org

* 版本歷程:
1) 2005-09-16 v0.01
	- 初版
2) 2006-06-02 v0.02
	- 修改 sshopen.sh 
3) 2007-11-26 v0.03
	- deny unmatched ip
个人工具
名字空间
变换
导航
工具箱