Linux安全基础知识

1、概览

首先,Linux从UNIX和POSIX那里继承了最基本的安全机制:用户、文件权限和进程capabilities。
其次,补充提供了一个通用的安全访问控制框架——Linux安全模块(LSM),是通过可加载的内核模块实现的,可以支持现存的各种不同的安全访问控制系统。SELinux、DTE、LIDS、AppArmor、SELinuxSmack、TOMOYO Linux、Openwall等都是通过LSM框架提供自己的服务。
LSM框架提供了类似于netfilter的hook机制,将安全点做成hook,各种安全机制对安全的限制策略都通过hook点去实现。这样就兼容了大部分的安全方案。如果你发现某个安全模式不好用,可以换其他的内核模块来提供内核安全保护。
LSM模块的大部分作用都是保护,而非审计。

安全机制开发者一般是在LSM定义钩子的位置,在内核内部直接定义安全机制,或者通过security()系统调用让用户端程序可以控制内核端实现模块的行为。
这类钩子有:
  • 任务钩子,如任务间通信、kill调用等;
  • 程序装载钩子,可以改变程序的特权、文件描述符控制等;
  • 文件系统钩子,可以对文件系统挂载、打开文件甚至socket等做额外的检查;
  • 网络钩子,主要控制什么进程允许socket到哪里;
  • 模块钩子
  • 顶层系统钩子,如访问端口、设备主机名。
在民用安全软件领域,近些年最常用的是SELinux,以及Ubuntu所使用的Apparmor。

2、密码学

数论是加密算法的基础,加密算法是密码应用的基础。
在密码应用上主要有3个领域:
  • 摘要
  • 加密
  • 认证

2.1 摘要

是对一大段数据或很小的一段数据生成一个长度较短的固定长度的数据。这个数据能够代表原数据,且一般不会重复。
主要用途是下载或传输文件(计算并对比双方的摘要是否一致来判断是否出现错误)、密码验证(系统里不存真实的密码,而只存密码的摘要信息,登录过程就是计算摘要并对比二者是否一致)。大部分的企业在存储密码的时候都会存储哈希后的密文,而且还会加盐。

摘要的主要算法有:
  • MD系列,当前使用最广泛的是MD5版本;
  • SHA系列,SHA本身是对MD4升级所得到的,目前发展到了SHA4版本;
  • HMAC系列,使用已有的摘要算法(MD5、SHA),同时加入了一个秘钥成分;
  • CRC系列,是一种非常常用的摘要算法,但是它的碰撞概率也是最高的,优点是计算速度快,所以一般只用在对简单数据的摘要计算上,例如网络通信中的数据包。
摘要算法常识:
  • 衡量一个摘要算法好坏的指标有两个:速度和碰撞。
  • 所有的摘要算法的基本实现思想是相同的,不同之处就是算法采用的参数,例如分组长度、每个分组进行操作的步骤,输出摘要的长度等。
  • 本质上常见的哈希算法都是将数据分组,然后对每个分组进行数学运算,并且之前分组的运算结果参与之后分组的运算(加、减、异、或等),每个算法各有特点。
  • MD5已经被证明存在碰撞。但在民用领域,使用这些哈希算法还是安全的。
  • 摘要算法在内核中几乎都支持,同时很多文件系统和比较大的模块也会自己实现一套摘要算法。

2.2 加密

是对一段易读数据进行数学变换,变换为另一段表面无意义的数据,用于在不安全的信道上传输数据。
加密涉及的常见数论是3种各不相同的数论难题:
  • 整数分解
  • 离散对数
  • 椭圆曲线上的离散对数
破解的过程,就是解决数论难题的过程。

根据加密和解密的秘钥是否一样,可以将加密算法分为对称性和非对称性的。
常用的对称性加密算法有:
  • DES,是分组式的加密算法,各个分组不发生交互运算,是早期的数据加密标准,速度快,但可以用穷举法破解;
  • 3DES,基于DES实现的,同时使用3个不同的密钥进行3次加密,加大了破解的难度;
  • AES,是流式的加密算法,流式之前的运算结果会影响下面的计算,所以要比分组式算法更安全,是下一代的加密算法标准,速度快且安全级别高,
常用的非对称性加密算法有:
  • RSA
  • Elgamal
  • 背包算法
  • Rabin
  • D-H
  • ECC(椭圆曲线加密算法)
RSA,是目前使用最广泛的加密算法。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难。因此可以将乘积公开作为加密密钥,而只有自己知道,其他人很难算出来的因式分解结果就是解密秘钥了。
在这个算法中,公开的只能是加密秘钥。主要用于实现认证和数字签名。

对称密钥的计算速度明显快于非对称秘钥,缺点是缺少安全的秘钥分发渠道。所以业界普遍是使用非对称加密来做认证和生成对称密钥(也叫会话密钥),然后双方使用对称密钥进行通信。由于对称密钥可以靠穷举法进行破解,所以一般的会话管理都会自动更换会话秘钥。

2.3 认证

认证是验证“你是你”、“我是我”的过程,主要使用的是非对称加密算法。这个场景的应用在数论的使用上与加密是一样的。
由于采用素数积的方式只能公布加密秘钥,所以通过公布解密密钥来做到认证的做法不可取。但是通过加入第三者就可以,这就是秘钥管理 系统,最常见的是Kerberos系统。认证过程一般有一个认证中心,被这个中心认证过的证书(X.509)就是可以信任的。这个认证过程本质上就是一些加密、解密的运算。
以下是一个示例。
首先是要搭建一个证书中心,提供证书自签名服务,先生成自己的私钥,并且加密(可选):
openssl genrsa -out private.key 2048 //生成自己的私钥,实际上数据中也包含了公钥部分的信息
openssl rsa -in private.key -des3 -out encrypted.key //对私钥进行加密
证书中心需要制作一个可以给其他用户签名的签名证书:
openssl req -new -key private.key -out ca.csr  //证书中心生成一个证书请求
openssl x509 -req -in ca.csr -extension v3_ca -signkey privatekey -out ca_sign.crt  //证书中心给自己生成的证书请求进行签名,自己批准自己通过,并且生成一个可以给其他用户签名的签名证书给证书中心使用
当一个server需要申请使用证书的时候:
openssl genrsa -out server-private.key 2048  //生成server自己的私钥,这里选择了不做密钥加密
openssl req -new -key server-private.key -out server.csr  //server生成证书请求
将server制作的证书请求文件发送给证书中心进行签名:
openssl x509 -req -in server.csr -extensions v3_ca -CA ca_sign.crt -CAkey private.key -CAcreateserial -out sign.crt //证书中心为server最终生成签名过的证书,server现在是被认证中心认证过的服务器了
这样就完成 了server的证书制作。
客户端只需要加载了CA公开的证书ca_sign.crt就可以认证所以被这个证书中心签名过的server了。由于颁发证书需要CA的private.key,所以客户端拿到了证书也无法给别人颁发证书。

在PC的浏览器中一般都预存了很多大型CA的证书,这些个CA的证书都是自签名的,里面记录了CA的公钥。因此,当遇到持有某未在浏览器的信任CA列表中的CA签名的服务器csr证书文件的时候,浏览器也会给出相应的安全提示。

2.4 数字签名

数字签名是一种特殊的认证。这个认证方式就是典型的使用私钥来加密,使用公钥来解密的应用。虽然能够公布的只有质数积,但不一定非要用质数积来加密,也可以拿它来解密。
  • 数字签名,使用私钥加密,使用公钥解密
  • 认证,使用公钥加密,使用私钥解密

2.5 秘钥交换

常见的密钥交换方式有以下两种:
  • 公钥加密实现,发送方用接收方的公钥加密自己的密钥,接收方用自己的私钥解密得到发送方的密钥,从而实现密钥交换。
  • 使用DH算法,普通的DH算法被证明无法抵抗中间人攻击,因此又有进一步的演进。

3、Linux用户和权限系统

我们使用Linux系统,一定会使用一个用户账号。没有用户账号就不可能使用任何的系统功能,包括系统调用,因为系统调用本身也是要有用户的。
我们刚登录一个系统,需要一个login程序,验证了用户名密码后,就会返回一个shell,后面执行的内容都是在shell中执行的。

3.1 系统启动时的权限

由于Linux内核设计的进程继承关系,第一个进程是init进程,这个进程是root权限,拥有最高的完全权限。如果直接修改init程序,在里面实现逻辑,也是会具有完全权限的,内核的所有权限检查都可以完全通过。

后来启动的进程全部是init进程复制出来的。
Linux有两种复制接口:
  • fork,相当于完全复制,然后使用execve系统调用执行新的命令。vfork是因为fork调用过于占用内存(会拷贝整个内存空间),而vfork是暂停父进程的执行,直接在父进程的地址控制中执行execve系列调用。
  • clone,是可以指定复制内容的,例如文件句柄、根文件系统、命名空间等
fork, clone, vfork这3个API的内部实际上都是调用一个内核内部函数do_fork。

启动后面的低权限进程和用户的过程,是一个不断降低权限的过程。使用权限更小的用户启动程序。降权的方法是使用高权限的进程调用特定的系统调用,例如使用unshare、prctl或setuid来完成。

su命令是我们常用的切换到其他用户执行命令的方法。它所使用的就是setuid系统调用方法将当前执行的具有root权限的用户降级 为非root用户,或者sudo -s从低权限用户切换到root用户。
unshare和prctl是用户控制偏功能性的权限(capabilities、namespace等)。

3.2 系统启动后的权限

系统正常运行后,进程要么由其他的进程启动,要么由shell启动。由其他进程启动的很多也是由shell启动的。

Shell是Linux系统的中坚力量,其本身也必须有一个所属用户,例如登录使用的用户user1,那么login程序(root权限)验证了这个用户名和密码后,就可以setuid设置启动的Shell以特定的用户权限运行。

Shell之所以重要,是因为它就是Linux的一个中转中心。也有使用图形界面作为中转中心的,如Windows。而SSH是使用服务进程作为中转中心的一个例子。只不过,登录SSH后中心还是转变为了Shell。

在系统接口层面,只有Shell能够做到将程序、命令与字符串有机结合,即功能强大且非常简便。

3.3 内核中的用户和权限模型

Linux中为了定义权限,设计了一个对象模型。这个模型主要组件有object、subject、context、action、rule。
  • object,常见的对象都是object,如Task、Files/inodes、Sockets、Message queues、Shared memory segments、Semaphores、Keys;
  • subject,当一个object作用在其他的object的时候,发起方就是subject,最常见的变成subject的object就是task;
  • context,无论是object是subject,都有自己的context,context主要是一些归属于自身的权限存储(credentials);
  • action,一个subject作用到另外一个object的动作叫作action;
  • rule,限制一个action权限叫作rule,rule包括MAC和DAC两类,常见的SELinux规则就是在这里工作的。
整个模型动作起来,给所有的对象都赋予了静态和动态的权限,就形成了完整的权限系统。

我们常见的用户和文件权限工作在context层次,即credentials。
目前有7种credentials,需要同时满足这些权限检查,若不满足其中一个检查权限就不能通过安全检查。
比较常见的权限检查有以下3种:
  • 传统uid系列,设置在文件object context credentials层次,但是euid系列设置在subject context credentials层次。
  • capabilities是Linux独创的系统。其将系统分成了几个部分,权限一个一个子系统地设置和删除。这是进程subject context的内容。
  • LSM是大部分大规模的安全系统所基于的内核安全机制。通过在常用的路径上安装钩子实现,是完全独立于模型的机制。
Linux 内核中并没有专门的数据库存储用户和组的信息,而是依附在每个进程上,每个进程都可以有多种用户和组的设置。


4、Linux下的用户和文件权限

4.1 Linux下的用户权限

linux系统中每个进程都有2个ID,分别为用户ID(uid)和有效用户ID(euid),UID一般表示进程的创建者(属于哪个用户创建),而EUID表示进程对于文件和资源的访问权限(具备等同于哪个用户的权限)。C语言中,可以通过函数getuid()和geteuid()来获得进程的两个ID值。
  • UID(又称为RUID,Real UID),用于在系统中标识一个用户是谁。当一个用户登陆系统时,系统会将UID和EUID都赋值为/etc/passwd文件中的UID,一般情况下2个ID是相同的。
  • EUID,Effective UID,用于系统决定用户对系统资源的访问权限,通常情况下等于RUID。只有在运行Set UID程序时,EUID才会与RUID不同,例如su。
  • SUID,saved set-user-ID,保存设置用户ID,是进程刚开始执行时euid的副本。这样在执行exec调用之后还能重新恢复原来的effectiv user ID。用于对外权限的开放。跟RUID及EUID是用一个用户绑定不同,它是跟文件而不是跟用户绑定。

4.2 Linux下的文件权限

Linux下可以用ls -l 命令来看到文件的权限。用ls命令所得到的表示法的格式是类似这样的:-rwxr-xr-x 。
下面解析一下格式所表示的意思。这种表示方法一共有十位:
9 8 7 6 5 4 3 2 1 0
- r w x r - x r - x
第9位表示文件类型,可以为p、d、l、s、c、b和-:
  • p表示命名管道文件
  • d表示目录文件
  • l表示符号连接文件
  • -表示普通文件
  • s表示socket文件
  • c表示字符设备文件
  • b表示块设备文件

4.3 SUID、SGID以及Sticky bit

SUID 是 Set User ID, SGID 是 Set Group ID的意思。
SUID
当一个设置了SUID 位的可执行文件被执行时,该文件将以所有者的身份运行,也就是说无论谁来执行这个文件,他都有文件所有者的特权。
如果所有者是 root 的话,那么执行人就有超级用户的特权了。

SGID
当一个设置了SGID 位的可执行文件运行时,该文件将具有所属组的特权, 任意存取整个组所能使用的系统资源。
若一个目录设置了SGID,则所有被复制到这个目录下的文件, 其所属的组都会被重设为和这个目录一样,除非在复制文件时加上-p (preserve,保留文件属性)的参数,才能保留原来所属的群组设置。

如果一个文件被设置了SUID或SGID位,会分别表现在所有者或同组用户的权限的 可执行位上。
例如:
  • -rwsr-xr-x 表示SUID和所有者权限中可执行位被设置
  • -rwSr--r-- 表示SUID被设置,但所有者权限中可执行位没有被设置
  • -rwxr-sr-x 表示SGID和同组用户权限中可执行位被设置
  • -rw-r-Sr-- 表示SGID被设置,但同组用户权限中可执行位没有被社
实际上在Linux的源码实现中,文件权限用12个二进制位表示,如果该位置上的值是1,表示有相应的权限:
11 10 9 8 7 6 5 4 3 2 1 0
S  G  T r w x r w x r w x
第11位为SUID位,第10位为SGID位,第9位为sticky位,第8-0位对应于上面的三组rwx位。
-rwsr-xr-x的值为: 1 0 0 1 1 1 1 0 1 1 0 1
-rw-r-Sr--的值为: 0 1 0 1 1 0 1 0 0 1 0 0

Sticky bit
该位可以理解为防删除位。八进制表示位1000,它是从UNIX中继承下来的,在LINUX中将会忽略文件的sticky位。但是对一个目录设置sticky位,那么将能阻止用户删除或者重命名文件,除非用户是这个目录的所有者、文件所有者或者超级用户。它通常用来控制对共享目录(例如/tmp)的访问。
chmod o+t temp -- 为temp目录加上sticky标志 (sticky一般只用于目录)

三种特殊权限可以用单独的一位8进制数值表示。
其实文件的权限应该用四个八进制来表示,不过用 ls -l 命令时,只显示三个罢了。那个没有显示的八进制数字其实是第一个,它用来设定一些特殊权限。这个八进制数字的三个位是:SUID SGID sticky-bit
SUID、SGID和sticky-bit的数值表示
SUID SGID sticky 二进制 八进制 说明
- - - 000 0 不设置特殊权限
- - t 001 1 只设置sticky
- s - 010 2 只设置SGID
- s t 011 3 只设置SGID和sticky
s - - 100 4 只设置SUID
s - t 101 5 只设置SUID和sticky
s s - 110 6 只设置SUID和SGID
s s t 111 7 设置三种特殊权限

设置完这些标志后, 可以用 ls -l 来查看. 如果有这些标志, 则会在原来的执行标志位置上显示. 如
rwsrw-r-- 表示有setuid标志
rwxrwsrw- 表示有setgid标志
rwxrw-rwt 表示有sticky标志
那么原来的执行标志x到哪里去了呢? 
系统是这样规定的, 如果本来在该位上有x, 则这些特殊标志显示为小写字母 (s, s, t). 否则, 显示为大写字母 (S, S, T)

授予setuid权限
chmod u+s prog1
or
chmod 4xxx prog1
具有setuid属性的程序为-rwsr-xr-x。

授予setgid权限
chmod g+s dir1
or
chmod 2xxx dir1
具有setgid属性的目录为drwxrwsr-x。

授予sticky权限
chmod t dir1
or
chmod 1xxx dir1
具有sticky属性的目录为drwxrwxrwt。

4.5 目录的读权限和执行权限

目录的读权限和执行权限是不同的。
  • 当用户对某个目录只有读权限时,那么该用户可以列出该目录下的文件列表(即可以使用ll来列出目录下的文件),但是不能进入该目录(即不能cd 目录名 来进入该目录),即如果该目录是用户访问路径的某个组成部分的话,到这里是访问不了的。
  • 当用户对某个目录只有执行权限时,该用户是可以进入该目录的(即可以通过cd 目录名 来进入该目录),因为一个用户要想进入一个目录,就必须具有可执行权限才可以。但该用户是不能列出这个目录下的文件列表的(即不能使用ll等命令列出该目录下的信息)
  • 当用户具有写权限时,用户可以在当前目录增加或者删除文件,但需要几个前提:需要有可执行权限;要想删除文件,那么sticky bit位是没有设置的。

5、Linux安全体系

内核只管权限。如果文件的所有者是普通进程,但是却调用了reboot,只要执行的时候有root权限,这个程序就能够执行成功。所以内核默认依赖于谁(uid)在执行程序,而不是依赖执行的内容。
大部分额外的安全系统(如Apparmor、SELinux、seccomp、capabilities、ACL等)都是对默认最有效的、基于用户的安全体系的补充,大多数作用于执行的内容,而不是执行的用户,并且作用在不同的位置。

5.1 用户和组的概念

用户和组是独立于文件和进程而存在的,它们被存储在/etc/下的几个文件中。
一个用户可以属于多个组,有一个主要组,其他的叫作supplementary group,但这些组之间并没有什么区别。

文件object静态地包含了用户和组的设置,而task(进程)也分为静态和动态的用户和组的设置。

5.2 文件object权限

文件有标准权限和扩展权限。标准权限包括用户、组、其他组3个的r、w、x、s、t权限。
  • s是让非root程序以root身份运行的标志位;
  • t是让进程启动后滞留内存不被回收的标志位,以及该文件属于哪个用户哪个组;

比较常见的扩展有i、a。
  • i,限制文件不能被删除;
  • a,限制文件只能被追加;
不同的文件系统可以实现不同的扩展权限,甚至可以用户自定义,ACL扩展是所有文件系统都具有的能力。例如阻止root删除文件。

设置标准权限用chmod,设置扩展权限用chattr。此外,还有getfacl、lsattr等命令。

5.3 进程的object和subject权限

进程虽然看起来是动态的,但它们既是object(静态的一面)也是subject(动态的一面)。
  • 静态的一面,就是我们设置在文件上的用户和组,以及其对应的权限。在大部情况下,内核依据这个信息进行权限判断,这个用户叫作实际用户。
  • 动态的一面,就是当文件suid置位的时候,用户以root权限运行。这时进程的权限是root的,这个用户就是有效用户。理论上有效用户不一定是root,但是目前都是这样,sgid也是一个道理。
所以文件object本身的权限设置,既提供了文件object本身的权限,也提供了进程object的权限和进程subject的权限。

Linux中默认是基于用户的安全,并且有各个文件系统的权限位补充配合。后续发展的多种维度的、基于行为的安全机制成为Linux安全系统发展的方向。
安全系统大部分都在内核中完成,内核只是一个管理和验证系统,并不是所有的安全验证都在内核中完成,系统层次可以完成相当多的权限验证。


参考资料:
《深入Linux内核架构与底层原理》


  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux是一种开源、免费的操作系统内核,由 Linus Torvalds 在1991年创建。它以其稳定性、安全性和高度可定制性闻名,并在服务器、超级计算机和嵌入式系统等领域广泛应用。以下是 Linux 平台的一些基础知识: 1. **内核与用户空间**: - 内核:Linux的核心部分,负责处理硬件、安全管理、进程管理等核心任务,运行在系统最低权限级别。 - 用户空间:应用程序和用户接口运行的地方,相对于内核更安全,有独立的内存空间。 2. **文件系统**: - Linux 使用多种文件系统,如 ext2、ext3、ext4、XFS、Btrfs等,用于存储数据和组织目录结构。 3. **命令行界面(CLI)**: - 常用的有 Bash shell(基于 Bourne Again Shell),提供强大的文本交互环境。 - 可以通过命令行执行各种操作,包括文件管理、系统配置和网络管理等。 4. **进程与线程**: - 进程是程序在系统中运行的一个实例,而线程是进程中的轻量级执行单元。 - Linux 支持多任务和并发,使用 fork() 和 exec() 函数创建和切换进程,以及 pthread_create 创建线程。 5. **软件包管理**: - 主要的包管理器有 apt(Debian/Ubuntu)、yum(Red Hat/CentOS)、zypper(SUSE)等,用于安装、更新和管理软件。 6. **版本控制系统**: - Linux 开发者广泛使用 Git 进行代码管理,提供分支管理、合并冲突解决等功能。 7. **网络配置与服务**: - Linux 提供丰富的网络工具,如 ifconfig、iptables等,配置和管理网络连接。 - 包括 TCP/IP 协议栈、DNS、NTP 等服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值