月份:2017年7月


SSL工作原理


(1) 浏览器发送一个https的请求给服务器;

(2) 服务器要有一套数字证书,可以自己制作(但使用自己制作的证书,浏览器访问的时候会提示不信任),也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥;

(3) 服务器会把公钥传输给客户端;

(4) 客户端(浏览器)收到公钥后,会验证其是否合法有效,无效会有警告提醒,有效则会生成一串随机数,并用收到的公钥加密;

(5) 客户端把加密后的随机字符串传输给服务器;

(6) 服务器收到加密随机字符串后,先用私钥解密(公钥加密,私钥解密),获取到这一串随机数后,再用这串随机字符串加密传输的数据(该加密为对称加密,所谓对称加密,就是将数据和私钥也就是这个随机字符串通过某种算法混合在一起,这样除非知道私钥,否则无法获取数据内容);

(7) 服务器把加密后的数据传输给客户端;

(8) 客户端收到数据后,再用自己的私钥也就是那个随机字符串解密;

shell习题-监控磁盘使用率


写一个shell脚本,检测所有磁盘分区使用率和inode使用率并记录到以当天日期为命名的日志文件里,当发现某个分区容量或者inode使用量大于85%时,发邮件通知你自己。

思路:就是先df -h 然后过滤出已使用的那一列,然后再想办法过滤出百分比的整数部分,然后和85去比较,同理,inode也是一样的思路。

 

参考答案:

#!/bin/bash
## This script is for record Filesystem Use%,IUse% everyday and send alert mail when % is more than 85%.

log=/var/log/disk/`date +%F`.log
date +'%F %T' > $log
df -h >> $log
echo >> $log
df -i >> $log

for i in `df -h|grep -v 'Use%'|sed 's/%//'|awk '{print $5}'`; do
    if [ $i -gt 85 ]; then
        use=`df -h|grep -v 'Use%'|sed 's/%//'|awk '$5=='$i' {print $1,$5}'`
        echo "$use" >> use
    fi
done
if [ -e use ]; then

   ##这里可以使用咱们之前介绍的mail.py发邮件
    mail -s "Filesystem Use% check" root@localhost < use
    rm -rf use
fi

for j in `df -i|grep -v 'IUse%'|sed 's/%//'|awk '{print $5}'`; do
    if [ $j -gt 85 ]; then
        iuse=`df -i|grep -v 'IUse%'|sed 's/%//'|awk '$5=='$j' {print $1,$5}'`
        echo "$iuse" >> iuse
    fi
done
if [ -e iuse ]; then
    mail -s "Filesystem IUse% check" root@localhost < iuse
    rm -rf iuse
fi

思路:
1、df -h、df -i 记录磁盘分区使用率和inode使用率,date +%F 日志名格式
2、取出使用率(第5列)百分比序列,for循环逐一与85比较,大于85则记录到新文件里,当for循环结束后,汇总超过85的一并发送邮件(邮箱服务因未搭建,发送本地root账户)。

此脚本正确运行前提:

该系统没有逻辑卷的情况下使用,因为逻辑卷df -h、df -i 时,使用率百分比是在第4列,而不是第5列。如有逻辑卷,则会漏统计逻辑卷使用情况。

shell习题-统计普通用户


写个shell,看看你的Linux系统中是否有自定义用户(普通用户),若是有,一共有几个?

 

参考答案:

假设所有普通用户都是uid大于1000的

#!/bin/bash
 n=`awk -F ':' '$3>1000' /etc/passwd|wc -l`
 if [ $n -gt 0 ]
 then
     echo "There are $n common users."
 else
     echo "No common users."
 fi

shell习题-找规律打印数字


请详细查看如下几个数字的规律,并使用shell脚本输出后面的十个数字。
10 31 53 77  105 141 …….

试题解析:
我想大多数人都会去比较这些数字的差值:
10  31  53  77  105  141
21   22   24   28   36
但是这个差值看,并没有什么规律,而我们再仔细看的时候,发现这个差值的差值是有规律的:
10  31  53  77  105  141
21   22   24   28   36
1      2     4     8

参考答案:

#! /bin/bash
x=21
m=10
echo $m
for i in `seq 0 14`; do
 j=$[2**$i]
 m=$[$m+$x]
 echo $m
 x=$[$x+$j]
done

pagent免密钥密码


使用putty远程登录Linux,假如使用密钥验证,为了更加安全我们会增加一个密钥的密码,只有输入正确的密码才能成功远程登录Linux,其实这个输入密码的环节是可以省略的。这就用到了 pagent.exe 程序。它的作用就是把密钥加载到内存中,只需在第一次加载到内存时输入密码,之后就不再输入密码了。

双击pagent.exe, 虽然没有弹出什么窗口,但是它已经运行了,在电脑右下角,双击小图标把它调到前台来,点 “Add key” , 找到我们要加载到内存的私钥,这时会弹出一个小窗口让我们输入私钥的密码,等输入完成后,点 “OK” 就可以了,然后点”close”。

此时我们再运行putty.exe,打开远程主机时,不再输入私钥的密码了。但是以后每天开机后,你可不能忘记运行这个小程序,并加载一下私钥文件。为了让其更加自动化,可以让它开机启动:

在开始菜单中找到”启动” ,右键点击选择”打开”, 把pagent.exe 的快捷方式先发送到桌面,然后再剪切到该文件夹下。这样就开机启动了。

shell习题-封ip


需求: 根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉!

分析: 我们要做的,不仅是要找到哪些ip请求量不合法,并且还要每隔一段时间把之前封掉的ip(若不再继续请求了)给解封。 所以该脚本的关键点在于定一个合适的时间段和阈值。

比如, 我们可以每一分钟去查看一下日志,把上一分钟的日志给过滤出来分析,并且只要请求的ip数量超过100次那么就直接封掉。 而解封的时间又规定为每半小时分析一次,把几乎没有请求量的ip给解封!

参考日志文件片段:

157.55.39.107 [20/Mar/2015:00:01:24 +0800] www.aminglinux.com “/bbs/thread-5622-3-1.html” 200 “-” “Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)”
61.240.150.37 [20/Mar/2015:00:01:34 +0800] www.aminglinux.com “/bbs/search.php?mod=forum&srchtxt=LNMP&formhash=8f0c7da9&searchsubmit=true&source=hotsearch” 200 “-” “Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)”

 

参考答案

#! /bin/bashlogfile=/home/logs/client/access.log
d1=`date -d "-1 minute" +%H:%M`
d2=`date +%M`
ipt=/sbin/iptables
ips=/tmp/ips.txt

block(){
    grep "$d1:" $logfile|awk '{print $1}' |sort -n |uniq -c |sort -n >$ips
    for ip in `awk '$1>50 {print $2}' $ips`; do
        $ipt -I INPUT -p tcp --dport 80 -s $ip -j REJECT
        echo "`date +%F-%T` $ip" >> /tmp/badip.txt
    done
}

unblock(){
    for i in `$ipt -nvL --line-numbers |grep '0.0.0.0/0'|awk '$2<15 {print $1}'|sort -nr`; do
        $ipt -D INPUT $i
    done
    $ipt -Z
}

if [ $d2 == "00" ] || [ $d2 == "30" ]; then
    unblock
    block
else
    block
fi

 

nginx的location优先级


在nginx配置文件中,location主要有这几种形式:

1. 正则匹配 location ~ /abc { }

2. 不区分大小写的正则匹配 location ~* /abc { }

3. 匹配路径的前缀,如果找到停止搜索 location ^~ /abc { }

4. 精确匹配 location = /abc { }

5.普通路径前缀匹配 location /abc { }

 

先说优先级

4 > 3 > 2 > 1 > 5

 

再来解释一下各个格式

location = / {
# 精确匹配 / ,主机名后面不能带任何字符串
[ configuration A ]
}

location / {
# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
# 但是正则和最长字符串会优先匹配
[ configuration B ]
}

location /documents/ {

# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration C ]
}

location ~ /documents/Abc {

# 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
[ configuration CC ]
}

location ^~ /images/ {

# 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
[ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {

# 匹配所有以 gif,jpg或jpeg 结尾的请求
# 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
[ configuration E ]
}

location /images/ {

# 字符匹配到 /images/,继续往下,会发现 ^~ 存在
[ configuration F ]
}

location /images/abc {

# 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
# F与G的放置顺序是没有关系的
[ configuration G ]
}

location ~ /images/abc/ {

# 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
[ configuration H ]
}​

 

再来分析一下A-H配置的执行顺序。

1. 下面2个配置同时存在时

location = / {
[ configuration A ]
}

location / {
[ configuration B ]
}

此时A生效,因为=/优先级高于/

 

2. 下面3个配置同时存在时

location  /documents/ {
[ configuration C ]
}

location ~ /documents/ {

[configuration CB]

}

location ~ /documents/abc {
[ configuration CC ]
}

当访问的url为/documents/abc/1.html,此时CC生效,首先CB优先级高于C,而CC更优先于CB

 

3. 下面4个配置同时存在时

location ^~ /images/ {
[ configuration D ]
}

location /images/ {
[ configuration F ]
}

location /images/abc {
[ configuration G ]
}

location ~ /images/abc/ {
[ configuration H ]
}​

当访问的链接为/images/abc/123.jpg时,此时D生效。虽然4个规则都能匹配到,但^~优先级是最高的。

若^~不存在时,H优先,因为~/images/ > /images/

而/images/和/images/abc同时存在时,/images/abc优先级更高,因为后者更加精准

 

4. 下面两个配置同时存在时

location ~* \.(gif|jpg|jpeg)$ {
[ configuration E ]
}

location ~ /images/abc/ {

[ configuration H ]
}​

当访问的链接为/images/abc/123.jpg时,E生效。因为上面的规则更加精准。


最让程序员头痛的事莫过于此


问题描述:

网站访问时,并不能正常显示汉字,而是很多问号,如下图

这种问题一看就是字符集不对。 在IE浏览器下打开此站点,然后点击右键,把字符集修改为gbk,则显示正常,这样肯定是不行的,总不能让所有用户自己去设置浏览器吧。 所以还得从服务端去入手。

先curl测试:

HTTP/1.1 200 OK

Server: nginxDate: Wed, 19 Jul 2017 08:32:56 GMT

Content-Type: text/html; charset=UTF-8

Connection: keep-aliveVary: Accept-Encoding

X-Powered-By: PHP/5.6.30

发现charset为UTF-8,只要把它修改为gbk即可。 所以修改虚拟主机配置文件,在里面增加一行

charset=gbk;

重启nginx服务后,问题依旧。但curl一个静态文件字符编码变为了gbk,所以怀疑到了php设置。

/usr/local/php/bin/php -i |grep charset

结果如下:

default_charset => UTF-8 => UTF-8

打开php配置文件 /usr/local/php/etc/php.ini 搜索charset,的确有这样的配置:

default_charset = “UTF-8”

把它改为

default_charset = “”

再重启php-fpm服务

/etc/init.d/php-fpm restart

再次curl测试,结果正常了。浏览器的页面也正常了。

shell习题-监控httpd进程


在服务器上,写一个监控脚本。

1. 每隔10s去检测一次服务器上的httpd进程数,如果大于等于500的时候,就需要自动重启一下apache服务,并检测启动是否成功?
2. 若没有正常启动还需再一次启动,最大不成功数超过5次则需要理解发邮件通知管理员,并且以后不需要再检测!
3. 如果启动成功后,1分钟后再次检测httpd进程数,若正常则重复之前操作(每隔10s检测一次),若还是大于等于500,那放弃重启并需要发邮件给管理员,然后自动退出该脚本。假设其中发邮件脚本为之前咱们使用的mail.py

 

参考答案:

#!/bin/bash

check_service()
{
    n=0
    for i in `seq 1 5`
    do
    /usr/local/apache2/bin/apachectl restart 2>/tmp/apache.err
    if [ $? -ne 0 ]
    then
        n=$[$n+1]
    else
        break
    fi
    done

    if [ $n -eq 5 ]
    then
        ##下面的mail.py参考https://coding.net/u/aminglinux/p/aminglinux-book/git/blob/master/D22Z/mail.py
        python mai.py "123@qq.com" "httpd service down" `cat /tmp/apache.err`
        exit
    fi
}   


while :
do
    t_n=`ps -C httpd --no-heading |wc -l`
    if [ $t_n -ge 500 ]
    then
        /usr/local/apache2/bin/apachectl restart
        if [ $? -ne 0 ]
        then
            check_service
        fi
        sleep 60
        t_n=`ps -C httpd --no-heading |wc -l`
        if [ $t_n -ge 500 ]
        then
            python mai.py "123@qq.com" "httpd service somth wrong" "the httpd process is budy."
            exit
        fi
    fi
    sleep 10
done

shell习题-批量创建用户并设置密码


用shell脚本实现如下需求:
添加user_00 – user_09 10个用户,并且给他们设置一个随机密码,密码要求10位包含大小写字母以及数字,注意需要把每个用户的密码记录到一个日志文件里。

提示: 
1. 随机密码使用命令 mkpasswd
2. 在脚本中给用户设置密码,可以使用echo 然后管道passwd命令

 

参考答案

#!/bin/bash
for i in `seq -w 00 09`
do
useradd user_$i
p=`mkpasswd -s 0 -l 10`
echo “user_$i $p” >>/tmp/user0_9.pass
echo $p |passwd –stdin user_$i
done