Linux入职基础-2.4_文件特殊权限与应用

本文详细介绍了Linux中的三种特殊权限:setuid、setgid和sticky bit(stickbit)。通过实际案例展示了这些权限如何影响用户执行特定程序时的行为,以及它们如何用于确保系统安全。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文件特殊权限与应用

inux中除了常见的读(r)、写(w)、执行(x)权限以外,还有3个特殊的权限,分别是setuidsetgidstick bit。如下图:

3-1

一、特殊权限设置

setuidchmod u+s xxx ;表现形式:[-rwsr-xr-x]

setgid: chmod g+s xxx ;表现形式:[-rwxr-sr-x]

stick bit : chmod o+t xxx ;表现形式:[-rwxr-xr-t]

或者:

setuid:chmod 4755 xxx

setgid:chmod 2755 xxx

stick bit:chmod 1755 xxx

二、先来简单了解进程的一些知识点

特殊权限位是与控制进程运行有关的,linux的进程至少有7个与之相关的标识:

一个真实UIDreal UID)、一个真实GIDread GID);

一个有效UIDeffectiveUID)、一个有效GIDeffective GID);

一个保存UIDsaved UID)、一个保存GIDsaved GID);

一个文件系统UIDfilesystemUID)。

read UID/GID就是进程创建者的UID/GID

EUIDeffective UID/EGID用来确定进程在任何给定的时刻对哪些资源或者文件具有访问权限,即进程在运行是其当前的虚拟身份,也就是说在进程运行时候其UIDGID可能不是创建它的用户的UIDGID,但是在一般情况下,UID/GIDEUID/EGID是一样的。

SUIDsaved UID/SGIDsaved GID)表示进程刚刚开始执行时刻,进程EUID/EGID的副本。而FSUIDfilesystem UID),它只用来对文件系统权限的判断,但在内核之外并不常用。

通常对于一个进程来说不大可能会改变它自己的归属关系状态(即默认情况UID/GID=EUID/EGID),但在一种特殊情况下,可以修改进程的EUIDEGID。当执行设置了setuidsetgid的权限位的命令时,则当该命令运行时,其EUID/EGID为该程序命令的映像文件的UID或者GID,而不是启动运行该命令的用户UID/GID。这个例子,请看下面的【例1】、【例2】、【例3】里面有/bin/touch命令的操作,可用来解释!

还有一个例子就是passwd命令,其程序命令的映像文件的UID/GID都是root,但是当一个普通用户运行这个命令时(因为passwd可执行文件设置了其他人的执行权限),则这个用户开启的passwd命令进程的EUID/EGID=root而非该普通用户。既然setuidsetgid设置后的进程的EUID/EGID不是进程启动者的UID/GID,而是进程映像文件所有者的UID/GID,故该程序“所产生的任何操作的身份都是这个虚拟”身份,即都是EUID/EGID

Set UID

s 这个标志出现在文件拥有者的 x 权限上时,是为了让一般用户在执行某些程序的时候,能够暂时具有该程序拥有者的权限。

常见场景:该位是让普通用户可以以root用户的角色运行只有root帐号才能运行的程序或命令。如下,passwd命令普通用户运行也起效果!

 [root@localhost ~]# ll /usr/bin/passwd      //普通用修改密码的命令

-rwsr-xr-x 1 root root 23420 Aug  3  2010/usr/bin/passwd    //s权限

1s权限,使用命令(/usr/bin/passwd)时,普通用户(rabbit)可用该命令拥有者(root)的权限去执行(打开/etc/shadow文件,保存用户的修改后的密码)。

[root@localhost ~]# ll /etc/shadow       //存储用户密码文件

-r-------- 1 root root 1037 Nov 16 15:52/etc/shadow //普通用户没rw权限

 [rabbit@localhost ~]$ /usr/bin/passwd

Changing password for user rabbit.

Changing password for rabbit

(current) UNIX password:

New UNIX password:

Retype new UNIX password:

passwd: all authentication tokens updated successfully.

注意:特殊权限setuid的标志s会出现在x的地方[-rwsr-xr-x]s权限只能应用在二进制的可执行文件上才有意义。

其次,有时你设置了st 权限,你会发现它变成了ST,这是因为在那个位置上你没有给它x(可执行)的权限,这样的话这样的设置是不会有效的,你可以先给它赋上x的权限,然后再给s的权限。


3-2

2新增s权限,让普通用户能读取/etc/shadow文件

[root@localhost ~]# ll /bin/cat

-rwxr-xr-x 1 root root 23132 Feb 23  2010 /bin/cat   //cat程序无s权限

[root@localhost ~]# su rabbit

[rabbit@localhost root]$ cd ~

[rabbit@localhost ~]$ cat /etc/shadow

cat: /etc/shadow: Permission denied           //读取被拒绝

//root账号给/bin/cat增加setuid位,如下:

 [rabbit@localhost ~]$ su root

Password:

[root@localhost rabbit]# chmod u+s /bin/cat    //新增s权限

[root@localhost rabbit]# ll /bin/cat

-rwsr-xr-x 1 root root 23132 Feb 23  2010 /bin/cat   //s权限了

[root@localhost rabbit]# su rabbit

[rabbit@localhost ~]$ cat /etc/shadow               //读取文件成功

root:$1$rFRCj/Fd$yRqoBC20eKpCJzghKt7Wh/:16751:0:99999:7:::

bin:*:16751:0:99999:7:::

……

Set GID

s 这个标志出现在文件群组的 x 权限上时,与 SUID 不同的是,SGID 可以针对二进制可执行文件或目录来配置。

Set GID对二进制可执行文件时,一般用户在执行某些程序的时候,能够暂时具有该程序群组的权限。看如下案例:

3、默认touch是没有设置setuidsetgid的,那么用户执行touch后的文件的UID/GID都是touch发起者的UID/GID。如下:

[rabbit@localhost ~]$ ls -l /bin/touch

-rwxr-xr-x 1 root root 42284 Feb 23  2010 /bin/touch

[rabbit@localhost ~]$ touch a.txt

[rabbit@localhost ~]$ ls -l

total 4

-rw-r--r-- 1 rabbit rabbit 0 Nov 16 23:36a.txt 

//root账号给touch增加setgid位,如下:

[rabbit@localhost ~]$ su root

Password:

[root@localhost rabbit]# chmod g+s /bin/touch

[root@localhost rabbit]# ls -l /bin/touch

-rwxr-sr-x 1 root root 42284 Feb 23  2010 /bin/touch  //s权限

//然后,普通用户(rabbit)再次touch新文件,发现文件的属组也发生了变化,如下:

[root@localhost rabbit]# su rabbit

[rabbit@localhost ~]$ touch b.txt

[rabbit@localhost ~]$ ls -l

total 8

-rw-r--r-- 1 rabbit rabbit 0 Nov 16 23:36a.txt

-rw-r--r-- 1 rabbit root   0Nov 16 23:41 b.txt  //roottouch执行程序的群属组,而非执行该程序的用户的群组(rabbit

Set GID对于目录时,在某个目录上设置了setgid权限位后,在这个目录下创建的文件具有与该目录的属组权限,而不是创建该文件的用户的属组。当然对目录设置setuid,是不起任何作用的。看下面这个例子:

4

[rabbit@localhost ~]$ mkdir a

[rabbit@localhost ~]$ mkdir b

[rabbit@localhost ~]$ mkdir c

[rabbit@localhost ~]$ ll -l

total 24

drwxr-xr-x 2 rabbit rabbit 4096 Nov 16 23:52a

drwxr-xr-x 2 rabbit rabbit 4096 Nov 16 23:52b

drwxr-xr-x 2 rabbit rabbit 4096 Nov 16 23:52c

//root用户给这三个目录分别加上权限

[root@localhost rabbit]# chmod u+s  /home/rabbit/a  //设置suid

[root@localhost rabbit]# chmod g+s  /home/rabbit/b  //设置sgid

[root@localhost rabbit]# chmod +s  /home/rabbit/c   //设置suid+sgid

[root@localhost rabbit]# ll

total 24

drwsr-xr-x 2 rabbit rabbit 4096 Nov 16 23:52 a   //目录asuid权限

drwxr-sr-x 2 rabbit rabbit 4096 Nov 16 23:52 b   //目录bsgid权限

drwsr-sr-x 2 rabbit rabbit 4096 Nov 16 23:52 c   //目录csuidsgid权限

//利用root用户新建文件,只有setgid位起到了作用,如下:

[root@localhost rabbit]# ll -l /bin/touch

-rwxr-sr-x 1 root root 42284 Feb 23  2010 /bin/touch  //文件uid/gid=root

[root@localhost rabbit]# touch a/s.txt

[root@localhost rabbit]# touch b/s.txt

[root@localhost rabbit]# touch c/s.txt

[root@localhost rabbit]# ls -l a/

-rw-r--r-- 1 root root 0 Nov 17 00:01 s.txt    //suid权限无效

[root@localhost rabbit]# ls -l b/

-rw-r--r-- 1 root rabbit 0 Nov 17 00:01 s.txt   // sgid权限有效

[root@localhost rabbit]# ls -l c/

-rw-r--r-- 1 root rabbit 0 Nov 17 00:01 s.txt   // suid权限无效、sgid权限有效

SBIT

SBIT 目前只对目录有效,对文件已没有效果。将给目录加上了SBIT权限时, 则用户只能够针对自己创建的文件或目录进行删除/更名/移动等动作(前提:该用户对目录具有 w, x 权限,即写入权限),而无法删除他人的文件。root用户除外!

5:新建共享目录给rabbittest用户使用,他们可以在里面新建文件与目录,但不能修改、删除他人的文件。

[root@localhost /]# mkdir /test

[root@localhost /]# chmod o+w,g+w,o+t test     //给目录设置SBIT

[root@localhost /]# ll -d test

drwxrwxrwt 2 root root 4096 Nov 17 09:13 test  

//rabbit用户登录 新建文件/test/a.txt,修改文件权限777

[root@localhost test]# su rabbit

bash-3.2$ touch /test/a.txt

bash-3.2$ ls -l /test/a.txt

-rw-r--r-- 1 rabbit rabbit 0 Nov 17 09:22/test/a.txt

bash-3.2$ chmod 777 /test/a.txt

bash-3.2$ ls -l /test/a.txt

-rwxrwxrwx 1 rabbit rabbit 0 Nov 17 09:22/test/a.txt  //空文件a.txt已存在

//test用户登录,做查看、修改文件内容、删除文件等实验。

[root@localhost rabbit]# su test

[test@localhost ~]$ cd /test

[test@localhost test]$ vi a.txt     //可编辑文件、保存文件内容

[test@localhost test]$ cat a.txt     //可查看文件内容

this is test`

[test@localhost test]$ cp a.txt b.txt   //可复制文件

[test@localhost test]$ ll

-rwxrwxrwx 1 rabbit rabbit 14 Nov 17 09:30a.txt

-rwxrwxr-x 1 test   test  14 Nov 17 09:48 b.txt

[test@localhost test]$ rm a.txt

rm: cannot remove `a.txt': Operation notpermitted   //不可删除文件

[test@localhost test]$ mv a.txt /home/test/

mv: cannot remove `a.txt': Operation notpermitted   //不可移动文件

//root用户可以删除文件


3-3

全局 Rules --- ## Cursor Rules for Comment Standards(注释规范 Cursor 规则) ### 1. 总体注释原则 - **目的**:注释应解释代码的**意图**(为什么这样做)、**复杂逻辑**或**非显而易见的实现细节**,而不是重复代码的字面含义。 - **简洁性**:注释应简明扼要,避免冗长或无意义的描述。 - **语言**:注释使用**中文**,确保团队成员一致理解;必要时可结合英文(如引用第三方库文档)。 - **维护性**:注释需代码同步更新,避免过时或误导性注释。 - **格式**:遵循 PEP 8 规范,注释代码对齐,使用适当的缩进空行。 ### 2. 注释类型规范 以下是项目中常用的注释类型及其具体规范,适用于 `src/`、`scripts/`、`tests/` 等目录中的 Python 代码。 #### 2.1 模块级注释(Module-Level Comments) - **位置**:位于模块顶部,紧跟 `import` 语句之前或之后。 - **内容**:描述模块的**功能**、**主要责****使用场景**。 - **格式**:使用多行注释(`"""` 或 `#`),以 `#` 开头每行对齐。 - **示例**(`src/modules/adspower/client.py`): ```python # 本模块封装 AdsPower 本地 API 客户端,用于管理浏览器实例的启动、停止状态检查。 # 主要功能包括速率限制、多进程同步错误重试机制。 # 使用时需配置 config.yaml 中的 adspower 字段。 ``` #### 2.2 函数方法注释(Function/Method Comments) - **位置**:使用 **Docstring**,位于函数或方法定义下方。 - **内容**: - 简要描述函数功能。 - 列出所有参数(`Args`)、返回值(`Returns`)可能的异常(`Raises`)。 - 可选:补充使用场景或注意事项。 - **格式**:采用 **Google 风格** Docstring,使用三引号(`"""`)。 - **规范**: - 参数返回值需包含类型注解。 - 每个部分(Args、Returns、Raises)使用缩进对齐。 - **示例**(`src/utils/config.py`): ```python def load_config(config_path: str) -> dict: """加载 YAML 配置文件并解析路径 Args: config_path (str): 配置文件路径 Returns: dict: 解析后的配置字典 Raises: FileNotFoundError: 配置文件不存在 yaml.YAMLError: 配置文件格式错误 """ ``` - **注意**:简单函数(如 getter/setter)可使用单行 Docstring,但仍需说明功能: ```python def get_logger(module_name: str) -> logging.Logger: """获取指定模块的日志记录器""" ``` #### 2.3 类注释(Class Comments) - **位置**:使用 Docstring,位于类定义下方。 - **内容**: - 描述类的**责****主要功能**。 - 列出关键属性(`Attributes`)初始化参数(`Args`)。 - 可选:说明类的主要方法或使用场景。 - **格式**:Google 风格 Docstring。 - **示例**(`src/modules/adspower/client.py`): ```python class AdsPowerLocalApi: """AdsPower 本地 API 客户端,支持多进程速率限制 Attributes: user_id (str): AdsPower 环境 ID base_url (str): API 基础 URL,从 config.yaml 加载 Args: user_id (str): AdsPower 环境 ID(必需) acc_id (str, optional): 账户标识符,默认为 user_id headless (int, optional): 无头模式(0=有界面,1=无界面),默认为 0 timeout (int, optional): 请求超时时间(秒),默认为 10 """ ``` #### 2.4 行内注释(Inline Comments) - **位置**:位于代码行末尾,代码间隔至少两个空格。 - **内容**:解释**复杂逻辑**、**魔法数字**或**特殊处理**,避免描述显而易见的内容。 - **格式**:使用 `#` 开头,简短且清晰。 - **规范**: - 行内注释应少用,仅在必要时添加。 - 避免过长,超 40 字符的注释建议改为块注释。 - **示例**(`src/modules/adspower/client.py`): ```python interval = RATE_LIMIT_INTERVALS.get(endpoint, RATE_LIMIT_INTERVALS['default']) # 获取端点特定间隔,默认为 1.0 秒 ``` #### 2.5 块注释(Block Comments) - **位置**:位于代码段之前,描述一段逻辑的**目的**或**步骤**。 - **内容**:解释多行代码的整体意图,适用于复杂算法或流程。 - **格式**:每行以 `#` 开头,代码缩进对齐,上下各空一行。 - **示例**(`src/modules/adspower/client.py`): ```python # 全局同步速率限制,确保多进程环境下 API 调用不超频 try: with RATE_LIMIT_LOCK.acquire(timeout=5): with open(RATE_LIMIT_FILE, 'r') as f: state = json.load(f) ``` #### 2.6 TODO 注释 - **位置**:位于需要后续处理的地方,可为行内或块注释。 - **内容**:说明待完成的任务、优化点或问题,包含负责人(可选)预期完成时间(推荐)。 - **格式**:使用 `# TODO:` 前缀,清晰描述任务。 - **示例**: ```python # TODO: 添加对 AdsPower API 新端点 /restart 的支持 (负责人: 张三, 预计: 2025-08-15) ``` ### 3. 注释使用场景 - **资源路径处理**: - 在使用 `resource_path` 的地方,注释说明路径用途打包环境兼容性。 - 示例(`src/utils/helpers.py`): ```python def resource_path(relative_path: str) -> str: """获取资源文件的绝对路径,支持开发 PyInstaller 打包环境 Args: relative_path (str): 相对路径,如 'config/config.yaml' Returns: str: 绝对路径 """ # 检查是否为 PyInstaller 打包环境 if hasattr(sys, '_MEIPASS'): base_path = Path(sys._MEIPASS) # 打包后的临时目录 else: base_path = Path(__file__).resolve().parent.parent.parent # 开发环境根目录 return str(base_path / relative_path) ``` - **配置加载**: - 在 `load_config` 中,注释说明配置字段的默认值异常处理逻辑。 - 示例(`src/utils/config.py`): ```python # 设置默认 rate_limit_intervals,防止配置文件缺失 if 'rate_limit_intervals' not in config['adspower']: config['adspower']['rate_limit_intervals'] = {'default': 1.0, 'start': 1.0, 'stop': 1.0, 'active': 0.5} ``` - **API 请求**: - 在 AdsPower API 调用(如 `start_remote_browser`)中,注释说明重试机制错误处理。 - 示例(`src/modules/adspower/client.py`): ```python # 重试 3 次以处理网络波动,每次间隔 1 秒 for attempt in range(3): try: response = requests.get(url, params=params, timeout=self.timeout) response.raise_for_status() return response.json() except requests.RequestException as e: if attempt < 2: time.sleep(1.0) # 等待 1 秒后重试 continue logger.error(f"请求失败: {e}") return None ``` - **日志管理**: - 在 `logger.py` 中,注释说明日志轮转机制敏感信息过滤。 - 示例(`src/utils/logger.py`): ```python # 配置日志轮转,限制文件大小为 10MB,保留最近 30 个文件 handler = RotatingFileHandler( f"{log_dir}/{datetime.today().isoformat()}.log", maxBytes=10*1024*1024, # 10MB backupCount=30 ) ``` ### 4. 注释注意事项 - **避免冗余**: - 不要注释显而易见的代码,如 `x = 1 # 设置 x 为 1`。 - 示例(不推荐): ```python config = yaml.safe_load(f) # 加载 YAML 文件 ``` - 改为(推荐): ```python config = yaml.safe_load(f) # 解析 config.yaml 并返回字典 ``` - **保持同步**: - 修改代码时,同步更新相关注释,特别是在更改函数参数或逻辑时。 - 示例:若 `load_config` 新增参数,需更新 Docstring: ```python def load_config(config_path: str, env: str = "dev") -> dict: """加载 YAML 配置文件并解析路径 Args: config_path (str): 配置文件路径 env (str, optional): 环境名称,默认为 'dev' Returns: dict: 解析后的配置字典 """ ``` - **敏感信息**: - 注释中不得包含敏感信息(如 API 密钥、用户 ID)。 - 示例(不推荐): ```python # 使用密钥 ABC123 调用 API ``` - 改为(推荐): ```python # 使用 config.yaml 中的 API 密钥调用接口 ``` - **一致性**: - 统一使用中文注释,除非引用英文文档或第三方库术语(如 `PyInstaller` 的 `_MEIPASS`)。 - 所有 Docstring 使用 Google 风格,避免混用其他风格(如 reStructuredText)。 ### 5. Cursor 提示示例 在 Cursor 中编写代码时,可使用以下提示,确保注释符合规范: - **添加函数注释**: ``` 为 src/modules/my_module.py 中的新函数 process_data 添加 Google 风格 Docstring,说明功能、参数、返回值异常,注释复杂逻辑。 ``` - **更新模块注释**: ``` 为 src/modules/adspower/client.py 添加模块级注释,描述模块配置要求,使用 # 格式。 ``` - **添加 TODO 注释**: ``` 在 src/utils/config.py 的 load_config 函数中添加 TODO 注释,说明计划支持 JSON 格式配置,包含负责人截止日期。 ``` --- 感谢您的要求!以下是基于您提供的项目目录结构代码,针对**使用安全的第三方库**的 **Cursor Rules** 补充说明。这些规则专注于在开发本地化可执行文件时选择使用安全的第三方库,确保项目的安全性、稳定性兼容性,同时符合注释规范项目结构要求。内容以中文表述,适用于 Cursor 或其他代码编辑器,并特别考虑 PyInstaller 打包环境。 --- ## Cursor Rules for Using Safe Third-Party Libraries(使用安全的第三方库 Cursor 规则) ### 1. 第三方库选择原则 - **安全性**: - 优先选择经过广泛使用社区维护的成熟库,避免使用未经充分验证或长期未更新的库。 - 检查库的 GitHub 仓库活跃度(最近提交时间、问题响应速度)安全漏洞报告(如通过 `pip-audit` 或 GitHub Dependabot)。 - 避免使用包含已知安全漏洞的库版本,定期更新到最新稳定版本。 - **兼容性**: - 确保库项目使用的 Python 版本(推荐 Python 3.8+) PyInstaller 打包环境兼容。 - 检查库是否支持跨平台(Windows、macOS、Linux),特别是针对 `data/` `config/` 文件的路径处理。 - **许可证**: - 选择项目许可证(如 MIT/Apache 2.0)兼容的库,避免使用限制性许可证(如 GPL)导致分发问题。 - 记录使用的第三方库及其许可证信息,更新 `docs/README.md` 或 `LICENSE` 文件- **最小化依赖**: - 仅引必要的库,减少打包体积潜在的安全风险。 - 示例:优先使用标准库(如 `pathlib`、`json`)替代第三方库(如 `os.path` 的替代品)。 ### 2. 当前使用的第三方库 根据您提供的代码,以下是项目中已使用的第三方库及其安全使用建议: - **`pyyaml`**:用于解析 `config.yaml`。 - **安全建议**: - 使用 `yaml.safe_load`(已实现),避免 `yaml.load` 以防止代码注风险。 - 示例(`src/utils/config.py`): ```python import yaml def load_config(config_path: str) -> dict: """加载 YAML 配置文件并解析路径""" with open(config_path, 'r') as f: config = yaml.safe_load(f) or {} # 使用 safe_load 防止代码注 return config ``` - 确保版本为最新(如 `pyyaml>=6.0`),检查漏洞(如 CVE-2020-1747)。 - **`requests`**:用于 AdsPower API 调用。 - **安全建议**: - 确保使用 HTTPS 协议(如 `http://localhost:50325` 改为 `https://` 如果支持)。 - 配置合理的超时时间(已实现,`timeout=self.timeout`)。 - 示例(`src/modules/adspower/client.py`): ```python response = requests.get( f"{self.base_url}/api/v1/browser/start", params={"user_id": self.user_id, "headless": self.headless}, timeout=self.timeout # 设置超时防止挂起 ) ``` - 定期更新到最新版本(如 `requests>=2.28`),检查漏洞(如 CVE-2023-32681)。 - **`filelock`**:用于多进程速率限制。 - **安全建议**: - 确保锁文件(如 `ads_power_rate_limit.json.lock`)存储在 `data/adspower/`,通过 `resource_path` 访问。 - 处理 `Timeout` 异常并记录日志。 - 示例(`src/modules/adspower/client.py`): ```python from filelock import FileLock, Timeout from src.utils.helpers import resource_path RATE_LIMIT_FILE = resource_path(config['adspower']['rate_limit_file']) RATE_LIMIT_LOCK = FileLock(str(RATE_LIMIT_FILE) + ".lock") def _init_rate_limit_file(self): """初始化速率控制文件""" try: with RATE_LIMIT_LOCK.acquire(timeout=5): if not RATE_LIMIT_FILE.exists(): with open(RATE_LIMIT_FILE, 'w') as f: json.dump({"start": 0, "stop": 0, "active": 0}, f) except Timeout: logger.warning(f"初始化 {RATE_LIMIT_FILE} 超时,重置文件") # 记录超时情况 ``` - 使用最新版本(如 `filelock>=3.12`)。 - **`python-dotenv`**:加载 `.env` 文件中的环境变量。 - **安全建议**: - 确保 `.env` 文件在 `.gitignore` 中,避免泄露敏感信息。 - 验证环境变量是否存在并设置默认值。 - 示例: ```python from dotenv import load_dotenv import os load_dotenv() env = os.getenv("ENV", "dev") # 设置默认环境为 dev ``` - 使用最新版本(如 `python-dotenv>=1.0`)。 - **`pyinstaller`**:用于打包可执行文件- **安全建议**: - 确保 `pyinstaller` 版本 Python 版本兼容(如 `pyinstaller>=5.0`)。 - 使用 `--clean` 选项清理缓存,减少打包错误。 - 示例打包命令: ```bash pyinstaller --clean build.spec ``` ### 3. 第三方库管理规范 - **记录依赖**: - 将所有第三方库记录在 `requirements.txt` `pyproject.toml` 中,确保版本明确。 - 示例 `requirements.txt`: ``` pyyaml>=6.0 requests>=2.28 filelock>=3.12 python-dotenv>=1.0 pyinstaller>=5.0 ``` - 示例 `pyproject.toml`: ```toml [project] name = "project_name" version = "0.1.0" dependencies = [ "pyyaml>=6.0", "requests>=2.28", "filelock>=3.12", "python-dotenv>=1.0", "pyinstaller>=5.0", ] ``` - **依赖安装**: - 使用 `pip install -r requirements.txt` 安装依赖。 - 推荐使用虚拟环境(如 `venv`)隔离项目依赖: ```bash python -m venv venv source venv/bin/activate # Linux/macOS venv\Scripts\activate # Windows pip install -r requirements.txt ``` - **依赖更新**: - 定期运行 `pip-audit` 检查依赖的安全漏洞: ```bash pip install pip-audit pip-audit -r requirements.txt ``` - 更新到最新安全版本,使用 `pip install --upgrade <package>`。 - **PyInstaller 兼容性**: - 确保第三方库在打包后正常工作,测试 `data/` `config/` 文件访问。 - 在 `build.spec` 中显式包含第三方库的数据文件: ```python from PyInstaller.utils.hooks import collect_data_files a = Analysis( ['src/main.py'], datas=[ ('config/*', 'config'), ('data/input/*', 'data/input'), ('data/adspower/*', 'data/adspower') ], hiddenimports=['yaml', 'requests', 'filelock', 'python-dotenv'] ) ``` ### 4. 安全使用第三方库的代码规范 - **配置加载(`pyyaml`)**: - 始终使用 `yaml.safe_load` 解析 YAML 文件,防止代码注- 添加注释说明安全措施: ```python import yaml from src.utils.helpers import resource_path def load_config(config_path: str) -> dict: """加载 YAML 配置文件并解析路径 Args: config_path (str): 配置文件路径 Returns: dict: 解析后的配置字典 Raises: FileNotFoundError: 配置文件不存在 yaml.YAMLError: 配置文件格式错误 """ config_path = resource_path(config_path) # 确保兼容 PyInstaller try: with open(config_path, 'r') as f: config = yaml.safe_load(f) or {} # 使用 safe_load 防止代码注 except FileNotFoundError: raise FileNotFoundError(f"配置文件 {config_path} 不存在") except yaml.YAMLError as e: raise yaml.YAMLError(f"解析配置文件 {config_path} 失败: {e}") return config ``` - **API 请求(`requests`)**: - 使用 HTTPS 协议,设置超时,处理异常。 - 添加注释说明安全性重试逻辑: ```python import requests from src.utils.logger import get_logger logger = get_logger(__name__) def start_remote_browser(self): """启动浏览器实例 Returns: str: 浏览器 WebSocket 地址(成功时) None: 失败时 """ self._rate_limit("start") # 确保速率限制 for attempt in range(3): try: response = requests.get( f"{self.base_url}/api/v1/browser/start", params={"user_id": self.user_id, "headless": self.headless}, timeout=self.timeout # 设置超时防止挂起 ) response.raise_for_status() # 检查 HTTP 状态码 data = response.json() if data.get("code") != 0: logger.error(f"启动浏览器失败: {data.get('msg', '未知错误')}") return None return data["data"]["ws"]["puppeteer"] except requests.RequestException as e: if attempt < 2: time.sleep(1.0) # 重试间隔 1 秒 continue logger.error(f"启动浏览器失败: {e}") return None ``` - **文件锁(`filelock`)**: - 使用 `resource_path` 确保锁文件路径正确。 - 处理 `Timeout` 异常并记录日志: ```python from filelock import FileLock, Timeout from src.utils.helpers import resource_path RATE_LIMIT_FILE = resource_path(config['adspower']['rate_limit_file']) RATE_LIMIT_LOCK = FileLock(str(RATE_LIMIT_FILE) + ".lock") def _init_rate_limit_file(self): """初始化速率控制文件,确保多进程安全""" try: with RATE_LIMIT_LOCK.acquire(timeout=5): # 设置 5 秒超时 if not RATE_LIMIT_FILE.exists(): with open(RATE_LIMIT_FILE, 'w') as f: json.dump({"start": 0, "stop": 0, "active": 0}, f) except Timeout: logger.warning(f"初始化 {RATE_LIMIT_FILE} 超时,重置文件") with open(RATE_LIMIT_FILE, 'w') as f: json.dump({"start": 0, "stop": 0, "active": 0}, f) ``` - **环境变量(`python-dotenv`)**: - 确保 `.env` 文件安全加载,注释说明敏感信息处理: ```python from dotenv import load_dotenv import os load_dotenv() # 加载 .env 文件中的环境变量 BASE_URL = os.getenv("ADPOWER_URL", "http://localhost:50325") # 默认值防止缺失 ``` ### 5. 注释规范(第三方库相关) - **库用途**:在模块级注释中说明使用的第三方库及其功能。 - 示例(`src/modules/adspower/client.py`): ```python # 本模块封装 AdsPower 本地 API 客户端,依赖 requests(HTTP 请求)、filelock(多进程锁) pyyaml(配置解析)。 # 所有文件路径通过 resource_path 处理,确保 PyInstaller 打包兼容。 ``` - **安全措施**:在代码中注释说明第三方库的安全使用方式。 - 示例(`src/utils/config.py`): ```python config = yaml.safe_load(f) # 使用 safe_load 防止 YAML 代码注风险 ``` - **版本说明**:在 `docs/README.md` 或模块注释中记录推荐的库版本。 - 示例(`docs/README.md`): ```markdown ## 依赖 - pyyaml>=6.0: 安全的 YAML 解析 - requests>=2.28: HTTP 请求,支持超时重试 - filelock>=3.12: 多进程文件- python-dotenv>=1.0: 环境变量加载 - pyinstaller>=5.0: 打包为可执行文件 ``` ### 6. PyInstaller 打包第三方库 - **包含依赖**: - 在 `build.spec` 中通过 `hiddenimports` 显式包含第三方库: ```python a = Analysis( ['src/main.py'], hiddenimports=['yaml', 'requests', 'filelock', 'python-dotenv'], datas=[ ('config/*', 'config'), ('data/input/*', 'data/input'), ('data/adspower/*', 'data/adspower') ] ) ``` - **测试打包**: - 打包后运行可执行文件,验证第三方库功能: - 检查 `yaml.safe_load` 是否正确解析 `config.yaml`。 - 验证 `requests` 是否能正常访问 AdsPower API。 - 确保 `filelock` 正确管理 `ads_power_rate_limit.json`。 - **日志记录**: - 在打包环境中记录第三方库相关错误: ```python try: import yaml except ImportError: logger.error("未找到 pyyaml 库,请确保已安装 pyyaml>=6.0") raise ``` ### 7. Cursor 提示示例 在 Cursor 中使用以下提示,确保第三方库安全集成: - **添加新库**: ``` 在 src/utils/ 中添加新模块 crypto.py,使用 cryptography 库(版本>=40.0)进行数据加密,添加 Google 风格 Docstring,说明安全措施,并在 requirements.txt 中记录。 ``` - **安全配置**: ``` 修改 src/utils/config.py,使用 yaml.safe_load 解析 config.yaml,添加注释说明安全性 resource_path 使用。 ``` - **打包配置**: ``` 更新 build.spec,确保包含 pyyaml、requests data/adspower/ 目录,验证 resource_path 在打包后正常工作。 ``` ### 8. 其他注意事项 - **安全扫描**: - 定期使用 `pip-audit` 检查依赖漏洞: ```bash pip-audit -r requirements.txt ``` - **最小化权限**: - 限制第三方库的权限,如避免 `requests` 访问非必要 URL。 - 示例: ```python if not self.base_url.startswith("https://"): logger.warning(f"非 HTTPS 协议 URL: {self.base_url},建议启用 HTTPS") ``` - **文档更新**: - 在 `docs/README.md` 中记录新增第三方库的用途、版本安全注意事项。 - 示例: ```markdown ### 新增依赖 - cryptography>=40.0: 用于加密敏感数据,需确保使用安全的密钥管理。 ```
最新发布
07-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值