Linux基础 个人VPS安全
本文最后更新于 55 天前,如有失效请评论区留言。

本文内容的合理性正进一步评估中,请谨慎观看。

前言

Linux基础 装饰你的Shell中,我们简单地复习了一下Vim的用法,还接触了一些比较酷的Linux软件,比如ohmyzshhtop

虽然这些功能看似很强大,但你还不是真正的强大。因为在某种程度上,你的VPS还暴露在一个危险的互联网环境中,而你对此可能还没有太多的认识。所以,本回我将讨论个人VPS安全的相关问题。与个人对应的自然是企业级的安全了,不过那在我的能力范畴之外了。

大家可能偶有耳闻网络安全相关的新闻。比如,facebook的帐号信息被泄露啦,twitter上的名流被人冒名顶替啦。还有以前我读书那会的爆炸性新闻——美国“棱镜计划”和斯诺登。这些好像离我们十分遥远。说近的,平时互联网中很多自动化的攻击,对付它们往往也需要耗费大量的精力。

在日常生活中,会定期改改密码的人估计都是凤毛麟角。平时大家很少过分地考虑网络安全,好像一直也没啥事。这是为什么呢?对于这个问题,我也没有明确答案。不过,我有几个推测,大家可以参详一下:

  • 私人信息基本上已经是被窃取了。这点我就不想多说了。我还记得以前有骚扰电话可以准确地说出我的电话、名字、身份证号和住址。我也不知道这些信息是怎么被泄露出去的,可能在发生在很久以前,具体原因也不可考了。
  • 你的密码还是相对安全的
  • 我们平时使用的服务,比如银行、淘宝、微信之类的,账户和密码的安全由服务商保证。它们基于httpsssl协议,在数学原理和现代密码学原理的buff加持下使得直接破解是十分困难。我们平时说的密码泄露,多半是自己在不安全的地方(比如http开头的网站)输入了自己的帐号信息,又或者你使用了弱密码被别人暴力破解了。所以“定期更换复杂的密码”是一种比较合理的建议(当然,我认为bitwarden才是最佳实践)。
  • 随着移动智能设备的流行,二次验证也变得十分常见。比如你输入正确的帐户信息后,可能还要手机再确认一下,这样的帐户基本上很难被窃取。如果攻击者同时获得了你的手机和你的帐户信息,这基本上就意味着你可能遭遇了绑架之类的人身攻击了,这时候人身安全是优先考虑的问题了。

所以呀,在日常生活中,其实是服务提供商帮你考虑了安全问题。可是,如果你玩VPS的话,你就变成VPS的安全负责人了。这时,你就需要了解一些基本的网络安全的知识了。试想你通过http协议传输密码,那么你的信息将以明文的方式在互联网中传播。这根本没有任何安全性可言。

关于个人VPS的安全,如果以后有更多观点再补充。网络安全是一个相对的概念,你要做到的不是绝对安全,而是比大多数人安全。这样攻击者就不会去啃你这个硬骨头,而去找一些软柿子(那些没有安全防护的VPS)捏了(这么说好像有点腹黑,哈哈)。不过也不用太担心安全问题。毕竟你的VPS才开通没久,也没有布署多少网络服务,攻击者暂时还没发现你。况且,正规的云服务商本身也有一些安全措施,攻击者要突破他们的防线也绝非易事。

总之,在进一步学习Linux之前,我建议大家对自己的VPS做一些安全防护。这里会介绍一些通用的、简单的但却十分有效的安全措施。

测试环境

uname -a  # Linux VM-12-8-ubuntu 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

安全措施

你应该可以正常地顺着下面的代码一步步无障碍运行。

更新软件

旧版本的软件可能会含有某些漏洞,从而成为攻击者发起攻击的基础。这个怎么说呢,其实作为个人用户没有太多可以做的。请保持软件的最新状态吧!我使用OpenMediaVault这个NAS系统时,安全相关的更新会强制自动安装的。

下面这个命令你也学过了:

sudo apt-get update && sudo apt-get upgrade

使用非root用户

创建非root用户

从今天开始,希望你不要再直接使用root用户了!我们先马上来创建一个新的非root用户吧!

首先,创建一个新用户组:

# 创建新用户组 
sudo groupadd -g 344 test

344叫做gid,我是随便取的。你只要取一个不为0的整数应该都可以,因为0是root用户组专用的gid。另外,1000100也是很常见的内置用户组。如果你打算用这些用户组,那你可以不需要运行此命令。

这时,有童鞋可能会问:为什么用户(组)会有idname这两个属性呢?这个问题以后再讨论。

接着,我们为test用户组创建一个用户,名字叫做test_user

# 创建一个新用户
sudo useradd \
    -m -d /home/test_user `#自动创建用户目录`\
    -s /bin/bash `#设置默认shell`\
    -g test `#主组`\
    -G sudo `#副组`\
    test_user

这个命令有点长,而且结构有点奇怪,哈哈 🙂

这其实是一种shell命令的可视化写法,通过\号将一行中的多个元素分至不同的行。在shell中,这会被认为是一条命令。

这样拆分写的好处是,可以比较清晰地看到代码的功能结构。你以后运行或记录很长的shell命令时,也可以使用这个技巧。在markdown的代码框中,可以用TAB链来迅速生成前方空格,或者用Shift+TAB消除前方空格。以后有机会,你可以自己试试看。它和下面的写法是等价的:

sudo useradd -m -d /home/test_user -s /bin/bash -g test -G sudo test_user

下面我们将这个用户(组)删除。

# 删除用户
sudo userdel test_user

# 删除用户组
sudo groupdel test

注意,要将所有的用户删除后才可以删除用户组。

然后,根据类似的方法创建自己专属的用户和用户组吧!我这里就用test_user:test来展示了。

下面,我给这个用户设置一个密码:

# 设置密码
sudo passwd test_user # 假设我输入了testtest

要输入两次密码并完全一样才会生效:

New password:
Retype new password:
passwd: password updated successfully

这个密码,在我们调用sudo的权限会用到。

那么,要怎么切换到test_user用户呢?可以这样:

su test_user # su <用户名>

如果你目前的用户级别不比test_user高,它会要求你输入密码。这个密码就是testtest

如果你是root,直接就切换过去了。应该可以理解这种层次的关系以及它的合理性吧?

在切换的一瞬间,你会发现漂亮的ohmyzsh不见了。这是因为我们用了默认的/bin/bash的缘故。那么怎么搞回来呢?国内小伙伴只要(实际使用时test_user要换成你自己的非root用户名):

# 国内
ZSH=/home/test_user/ohmyzsh sh -c "$(wget -O- https://gitee.com/pocmon/ohmyzsh/raw/master/tools/install.sh)" 

国外小伙伴只要:

# 国外
ZSH=/home/test_user/ohmyzsh sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

按提示操作。看,又回来了。舒服啊!主题自己改,我不多说。不懂的回去《Linux基础 装饰你的Shell》复习。当然,你也可以将oh-my-zsh安装在一个任何用户都可以访问的目录,然后在~/.zshrc里指定$ZSH路径。你以后熟悉Linux的时候,可以尝试一下。毕竟我是比较懒的,就不折腾了。

言归正传。我们可以观察一下主机都有哪些用户:

sudo less /etc/passwd

自己看一下就好了,最下面应该是新的用户。按q可以终止less命令的使用。

观察home目录

我们进入一下新用户的home目录:

cd ~

看看目录的内容:

ls -hl

输出total 0,表示什么都没有。

这时,观察一下home目录的绝对路径:

pwd

输出/home/test_user

好吧,在Linux里创建新用户就是这么简单?对呀,我也不知道为什么这么简单呀:satisfied:

这里就是新家了,以后基本上就是在这里部署应用啦!

探索sudo

这个时候,我们试一下与root的交互。比如:

cd /root

输出bash: cd: /root: Permission denied。因为我们是普通用户嘛,没有办法进入root的目录。在大多数情况下,你甚至没有办法进入另外一个普通用户的home目录,除非你的权限比它高级。所以如果你想保护一些东西,可以用root权限保护它。

我们再试试能不能使用sudo

sudo apt-get update

输入密码后就可以正常地运行了。因为创建用户的时候,sudotest_user的副组。是不是很帅呐:relaxed:

这时,我们再输入这个命令,观察一下我们的用户:

id

输出如下:

uid=1002(test_user) gid=344(test) groups=344(test),27(sudo)

uid是用户的id,gid是用户组的id。这里看到test_user属于testsudo两个用户组。如果test_user不属于sudo用户组,它将不可以使用sudo!

至于uidgid的具体用途,以后玩Docker的时候你会有所体会的。这里按下不表。

最后,我个人认为你可以看一下/etc/sudoers文件:

ls -hl /etc/sudoers

输出是:

-r--r----- 1 root root 825 Apr 17 14:01 /etc/sudoers

看!在默认状态下,这个文件就算是root用户也只可以查看而不可以改动。说明它真的很重要喔!

实际上,它控制了用户对于root权限调用的程度。我们可以尝试来改动一下它。

首先,让它变成root可修改的文件

sudo chmod +600 /etc/sudoers # 600是啥我以后再介绍

然后用Vim编辑它:

sudo vim /etc/sudoers

它的内容应该会类似于:

#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
# timestamp_timeout=30即有效期改成30分钟。
Defaults        env_reset, timestamp_timeout=30
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# User privilege specification
root    ALL=(ALL:ALL) ALL

...

如刚刚运行sudo apt-get update时,你要输入密码。默认这个授权时间是5分钟。

你可以改得稍微长一些,比如30min。我们将Defaults env_reset来改为Defaults env_reset, timestamp_timeout=30即可。Vim退出:wq后生效。如果你不想改,就不要做任何事。直接:q!退出。

之后,我们将它的权限改回来:

sudo chmod -w /etc/sudoers && ls -hl /etc/sudoers

输出为:

-r--r----- 1 root root 847 Apr 19 13:38 /etc/sudoers

这里值得注意的一行是:root ALL=(ALL:ALL) ALL。这意味着root用户在做事情时都不用输入密码(没理解错吧?)。不要让普通用户轻易地拥有这种能力!

另外,你还可以即时强行结束sudo对你的授权:

sudo -K

此后你再调用sudo权限,就要再次输入用户密码获得授权。

其实sudo还有很多更高级的用法,不过我们作为新手了解这些就足够了。

目前阶段咱们还是稳一波,乖乖地用普通的非root用户和密码来做事:relaxed:

禁用root使用ssh登陆

我们用非root用户的重要原因,就是因为我们要禁用root通过ssh登陆我们的VPS。像腾讯云,在初始化系统的时候就是禁root的。这是为什么呢?

我用自己来举例。比如,我可以通过ssh [email protected]的方式尝试我的另一台VPS:

image-20220419140131767

一般情况下,主机是允许root用户远程登陆的。而root用户的名字一般就是root。所以,如果攻击者知道你VPS的ip地址(ping你的域名获得)、用户名(默认有一个root可用)和ssh端口号(默认22),那么保护你电脑的就只有你的用户密码了。如果你的root密码被破解了(比如你用了一些123456的弱密码),那你的VPS就任人鱼肉了!如果你只是非root用户密码被破解,那么root用户可以暂时保护一下你。不过这种时候基本上已经非常危险了。

所以呀,我们用非root用户是有原因的,这样我们可以在用户名这个层面上增强VPS的安全防护

当然,如果你能进一步操作ssh端口号和ip,那么你的VPS的安全等级将呈指数级上升!我下面还会介绍如何进行设置ssh端口和ip的!

我不知道root用户能不能改名,但我觉得没必要。你用一个新的非root用户,然后禁root远程登陆就行了

这里我们开始讲讲怎么禁用root用户远程ssh登陆。首先,我们编辑ssh程序的设置文件:

sudo vim /etc/ssh/sshd_config

在界面中应该在类似的内容:

#Port 22
#AddressFamily any
AddressFamily inet
#ListenAddress 0.0.0.0
#ListenAddress ::

#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
PermitRootLogin no  (就是这里!!)
# PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

找到PermitRootLogin参数,它的值yes改成no。要注意去掉前面的#号。:wq退出保存。

重启ssh服务后生效:

sudo service sshd restart

这里要切记,不要关闭旧的Shell。新开一个Shell,用你刚刚的非root用户登陆Shell。成功后再关闭旧的Shell窗口。切记切记!

隐藏公网ip

从前面的讨论,我们知道VPS的安全也可以在公网ip的层面进行操作。

我们可以通过这个命令获取自己的公网ip:

curl ifconfig.me

它通常长成这样:000.00.00.00,3个点分成4段数字。如果你用VPS,这个公网ip是固定的。如果你用的是家用宽带,这个ip是动态变化的,一般是48小时左右变化一次(视装网地区而定)。某些公司的网络是专线网,公网ip也是固定的。

隐藏ip之前,你应该要准备一个域名并托管在cloudflare上(其它域名托管商没有用过,不知道有没有类似的功能。这里我只展示cloudflare怎么用)。

首先,我们要准备一个前缀,比如abcd。登陆cloudflare的后台:https://dash.cloudflare.com/login

先在右上角先选择简体中文

image-20220419143029522

点泛域名进去,选择DNS。为了安全起见,我隐藏了自己的真实ip和地址名称。

image-20220419143216460

添加一条记录,比如:

image-20220419143434057

温馨提醒:直接开小黄云也是可以的。这里主要是向新人演示Cloudflare小黄云的作用机制,所以多设置一步。

记得打开小黄云,变成Proxy模式仅限DNS模式。最后保存。

回到shell中,你用以下命令ping下你的VPS:

ping abcd.<你的泛域名> # 我这个记录就是abcd.hwb0307.com

如果可以返回准确的ip,再回到clouldflare后台,将小黄云点开:

image-20220419143638500

保存后生效。你也可以再试一下:

ping abcd.<你的泛域名> # 我这个记录就是abcd.hwb0307.com

这时ip已经发生变化了。你也可以用一些站长工具ping一下:https://ping.chinaz.com/

我这里用博客地址来举例:

image-20220419143903294

这时真实的IP已经被隐藏起来。别人用abcd.<你的泛域名>无法正常地访问你的主机,因为你正尝试通过ssh访问cloudflare的某台服务器。是不是很神奇?当然,你也只能用真实ip去访问自己的VPS,而不是某个域名。

这是为什么呢?因为你选择Proxy模式后,每当外部有一个请求要访问abcd.<你的泛域名>时,cloudflare会首先接收这个请求,然后通过一些安全的协议(可能是https之类)与你真实的公网ip进行通信,这时它的作用有点像Nginx反向代理服务器,但应该使用了一些高级的技术。而ssh是没有办法通过这种方式访问的,因为端口号和协议不对,那个主机不一定会开放22端口或者你所改的1234端口。原理图如下:

DNS only: 外部-->你的域名-->VPS公网ip
Proxy: 外部-->你的域名-->Cloudflare反代服务器(这个服务器可能用了CDN之类的技术,ip也是不固定的)-->VPS公网ip

另外,如果你的VPS上有NPM之类的反向代理服务正在反代你的个人网站(比如博客),此时访问它们可能会出现ERR_TOO_MANY_REDIRECTS的报错。官方是这样解释的:

Cloudflare SSL/TLS 应用中的灵活 SSL 选项通过 HTTPS 加密浏览器和 Cloudflare 网络之间的流量。但是,当启用灵活SSL选项时,Cloudflare 会通过 HTTP 将请求发送到未加密的源 Web 服务器。如果您的源 Web 服务器配置为在使用灵活 SSL 选项时将所有 HTTP 请求重定向到 HTTPS,则会发生重定向循环。

解决重定向循环的方法就是:SSL/TLS的灵活模式改为完全模式

image-20220419145503592

这时候,我们会使用NPM(或者Nginx)自己的证书(通常是来自Let’s Encrypt的免费个人证书)来保证https请求的安全性。这个你可以在我另一篇博文Docker系列 两大神器Nginx proxy manager (NPM)和ddns-go的安装中更加详细地了解。

基于前面的原理,我们还可以推测,要安全地远程访问一台具有动态ip的主机(比如家用NAS)则不能使用Proxy的方式。你应该只能设置DNS only的模式,让域名直接解析你的域名;你也没有办法一直通过ip访问ip,因为你的ip在动态变化中。所以在这种情况下,你应该小心地保护这个域名,不要被别人知道。

不过,Proxy模式可能会造成某些地方无法访问你的网络。如果这个操作对你的需求造成造成了明显影响,你还是选择DNS-only模式吧。或者选择国内的域名托管商(搭建互联网服务要记得备案喔!)

这部分内容是我的推测,未经求证。也许我的理解有误,欢迎专业人士留言指正了!

安装UFW防火墙

官方的帮助文档:https://help.ubuntu.com/community/UFW

前面,我们通过更改ssh端口的方式增强安全性。其实呢,你还可以通过管理VPS所有的端口来进一步增加安全性喔!这里我们介绍ufw

首先,给大家可以看一段wiki上的介绍:

image-20220419151458184

大致来说,ufw是一个简单好用的防火墙工具,使用iptables进行设置。这里我不准备展开介绍iptables。自己想了解百度Google即可。

这里多说一句,iptables其实是一个很强大的防火墙工具,不过它确实很难用。如果你学会熟练地使用iptables的话,我觉得ufw应该也可以不用。像我们这种新手用ufw就足够了。

首先,观察一下自己的机器有没有ufw

which ufw # /usr/sbin/ufw

没有的话,直接安装一个:

sudo apt-get install ufw

如果有的话,就可以开始了!

sudo ufw status查看防火墙状态。如果你之前没有设置过ufw,一般是显示Status: inactive

下面我们逐步来设置ufw

  • 设置ufw的默认值
sudo ufw default deny incoming # 禁止所有进站的流量
sudo ufw default allow outgoing # 允许所有出站的流量
  • 允许https/http连接
sudo ufw allow 80 # 默认http
sudo ufw allow 443 # 默认https
  • 允许新ssh端口(下文会用到)
sudo ufw allow 1234/tcp comment 'SSH_2' # 1234记得换成你自定义的端口喔

如果你遵循我的docker教程,80端口和443端口一般是由Nginx proxy manager进行管理。一般情况下,都是Nginx软件管理80和443端口(比如宝塔面板)。

你也可以根据自己的需要开放端口:

sudo ufw allow <你的端口号>/tcp comment '你想要的备注'

如果你用docker,通常要添加某个应用的端口号,这样才可以正常地通过NPM反代。

值得一提的是,iptable可以提供更加精细的调控,但ufw我还不知道怎么精细地控制端口不同类型的流量。

  • 启动ufw:
sudo ufw enable # 启动ufw。重启主机后正式生效。

其它常用的命令有:

# 查看帮助 
ufw -h

# 如果你改动了ufw规则,记得reload一下生效
sudo ufw reload

# 显示规则的数字
sudo ufw status numbered

# 删除某个规则。基于sudo ufw status numbered命令。
sudo ufw delete <数字>

更改默认的ssh端口

默认的ssh端口号是22。SSH 的端口一般建议把它改成一个大于1024小于65535的整数。比如,我想改成1234

在你的VPS后台防火墙里先打开1234端口。有些VPS后台可能没有防火墙,就可以不用管。

下面,简单地用ufw将新的ssh端口1234打开:

sudo ufw allow 1234/tcp comment 'SSH' # 1234记得换上你自己的端口啦

然后像修改root访问ssh的权限一样打开ssh的设置文件:

sudo vim /etc/ssh/sshd_config

在开头不远处就一个#Port 22的字样。#号在多数情况下是注释号,表明后面的内容不生效。

#号去除,然后22改为1234:

Port 1234

重启ssh服务生效

sudo service sshd restart

此时不要关闭终端,新开一个窗口进行用新端口号、非root用户进行ssh登陆测试。如果成功,就可以关闭旧的Shell了。OK,安全指数+1,哈哈:smirk:

新端口成功后,旧的22端口已经没有用。可以关掉了。

禁ping

终于到最后一步了:laughing:

就算你隐藏了公网ip,别人通过穷举法还是有可能发现你的ip。

所以还是设置自己的主机禁ping,伪装成是一台不能使用的机器吧。

很简单,只要

sudo vim /etc/ufw/before.rules

外面到本地的访问是由INPUT控制的,其中echo-request就是ping所采用的类型。因此,只要找到ok icmp codes for INPUT下面的记录:

# ok icmp codes for INPUT
-A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT
-A ufw-before-input -p icmp --icmp-type echo-request -j DROP

如上面的代码框所示,找到含有echo-request,把ACCEPT改成DROP。这样外面的机器就无法ping通你的VPS了!

可重新加载一下ufw以使改动生效(不知道是否是必需):

sudo ufw reload

你可以用windows个人电脑或者Linux的主机ping一下你的VPS(~ ̄▽ ̄)~

小结

这一节,我们基本对个人的VPS进行了基本的防护,包括对ip、端口、用户的操作。这样可以让VPS更安全,但也不是绝对的。我也并没有太多经验。

总之,你可以在此基础上进行深入的Linux学习了,比如布署Docker应用和Wordpress之类的!

如果你以后网站做大做强了,访问量很大的时候,还是需要请专业的团队来帮忙维护的!

参考资料

版权声明:除特殊说明,博客文章均为Bensz原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。 如有需要,请至学习地图系统学习本博客的教程。加Telegram群可获得更多帮助喔! | 博客订阅:RSS | 广告招租:留言板 | 博客VPS |

评论

  1. tiezhu
    Windows Edge 104.0.1293.63
    1月前
    2022-8-24 10:08:14

    大佬,vps采用密钥对的登陆方式是不是也能大幅度的提升安全性呢

    • 博主
      tiezhu
      Windows Chrome 104.0.0.0
      1月前
      2022-8-24 17:00:19

      据说是这样,不过我平时用得也不多。安全性的追求程度和应用场景是相适应的。家用场景下,普通的密码登陆就行。注意,不要用123456之类的弱密码。

  2. 突突
    Android Chrome 99.0.4844.74
    5月前
    2022-4-20 23:30:07

    好文👍🏿👍👍🏻

    • 博主
      突突
      Windows Chrome 99.0.4844.51
      5月前
      2022-4-20 23:31:20

      哈哈,自己学完了随便写写,怕以后忘记了~谢谢鼓励哈! 🙂

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇