資安宣導 — 為什麼使用 PyYaml 解析 YAML 時要使用 safe_load 才對
Posted on Jan 15, 2024 in Python 程式設計 - 中階 , Python 資訊安全 by Amo Chen ‐ 1 min read
對於任何來自未受信任來源的資料,我們都必須假設它可能含有惡意的內容。
就連 YAML 檔也是一樣的!
本文環境
- Python 3
- PyYAML 6.0.1
$ pip install PyYAML==6.0.1
yaml.load vs. yaml.safe_load
以下是一段示範的程式碼,告訴你不明來源的 YAML 檔有多危險:
# pip install PyYAML==6.0.1
import yaml
from yaml import Loader
yaml_data = """
!!python/object/apply:eval
args: ['print("Hello")']
"""
try:
parsed_data = yaml.load(yaml_data, Loader)
except yaml.YAMLError as e:
print(f"Error: {e}")
上述程式碼可以看到 yaml_data
中含有 !!python/object/apply:eval
的字串,就能夠讓 PyYMAL 在解析字串時,順便執行 Python 程式碼列印出 Hello
字串。(這段程式碼可以在 Colab 玩看看,玩之前記得安裝 PyYAML )
而這種攻擊手法之所以能夠成功,是因為 PyYAML 支援將 Python objects 在 dump 時轉為特製的 YAML tags, 例如 !!python/object
, !!python/bytes
等等,因此也支援在 load 時轉回 Python objects, 這也造成前述攻擊手法成為 1 種可能。
所以在讀取不受信任來源的 YAML 檔時,請使用 safe_load()
, 該方法只會讀取 YAML 標準定義的 tags, 就能夠防範前述攻擊手法,例如:
import yaml
yaml_data = """
!!python/object/apply:eval
args: ['print("Hello")']
"""
try:
parsed_data = yaml.safe_load(yaml_data)
except yaml.YAMLError as e:
print(f"Error: {e}")
上述程式碼將會出現以下錯誤,代表其不接受 !!python/object/apply:eval
tag:
Error: could not determine a constructor for the tag 'tag:yaml.org,2002:python/object/apply:eval'
以上!資安宣導結束!
References
https://pyyaml.org/wiki/PyYAMLDocumentation