41、深入了解Shell的可移植性、安全性及相关特性

深入了解Shell的可移植性、安全性及相关特性

1. Shell会话与启动文件

1.1 交互式与非交互式会话

在Shell操作中,交互式会话和非交互式会话在启动文件的调用上有所不同。交互式会话通常只调用一个文件,例如使用 bash 启动交互式会话时:

$ bash
Start an interactive session
DEBUG: This is /home/bones/.bashrc
$ exit
Terminate the session
exit

而非交互式会话通常不调用任何文件,如:

$ echo pwd | bash
Run a command under bash
/home/bones

但如果 BASH_ENV 变量指向一个启动文件,非交互式会话也会调用该文件:

$ echo pwd | BASH_ENV=$HOME/.bashenv bash
Run a command under bash
DEBUG: This is /home/bones/.bashenv
/home/bones

1.2 Z-Shell的启动与终止

Z-Shell( zsh )具有复杂且灵活的定制过程。它可以伪装成Bourne shell或Korn shell。当以 sh ksh 命名调用,或以 s k 开头(可选地以单个 r 开头表示受限)时,它具有与这些shell相同的启动行为。

Z-Shell每次启动时,无论是登录shell、交互式shell还是非交互式shell,都会尝试读取两个初始化文件:

test -r /etc/zshenv && . /etc/zshenv
Read system-wide script
if test -n "$ZDOTDIR" && test -r $ZDOTDIR/.zshenv ; then
    . $ZDOTDIR/.zshenv
Read this file
elif test -r $HOME/.zshenv ; then
    . $HOME/.zshenv
Or else this file
fi

ZDOTDIR 变量可用于系统管理,阻止 zsh 自动读取用户主目录中的启动文件,而是从受管理控制的其他位置读取。如果需要该变量,通常会在 /etc/zshenv 中设置。若 ZDOTDIR 未设置,将个人定制放在 $HOME/.zshenv 文件中,可使其在每个Z-Shell会话中生效。

如果是登录shell,接下来会读取两个启动配置文件:

test -r /etc/zprofile && . /etc/zprofile
Read system-wide script
if test -n "$ZDOTDIR" && test -r $ZDOTDIR/.zprofile ; then
    . $ZDOTDIR/.zprofile
Read this file
elif test -r $HOME/.zprofile ; then
    . $HOME/.zprofile
Or else this file
fi

如果是登录shell或交互式shell,会尝试读取两个启动脚本:

test -r /etc/zshrc && . /etc/zshrc
Read system-wide script
if test -n "$ZDOTDIR" && test -r $ZDOTDIR/.zshrc ; then
    . $ZDOTDIR/.zshrc
Read this file
elif test -r $HOME/.zshrc ; then
    . $HOME/.zshrc
Or else this file
fi

最后,如果是登录shell,会尝试读取两个登录脚本:

test -r /etc/zlogin && . /etc/zlogin
Read system-wide script
if test -n "$ZDOTDIR" && test -r $ZDOTDIR/.zlogin ; then
    . $ZDOTDIR/.zlogin
Read this file
elif test -r $HOME/.zlogin ; then
    . $HOME/.zlogin
Or else this file
fi

zsh 退出时,如果是登录shell且不是因执行另一个进程而终止,会按顺序读取两个终止脚本:

if test -n "$ZDOTDIR" && test -r $ZDOTDIR/.zlogout ; then
Read this file
    . $ZDOTDIR/.zlogout
elif test -r $HOME/.zlogout ; then
Or else this file
    . $HOME/.zlogout
fi
test -r /etc/zlogout && . /etc/zlogout
Read system-wide script

以下是不同类型会话的示例:
- 登录会话

$ login
Start a new login session
login: zabriski
Password:
Echo suppressed to hide password
DEBUG: This is /etc/zshenv
DEBUG: This is /home/zabriski/.zshenv
DEBUG: This is /etc/zprofile
DEBUG: This is /home/zabriski/.zprofile
DEBUG: This is /etc/zshrc
DEBUG: This is /home/zabriski/.zshrc
DEBUG: This is /etc/zlogin
DEBUG: This is /home/zabriski/.zlogin
$ exit
Terminate the session
DEBUG: This is /home/zabriski/.zlogout
DEBUG: This is /etc/zlogout
  • 交互式会话
$ zsh
Start a new interactive session
DEBUG: This is /etc/zshenv
DEBUG: This is /home/zabriski/.zshenv
DEBUG: This is /etc/zshrc
DEBUG: This is /home/zabriski/.zshrc
$ exit
Terminate the session
Silence: no termination files are read
  • 非交互式会话
$ echo pwd | zsh
Run a command under zsh
DEBUG: This is /etc/zshenv
DEBUG: This is /home/zabriski/.zshenv
/home/zabriski

2. Shell脚本的可移植性与扩展

2.1 POSIX标准与Shell差异

POSIX标准为编写可移植的shell脚本做出了努力,但现实世界中情况复杂。 bash ksh93 在POSIX基础上有许多扩展,但两者之间并非完全兼容,即使在设置选项或保存shell完整状态等简单领域也存在一些需要注意的小问题。

2.2 bash的shopt命令

shopt 命令可控制 bash 的行为,特别推荐在交互式使用时启用 extglob 选项。

2.3 常见扩展特性

bash ksh93 有许多对shell编程非常有用的共同扩展,如 select 循环、 [[…]] 扩展测试工具、扩展模式匹配、花括号扩展、进程替换和索引数组等。还有一些小但有用的杂项扩展,其中算术 for 循环和 ((…)) 算术命令较为显著。

2.4 版本确定与其他Shell

可以从互联网下载 bash ksh93 的源代码并进行编译。此外,还提到了另外两种流行的扩展Bourne风格的shell: pdksh zsh 。了解正在运行的shell版本很重要,因为不同的Bourne shell语言实现具有不同的启动和终止定制功能及文件。通用的shell脚本不应依赖于每个用户设置的功能或变量,而应自行完成所有必要的初始化。

3. 安全的Shell脚本编写

3.1 编写安全脚本的建议

为了编写更安全的shell脚本,可以参考以下建议:
1. 不将当前目录放入PATH :可执行程序应仅来自标准系统目录,将当前目录( . )放入 PATH 会为“特洛伊木马”攻击打开大门。
2. 保护bin目录 :确保 $PATH 中的每个目录只能由其所有者写入,bin目录中的所有程序也应如此。
3. 设计后编码 :在编码前花时间思考要做的事情和实现方法,包含处理错误和失败的代码。
4. 检查输入参数的有效性 :验证输入参数是否符合预期类型和范围,shell的模式匹配功能对此很有用。
5. 检查命令的错误代码 :即使是看似不会失败的命令,也可能因恶意操作而失败,从而导致脚本行为异常。
6. 不信任传入的环境变量 :如果后续命令使用环境变量,应检查并将其重置为已知值。例如,显式设置 PATH 只包含系统bin目录, IFS 设置为空格、制表符和换行符。
7. 从已知位置开始 :脚本启动时显式切换到已知目录,并确保切换成功,如 cd app-dir || exit 1
8. 使用完整路径名 :使用命令的完整路径名,以确保使用的是预期版本。
9. 使用syslog记录审计跟踪 :记录脚本调用的日期、时间和用户名等信息。如果没有 logger ,可以创建一个函数来记录日志:

logger( ) {
    printf "%s\n" "$*"  >>  /var/adm/logsysfile
}
logger "Run by user "  $(id -un)  "($USER) at "  $(/bin/date)
  1. 始终引用用户输入 :例如,使用 "$1" "$*" ,防止恶意用户输入被进一步评估和执行。
  2. 不使用eval处理用户输入 :即使引用了用户输入,也不要使用 eval 重新处理,否则用户容易破坏脚本。
  3. 引用通配符扩展结果 :创建包含特殊字符的文件名可能会对系统管理员造成危害,因此在脚本中应引用文件名参数。
  4. 检查用户输入中的元字符 :如果在 eval $(…) 中使用用户输入,要查找 $ 或反引号等元字符。
  5. 测试和审查代码 :仔细检查代码中的假设和错误,尝试找出可能被利用的漏洞并修复。
  6. 注意竞态条件 :确保攻击者无法在脚本的两个命令之间执行任意命令而破坏安全性。
  7. 怀疑符号链接 :在更改文件权限或编辑文件时,检查文件是否为符号链接,可使用 [ -L file ] [ -h file ] 进行测试。
  8. 让他人审查代码 :新的视角可能会发现原作者遗漏的问题。
  9. 尽量使用setgid而非setuid :使用 setgid 可以限制受损组可能造成的损害。
  10. 使用新用户而非root :如果必须使用 setuid 访问一组文件,考虑创建一个非root用户并设置 setuid
  11. 尽量减少setuid代码 :将 setuid 代码量减到最小,并将其移到一个单独的程序中,在必要时从较大的脚本中调用。

以下是 bash 维护者Chet Ramey提供的用于更安全脚本的代码:

# Reset IFS. Even though ksh doesn't import IFS from the environment,
# $ENV could set it.  This uses special bash and ksh93 notation,
# not in POSIX.
IFS=$' \t\n'
# Make sure unalias is not a function, since it's a regular built-in.
# unset is a special built-in, so it will be found before functions.
unset -f unalias
# Unset all aliases and quote unalias so it's not alias-expanded.
\unalias -a
# Make sure command is not a function, since it's a regular built-in.
# unset is a special built-in, so it will be found before functions.
unset -f command
# Get a reliable path prefix, handling case where getconf is not
# available.
SYSPATH="$(command -p getconf PATH 2>/dev/null)"
if [[ -z "$SYSPATH" ]]; then
        SYSPATH="/usr/bin:/bin"         # pick your poison
fi
PATH="$SYSPATH:$PATH"

3.2 受限Shell

受限shell旨在限制用户的移动和文件写入能力,通常用于来宾账户。POSIX未规定环境必须提供受限shell,但 ksh93 bash 都提供了此功能。

3.2.1 ksh93受限shell

当以 rksh 调用(或使用 –r 选项)时, ksh93 作为受限shell。可以通过在用户的 /etc/passwd 条目中设置 rksh 的完整路径名来使登录shell受限,前提是 ksh93 可执行文件有一个名为 rksh 的链接。受限 ksh93 对用户有以下限制:
- 无法更改工作目录,使用 cd 会报错 ksh: cd: restricted
- 不允许将输出重定向到文件,包括使用 exec
- 不能为环境变量 ENV FPATH PATH SHELL 分配新值,也不能使用 typeset 更改其属性。
- 不能指定包含斜杠( / )的命令路径名,只能运行 $PATH 中的命令。
- 不能使用 builtin 命令添加新的内置命令。

3.2.2 bash受限shell

当以 rbash 调用时, bash 作为受限shell,同样需要 bash 可执行文件有一个名为 rbash 的链接。 bash 的受限操作与 ksh93 类似,包括不能使用 cd 更改目录、设置或取消设置 SHELL PATH ENV BASH_ENV 等。

这些限制在用户的 .profile 和环境文件运行后生效,这意味着受限shell用户的整个环境在 .profile 中设置,系统管理员可以根据需要配置环境。为防止用户覆盖 ~/.profile ,仅将文件设置为只读是不够的,要么用户的主目录不可写,要么 .profile 中的命令应切换到不同的目录。常见的设置此类环境的方法是设置一个“安全”命令目录,并将其作为 PATH 中的唯一目录,或者设置一个特定的环境。

通过以上对shell会话、可移植性和安全性的介绍,我们可以更好地理解和使用shell,编写更健壮、安全的脚本。在实际应用中,应根据具体需求和场景选择合适的shell和编写方法,同时遵循安全建议,避免潜在的安全风险。

3.3 特洛伊木马与避免方法

“特洛伊木马”是一种恶意程序,它会伪装成正常的可执行文件,当用户在 PATH 中包含当前目录时,攻击者可以在当前目录放置一个与系统命令同名的恶意程序,当用户执行该命令时,就会执行恶意程序。

为了避免“特洛伊木马”攻击,关键在于不将当前目录( . )放入 PATH 中,确保可执行程序仅来自标准系统目录。例如,在编写脚本时,使用绝对路径调用命令,而不是依赖 PATH 来查找命令。

3.4 setuid shell脚本与Korn shell的特权模式

3.4.1 setuid和setgid的概念
  • setuid :当一个程序被设置了setuid位后,用户执行该程序时,会以该程序所有者的身份运行。例如,如果一个root用户拥有的程序设置了setuid位,普通用户执行该程序时会拥有root权限。
  • setgid :与setuid类似,但它是以程序所属组的身份运行。使用setgid可以限制可能造成的损害范围,因为它只提升组权限。
3.4.2 注意事项
  • 尽量使用setgid而非setuid,以减少潜在的安全风险。
  • 如果必须使用setuid来访问一组文件,考虑创建一个新的非root用户,并将setuid设置为该用户。
  • 要尽量减少setuid代码的数量,将其移到一个单独的程序中,并在必要时从较大的脚本中调用。同时,要以防御性的方式编写代码,假设脚本可以被任何人从任何地方调用。

4. 总结与实际应用建议

4.1 知识总结

通过前面的介绍,我们了解了shell会话的不同类型(交互式、非交互式、登录会话)及其启动和终止时调用的文件。对于Z-Shell,其启动和终止过程较为复杂,涉及多个初始化文件和脚本。同时,我们也掌握了编写安全shell脚本的重要建议,包括避免“特洛伊木马”攻击、使用受限shell、正确处理setuid和setgid等。

4.2 实际应用建议

4.2.1 脚本编写流程

为了编写安全且可移植的shell脚本,可以遵循以下流程:
1. 规划阶段 :明确脚本的功能和需求,设计脚本的整体结构。考虑可能出现的错误情况,并计划如何处理。
2. 编码阶段 :根据设计编写代码,遵循安全脚本编写的建议。使用完整路径名调用命令,检查输入参数的有效性,处理命令的错误代码等。
3. 测试阶段 :对脚本进行全面测试,尝试从攻击者的角度思考,寻找可能的漏洞。可以使用不同的输入和场景进行测试,确保脚本在各种情况下都能正常工作。
4. 审查阶段 :让他人审查代码,以发现自己可能遗漏的问题。
5. 部署阶段 :在部署脚本时,确保脚本运行的环境安全,例如设置正确的文件权限,避免将敏感信息暴露。

4.2.2 不同shell的选择
  • 如果需要兼容性和广泛的应用场景, bash 是一个不错的选择,它支持许多扩展功能,并且在大多数系统中都有预装。
  • 如果对性能和特定功能有较高要求, ksh93 可能更适合,它也有丰富的扩展和强大的编程能力。
  • zsh 具有复杂而灵活的定制功能,适合需要高度个性化配置的用户。

4.3 安全意识的重要性

在编写和使用shell脚本时,始终要保持安全意识。安全问题可能随时出现,即使是看似简单的脚本也可能存在潜在的漏洞。因此,要不断学习和更新安全知识,关注最新的安全威胁和防范方法。

5. 示例与实践

5.1 安全脚本示例

以下是一个简单的安全shell脚本示例,它遵循了前面提到的一些安全建议:

#!/bin/bash
# Reset IFS
IFS=$' \t\n'
# Unset all aliases
unset -f unalias
\unalias -a
# Set a reliable path
SYSPATH="$(command -p getconf PATH 2>/dev/null)"
if [[ -z "$SYSPATH" ]]; then
    SYSPATH="/usr/bin:/bin"
fi
PATH="$SYSPATH:$PATH"
# Check input arguments
if [ $# -ne 1 ]; then
    echo "Usage: $0 <number>"
    exit 1
fi
if ! [[ $1 =~ ^[0-9]+$ ]]; then
    echo "Error: Input must be a number."
    exit 1
fi
# Do some operations
echo "The input number is: $1"

5.2 实践操作

为了更好地掌握这些知识,可以进行以下实践操作:
- 编写脚本 :根据自己的需求编写一些简单的shell脚本,并在编写过程中应用安全建议。
- 测试脚本 :使用不同的输入和场景测试脚本,检查脚本的安全性和稳定性。
- 使用受限shell :创建一个受限shell环境,体验受限shell的功能和限制。

6. 总结

通过对shell会话、可移植性、安全性等方面的深入了解,我们可以编写更安全、更健壮的shell脚本。在实际应用中,要根据具体情况选择合适的shell和编写方法,同时始终保持安全意识,遵循安全建议,不断提高脚本的质量和安全性。

6.1 关键要点回顾

  • 不同类型的shell会话(交互式、非交互式、登录会话)在启动和终止时调用不同的文件。
  • 编写安全shell脚本的建议,如不将当前目录放入 PATH 、检查输入参数、处理错误代码等。
  • 受限shell可以限制用户的操作,提高系统的安全性。
  • 避免“特洛伊木马”攻击,正确处理setuid和setgid。

6.2 未来展望

随着技术的不断发展,shell脚本的应用场景也在不断扩大。未来,我们可以期待更强大、更安全的shell工具和防护机制的出现。同时,我们也应该不断学习和更新知识,以适应新的安全挑战。

以下是一个简单的mermaid流程图,展示了安全脚本编写的基本流程:

graph LR
    A[规划阶段] --> B[编码阶段]
    B --> C[测试阶段]
    C --> D[审查阶段]
    D --> E[部署阶段]

表格:不同shell类型的特点对比
| Shell类型 | 特点 |
| ---- | ---- |
| bash | 兼容性好,支持许多扩展功能,大多数系统预装 |
| ksh93 | 性能高,有丰富的扩展和强大的编程能力 |
| zsh | 定制功能复杂灵活,适合高度个性化配置 |

通过以上内容,希望能帮助你更好地理解和应用shell脚本的相关知识,编写安全可靠的脚本。

内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略与效果评估体系,涵盖当前企业传播面临的预算、资源、内容与效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户和自媒体四类媒体资源的特性、传播优势与发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化与GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理与舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率与ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放与GEO优化,提升品牌在AI搜索中的权威性与可见性;④通过数据驱动评估体系量化品牌影响力与销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析与工具指南进行系统学习,重点关注媒体适配性策略与GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
【EI复现】基于主从博弈的新型城镇配电系统产消者竞价策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于主从博弈理论的新型城镇配电系统中产消者竞价策略的研究,结合IEEE33节点系统进行建模与仿真分析,采用Matlab代码实现。研究聚焦于产消者(兼具发电与用电能力的主体)在配电系统中的竞价行为,运用主从博弈模型刻画配电公司与产消者之间的交互关系,通过优化算法求解均衡策略,实现利益最大化与系统运行效率提升。文中详细阐述了模型构建、博弈机制设计、求解算法实现及仿真结果分析,复现了EI期刊级别的研究成果,适用于电力市场机制设计与智能配电网优化领域。; 适合人群:具备电力系统基础知识和Matlab编程能力,从事电力市场、智能电网、能源优化等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①学习主从博弈在电力系统中的建模方法;②掌握产消者参与电力竞价的策略优化技术;③复现EI级别论文的仿真流程与结果分析;④开展配电网经济调度与市场机制设计的相关课题研究。; 阅读建议:建议读者结合提供的Matlab代码,深入理解博弈模型的数学表达与程序实现细节,重点关注目标函数构建、约束条件处理及算法收敛性分析,可进一步拓展至多主体博弈或多时间尺度优化场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值