Some security tips for SSH in CentOS
Preface
I don't need to talk about the benefits of ssh? For example, the previous rpc commands can be replaced by ssh in telnet:
-Remote Logon
ssh user@remote.machine
-Remote Execution
ssh user@remote.machine 'command ...'
-Remote replication
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
For detailed usage, I will not talk about it. Please study it on your own.
I want to talk about some security skills for the ssh service.
Instance
(Take RedHat 9 as an example)
Publish to client:
$ ssh-keygen -t rsa
* You do not need to set a password when you press enter three times, unless you use ssh-agent.
$ scp ~/.ssh/id_rsa.pub user1@server.machine:id_rsa.pub
* If it is a windows client, puttygen.exe can be used to generate a public key,
Then modify it after writing the code to the server to make the content a single line.
* If the server has disabled Password Logon, use other methods to encrypt the publick key.
Log on to the server:
Disable root Login
# vi /etc/ssh/sshd_config
PermitRootLogin no
In addition to password authentication, the token forces the use of the RSA certificate (false ssh authentication as user1)
# vi /etc/ssh/sshd_config
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication no
# service sshd restart
# su - user1
$ mkdir ~/.ssh 2>/dev/null
$ chmod 700 ~/.ssh
$ touch ~/.ssh/authorized_keys
$ chmod 644 ~/.ssh/authorized_keys
$ cat ~/id_rsa.pub >> ~/.ssh/authorized_keys
$ rm ~/id_rsa.pub
$ exit
Restrict su/sudo names:
# vi /etc/pam.d/su
auth required /lib/security/$ISA/pam_wheel.so use_uid
# visudo
%wheel ALL=(ALL) ALL
# gpasswd -a user1 wheel
Restrict ssh user names
# vi /etc/pam.d/sshd
auth required pam_listfile.so item=user sense=allow file=/etc/ssh_users onerr=fail
# echo user1 >> /etc/ssh_users
Use the web control tool to clear the login ssh authentication ticket.
# iptables -I INPUT -p tcp --dport 22 -j DROP
# mkdir /var/www/html/ssh_open
# cat > /var/www/html/ssh_open/.htaccess <<END
AuthName "ssh_open"
AuthUserFile /var/www/html/ssh_open/.htpasswd
AuthType basic
require valid-user
END
# htpasswd -c /var/www/html/ssh_open/.htpasswd user1
(It is better to set up SSL, or set it only for https protocol. I have set it for SSL. Please refer to the setting here .) (If you need to control the source region, please refer to the Allow/Deny category, or the author's self-contained .)
# cat > /var/www/html/ssh_open/ssh_open.php <<END
<?
//Set dir path for ip list
$dir_path=".";
//Set filename for ip list
$ip_list="ssh_open.txt";
//Get client ip
$user_ip=$_SERVER['REMOTE_ADDR'];
//allow specifying ip if needed
if (@$_GET['myip']) {
$user_ip=$_GET['myip'];
}
//checking IP format
if ($user_ip==long2ip(ip2long($user_ip))) {
//Put client ip to a file
if(@!($file = fopen("$dir_path/$ip_list","w+")))
{
echo "Permission denied!!<br>";
echo "Pls Check your rights to dir $dir_path or file $ip_list";
}
else
{
fputs($file,"$user_ip");
fclose($file);
echo "client ip($user_ip) has put into $dir_path/$ip_list";
}
} else {
echo "Invalid IP format!!<br>ssh_open.txt was not changed.";
}
?>
END
# touch /var/www/html/ssh_open/ssh_open.txt
# chmod 640 /var/www/html/ssh_open/*
# chgrp apache /var/www/html/ssh_open/*
# chmod g+w /var/www/html/ssh_open/ssh_open.txt
# chmod o+t /var/www/html/ssh_open
# service httpd restart
# mkdir /etc/iptables
# cat > /etc/iptables/sshopen.sh <<END
#!/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
list_dir=/var/www/html/ssh_open
list_file=$list_dir/allow_ssh.txt
bad_list=$list_dir/bad_ip.txt
auth_log=$list_dir/xinetd.log
trusted_ip="127.0.0.1 4.3.2.1"
chain_name=ssh_rules
mail_to=root
# clear chain if exits, or create chain.
iptables -L -n | /bin/grep -q "^Chain $chain_name" && {
iptables -F $chain_name
true
} || {
iptables -N $chain_name
iptables -I INPUT -p tcp --dport 22 -j $chain_name
}
# clear chain on demand
[ "$1" = clear ] && {
iptables -F $chain_name
cat /dev/null > $list_file
exit 0
}
# do nothing while list is empty
[ -s $list_file ] || exit 1
# deny connection if host dosn't math to list
host_ip=$(grep 'myssh from=' $auth_log | tail -1 | awk -F'=' '{print $NF}')
list_ip=$(cat $list_file)
if [ -n "$host_ip" -a "$host_ip" != "$list_ip" ]; then
echo -e "${trusted_ip/ /\n}" | grep -q "$host_ip" || {
/sbin/iptables-save | grep -q "INPUT -s $host_IP -j DROP$" || {
/sbin/iptables -I INPUT -s $host_ip -j DROP
echo $host_ip >> $bad_list
echo "$host_ip is blocked by $0 on $(date)" | mail -s "block
ip" $mail_to
}
}
exit 2
fi
# add rule
iptables -A $chain_name -p tcp --dport 22 -s $(< $list_file) -j ACCEPT && \
echo "ssh opened to $(< $list_file) on $(date)" | \
mail -s "sshopen" $mail_to
exit 0
END
# chmod +x /etc/iptables/sshopen.sh
# echo -e 'sshopen\t\t1234/tcp' >> /etc/services
# cat > /etc/xinetd.d/sshopen <<END
service sshopen
{
log_type = FILE /studyarea/www/phorum/xinetd.log
log_on_success = HOST
log_on_failure = HOST
disable = no
socket_type = stream
protocol = tcp
wait = no
user = root
server = /etc/iptables/sshopen.sh
}
# iptables -I INPUT -p tcp --dport 1234 -j ACCEPT
# cat > /etc/cron.d/sshopen <<END
*/5 * * * * root /etc/iptables/sshopen.sh clear
END
Publish to client
In browser URL merge:
http://server.machine/ssh_open/ssh_open.php?myip=1.2.3.4
(If not specified? Myip = 1.2.3.4 is based on the client's IP address at that time. If no proxy is available .)
In this way, the ssh_open.txt on the server only has a single record, and each time the record is sent.
Next:
$ telnet server.machine 1234
Then you have a maximum of five minutes using ssh to connect to the server!
The basic structure of this step is as follows:
Block all firewall blocks of sshd.
-
- Then, set a directory in httpd, set ssl + htpasswd + allow/deny control, and then upload a php file to record the browser ip address. txt text. depending on your browser capabilities, you can manually capture the IP address of the browser, or allow the browser terminal to import data to specify. only one record is displayed for the text watermark, Which is cleared regularly each time.
-
- Modify/etc/services, add a new category (such as xxx), and specify a new port (such as 1234)
-
- Use the xinetd script to listen to the port and run a script to configure iptables. Then, obtain the IP address from the checklist in step 2 and enable ssh authentication.
-
- Set crontab to clean up iptables rules related to ssh route entries and clear the records in each score. this does not mean that there are already two operators. If the time exceeds the limit, the above will be repeated.
If this parameter is not set in the previous step, you may be tempted to try your ssh Server:
# cat > /etc/iptables/sshblock.sh <<END
#!/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
LOG_FILE=/var/log/secure
KEY_WORD="Illegal user"
KEY_WORD1="Failed password for root"
PERM_LIST=/etc/firewall/bad.list.perm
LIMIT=5
MAIL_TO=root
IPT_SAV="$(iptables-save)"
bad_list=$(egrep "$KEY_WORD" $LOG_FILE | awk '{print $NF}' | xargs)
bad_list1=$(egrep "$KEY_WORD1" $LOG_FILE | awk '{print $11}' | xargs)
bad_list="$bad_list $bad_list1"
for i in $(echo -e "${bad_list// /\n}" | sort -u)
do
hit=$(echo $bad_list | egrep -o "$i" | wc -l)
[ "$hit" -ge "$LIMIT" ] && {
echo "$IPT_SAV" | grep -q "$i .*-j DROP" || {
echo -e "\n$i was dropped on $(date)\n" | mail -s "DROP by ${0##*/}: $i" $MAIL_TO
iptables -I INPUT -s $i -j DROP
}
egrep -q "^$i$" $PERM_LIST || echo $i >> $PERM_LIST
}
done
END
# chmod +x /etc/firewall/sshblock.sh
# cat >> /etc/hosts.allow <<END
sshd: ALL: spawn ( /etc/firewall/sshblock.sh )& : ALLOW
END
In this way, the guys who try SSH can initiate a maximum of five LIMIT requests, and then BLOCK the requests. in addition, the ip address in PERM_LIST can also be provided to the initial script of iptables to generate a permanent token:
for i in $(< $PERM_LIST)
do
/sbin/iptables -I INPUT -s $i -j DROP
done
Here, I just set it to send to root.
In fact, you can modify it to trigger firewall to return the value of % a to ban.
However, if the peer has a selective port scan and does not reach finger, then it is useless...