版权 © 2011, 2012 http://netkiller.github.com
摘要
Linux 系统安全问题
下面是我多年积累下来的经验总结,整理成文档供大家参考:
目录
1. 帐号安全1.1. Shell 安全1.2. .history 文件2. 数据库安全2.1. 数据库客户端安全2.1.1. mysql 管理2.1.2. ~/.mysql_history2.2. mysqldump 安全2.2.1. 数据备份2.2.2. 数据恢复2.3. 数据库归档文件2.4. 开发与测试环境的数据库安全问题3. 其他安全问题3.1. 与数据库有关的服务器安全问题帐号权限安全
需求:限制用户权限,仅提供一些linux常用命令,用户监控linux系统于网络运行情况,不允许用户ssh登录后随意运行linux命令
-
用户不能进入到Shell环境
例如普通用户一旦登录web服务器可以看到web程序中的数据库配置
-
用户可以了解OS工作状态如内存,cpu,网络等等
例如:ping, tracepath, top, free, netstat
-
可以查看系统部分日志
例如:access.log, error.log, php-error.log ...
使用mgmt替代bash
#!/bin/bash TITLE="Client" #USER=$(whiptail --inputbox "User:" 8 60 --title "$TITLE" 3>&1 1>&2 2>&3) #PASSWD=$(whiptail --title "$TITLE" --passwordbox "Passsword:" 8 60 3>&1 1>&2 2>&3) COMMAND=$(whiptail --title "$TITLE" --menu "Administrator Tools" 22 50 10 \ "ping" "ping" \ "tracepath" "tracepath" \ "top" "top" \ "free" "free" \ "ps" "ps" \ "netstat" "netstat" \ "lsof" "lsof" \ "iftop" "iftop" \ "log" "log" \ 3>&1 1>&2 2>&3) function option(){ OPTION=$(whiptail --inputbox "COMMAND-LINE Options: " 8 60 --title "$TITLE" 3>&1 1>&2 2>&3) } function weblog(){ LOG=$(whiptail --title "$TITLE" --menu "Logs" 22 50 8 \ "/var/log/messages" "message" \ "/var/log/syslog" "syslog" \ "/var/log/nginx/access.log" "access.log" \ "/var/log/nginx/error.log" "error.log" \ 3>&1 1>&2 2>&3) } case $COMMAND in ping) option $COMMAND $OPTION ;; tracepath) option $COMMAND $OPTION ;; free) $COMMAND -m read ;; top|iftop) $COMMAND ;; log) weblog tail -f $LOG ;; ps|lsof) option $COMMAND $OPTION read ;; netstat) option $COMMAND $OPTION read ;; *) exit $? esac
Shell 启动文件,主要用户隐藏 /srv/sbin/mgmt 文件(针对菜鸟)
$ cat shell.c #include <stdlib.h> main() { for (;;){ system("/srv/sbin/mgmt"); } }
编译.c文件
gcc shell.c -o /bin/nsh
添加Shell到/etc/shells
echo /bin/nsh >> /etc/shells
将用户shell更改为我们刚刚创建的nsh
$ vim /etc/passwd www:x:33:33:www:/var/www:/bin/nsh
现在来作一个测试,如果正确应该现在为下面的TUI界面
ssh www@example.com ┌───────────────────┤ Client ├───────────────────┐ │ Administrator Tools │ │ │ │ ping ping │ │ tracepath tracepath │ │ top top │ │ free free │ │ ps ps │ │ netstat netstat │ │ lsof lsof │ │ iftop iftop │ │ log log │ │ │ │ │ │ <Ok> <Cancel> │ │ │ └────────────────────────────────────────────────┘
提示
这里采用的方式是给用户提供一个界面的方式,另外还有更好的方案,你可以些一个Shell的外壳,你需要实现
-
与Shell相同的提示符
-
提供TAB补齐
-
上下光标键翻看历史命令,左右光标改变位置,Home/End 键到行首与行尾
-
Ctrl+R 搜索, Ctrl+D 退出
-
Ctrl+S,Ctrl+Q 等等
流程
用户输入 -> 关键字过滤 -> 放行
例如用户输入 cd / 经过过滤器后, cd /home/usr/
例如用户输入 cd /aaa 经过过滤器后, cd /home/usr/aaa
rm -rf /usr/local 提示拒绝等等
我已经使用Python实现上面的大部分功能(因为python受到很多限制)如果使用C可以100%实现,需要你的想想力了
SA的操作记录问题
通过~/.bash_history文件记录系统管理员的操作记录,定制.bash_history格式
HISTSIZE=1000 HISTFILESIZE=2000 HISTTIMEFORMAT="%Y-%m-%d-%H:%M:%S " export HISTTIMEFORMAT
看看实际效果
$ history | head 1 2012-02-27-09:10:45 do-release-upgrade 2 2012-02-27-09:10:45 vim /etc/network/interfaces 3 2012-02-27-09:10:45 vi /etc/network/interfaces 4 2012-02-27-09:10:45 ping www.163.com
我们以MySQL为例,讲解怎样控制DBA权限。稍加修改即可用于oracle等服务器
-
DBA 没有系统SSH帐号,只有数据库帐号
-
系统管理员只能有SSH系统帐号,没有数据库帐号
-
DBA 可备份数据库,还原数据库指定的备份文件,但是接触不到备份文件
-
DBA 有权重启数据库以及修复损坏库/表文件,通过工具完成,而不是登录SSH运行命令
DBA不需要通过SSH登录数据库服务器,然后运行mysql/sqlplus在登录数据库
$ cat ../database/mysqltui #!/bin/bash TITLE="MySQL Client" HOST=$(whiptail --title "$TITLE" --menu "MySQL Host" 22 50 8 \ "127.0.0.1" "localhost" \ "172.16.0.1" "MySQL Master" \ "172.16.0.2" "MySQL Slave 1" \ "172.16.0.3" "MySQL Slave 2" \ 3>&1 1>&2 2>&3) USER=$(whiptail --inputbox "MySQL User:" 8 60 --title "$TITLE" 3>&1 1>&2 2>&3) PASSWD=$(whiptail --title "$TITLE" --passwordbox "MySQL Password:" 8 60 3>&1 1>&2 2>&3) #DATABASE=$(mysqlshow -h$HOST -u$USER | egrep -o "|\w(.*)\w|" | grep -v "Databases" |awk '{print "\""$1"\" \""$1"\""}') #DATABASE=$(mysqlshow -h$HOST -u$USER | egrep -o "|\w(.*)\w|" | grep -v "Databases" |awk "{print \"$1\" \"$1\"}") #DB=$(whiptail --title "$TITLE" --menu "MySQL DATABASE" 22 50 8 $DATABASE 3>&1 1>&2 2>&3) DATABASE=$(whiptail --inputbox "MySQL Database:" 8 60 --title "$TITLE" 3>&1 1>&2 2>&3) echo $HOST $USER $PASSWD $DATABASE mysql -h$HOST -u$USER -p$PASSWD $DATABASE
┌───┤ MySQL Adminstrator ├───┐ │ Menu │ │ │ │ 1 MySQL Manager │ │ 2 MySQL Backup │ │ 2 MySQL Restore │ │ │ │ │ │ <Ok> <Cancel> │ │ │ └────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ Database Host │ │ │ │ 127.0.0.1 localhost │ │ 172.16.0.1 mysql master │ │ 172.16.0.2 mysql slave │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
/etc/php5/fpm/pool.d/www.conf
┌────────┤ MySQL Adminstrator ├────────┐ │ User │ │ │ │ root________________________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘ ┌────────┤ MySQL Adminstrator ├────────┐ │ Password │ │ │ │ ****________________________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
进入mysql客户端
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 503 Server version: 5.1.58-1ubuntu1 (Ubuntu) Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. This software comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to modify and redistribute it under the GPL v2 license Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
安全提示
-
从安全角度看,你可以去掉输入密码的过程。在终端提示符下输入
Enter password:
-
还可以写入~/.my.conf文件
这样ssh mysql@example.com的时候输入第一道密码,然后进入mysql不需要输入密码
-
如果需要输入密码对话到建议删除.bash_history
rm -rf .bash_history
ln -s /dev/null .bash_history
通过~/.mysql_history文件记录DBA操作记录
插入时间点,在~/.bashrc中加入下面命令
cat >> ~/.bashrc <<EODdd echo `date` >> ~/.mysql_dhistory EOD
$ tail ~/.bashrc echo `date` >> ~/.mysql_history
查看实际效果
$ tail ~/.mysql_history EXPLAIN SELECT * FROM stuff where id=3 \G EXPLAIN SELECT * FROM stuff where id='3' \G EXPLAIN SELECT * FROM stuff where id='2' \G Mon Feb 27 09:15:18 CST 2012 EXPLAIN SELECT * FROM stuff where id='2' and created = '2012-02-01' \G EXPLAIN SELECT * FROM stuff where id='1' and created = '2012-02-01' \G EXPLAIN SELECT * FROM stuff where id='3' and created = '2012-02-01' \G EXPLAIN SELECT * FROM stuff where id='2' and created = '2012-02-01' \G EXPLAIN SELECT * FROM stuff where id='2' or created = '2012-02-01' \G EXPLAIN SELECT * FROM stuff where id='2' and created = '2012-02-01' \G Mon Feb 27 11:48:37 CST 2012
MySQL Client ┌───┤ MySQL Adminstrator ├───┐ │ Menu │ │ │ │ 1 MySQL Manager │ │ 2 MySQL Backup │ │ 2 MySQL Restore │ │ │ │ │ │ <Ok> <Cancel> │ │ │ └────────────────────────────┘
MySQL Client ┌────────┤ MySQL Adminstrator ├────────┐ │ Database Host │ │ │ │ 127.0.0.1 localhost │ │ 172.16.0.1 mysql master │ │ 172.16.0.2 mysql slave │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ User │ │ │ │ root________________________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘ ┌────────┤ MySQL Adminstrator ├────────┐ │ Password │ │ │ │ ****________________________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ Backup File Name │ │ │ │ 2010-12-12.01:00:00_________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ │ │ Backup? │ │ │ │ │ │ <Yes> <No> │ │ │ └──────────────────────────────────────┘
MySQL Client ┌───┤ MySQL Adminstrator ├───┐ │ Menu │ │ │ │ 1 MySQL Manager │ │ 2 MySQL Backup │ │ 2 MySQL Restore │ │ │ │ │ │ <Ok> <Cancel> │ │ │ └────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ Database Host │ │ │ │ 127.0.0.1 localhost │ │ 172.16.0.1 mysql master │ │ 172.16.0.2 mysql slave │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ Backup History │ │ │ │ 1 2010-12-03 03:00:00 │ │ 2 2012-01-01 02:00:00 │ │ 3 2012-02-01 02:00:00 │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ User │ │ │ │ root________________________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘ ┌────────┤ MySQL Adminstrator ├────────┐ │ Password │ │ │ │ ****________________________________ │ │ │ │ <Ok> <Cancel> │ │ │ └──────────────────────────────────────┘
┌────────┤ MySQL Adminstrator ├────────┐ │ │ │ Restore? │ │ │ │ │ │ <Yes> <No> │ │ │ └──────────────────────────────────────┘
一般数据库服务器上可以保留一周的备份数据,历史数据需要保存到服务器以外的带库或者阵列柜中,怎么样保证这些数据的安全呢? 我们采用下面方式
-
制作PGP/GPG密钥,密钥放置在数据库服务器上,证书做好备份,否则一旦丢失,将无法在将备份文件恢复
-
数据库备份后,首先进行压缩处理
-
然后使用公钥证书进行GPG/PGP数据加密
-
这时可以放心的将备份数据库搬出数据库服务器到带库或磁盘阵列柜中
恢复数据,将数据库备份文件复制到该数据库服务器,然后用私钥解密备份文件,再恢复到数据库到中
其他服务器不能安装mysql客户端与mysqldump备份工具
例如:web服务器只能通过php/jdbc/odbc等链接mysql数据库 web服务器卸载 mysql,mysqldump工具,防止用户登录查询以及将数据库远程备份,然后通过web下载数据库
同时*22等端口,避免相互跳转
lokkit --enabled iptables -F iptables -A OUTPUT -p tcp -m multiport --dports 22,21,2049 -j REJECT /etc/init.d/iptables save iptables -L -n
web 服务器禁止使用ssh,作为跳板机