一些不太容易注意到的 Python 安全性問題

前幾天看到「10 Unknown Security Pitfalls for Python」這篇,講 Python ecosystem 裡面的一些設計造成的安全性問題,裡面很多東西都很有趣,而且有些算是共通的,其他程式語言也會中獎...

第一個是開發者用 assert() 確認權限,但 assert() 的設計是 debug 用的功能,所以可以預期在 optimization 後會被拿掉 (其他程式語言也有類似的功能),而導致權限沒被檢查而產生 security incident。

第二個是 os.makedirs() 所指定的 mode,依照說明看起來是 Python 改變行為了,變成只有最終的那個目錄照著設定:

In Python < 3.6, the folders A, B and C are each created with permission 700. However, in Python > 3.6, only the last folder C has permission 700 and the other folders A and B are created with the default permission 755.

這個設計就有點討厭了,我測了一下 umask 077 的情況下在 shell 下執行 mkdir a/b/c,所有的目錄都會是 700

第三個是串檔名的 os.path.join(),遇到 / 開頭的部份會把前面的部份都拔掉,也就是這樣:(嗯... 這樣搞的嗎 XDDD)

>>> os.path.join('var', 'lib', 'tmp', 'abc.png')
'var/lib/tmp/abc.png'
>>> os.path.join('var', 'lib', 'tmp', '/etc/shadow')
'/etc/shadow'

第四個就是蠻標準的 variable injection 了。

第五個算是每次處理 .zip 檔都很頭痛的問題,不限於 Python,因為壓縮檔裡面可能會有 ../../ 開頭這種看起來就很邪惡的檔案名稱,只要有安全意識的工程師都覺得處理起來很麻煩的東西...

第六個一看就是壞東西,想要用黑名單擋 injection 一定會有更多有創意的方法打進來。比較特別的是這邊有提到在 Python 裡 re.search()re.match() 的差異,這點真的是寫起來有時後會忽略掉的...

第七與第八個都是 Unicode 相關的問題,也是個超級麻煩的東西,大原則是先 normalize 再 escape,但還是有點見招拆招去看...

第九個也是類似的問題,沒有先 normalize 再確認,不過一般機器都會有 private ip address,還是可以試著打... 這個有機會用架構面去解決,像是用 MQ 架設 proxy service,隔出另外一區來跑;或是已經有 zero trust 的架構,內部網路也是要帶 token 跑來跑去,可以減少一些傷害...

第十個算是 Python 自己的歷史因素,早期同時吃 &; 當作 separator,而非只吃 &x-www-form-urlencoded (HTML spec 內定義的標準):

In Python < 3.7 the function urllib.parse.parse_qsl allows the use of the ; and & characters as separators for URL query variables.

查了一下官方文件可以看到 3.10 之後才變成 x-www-form-urlencoded

Changed in version 3.10: Added separator parameter with the default value of &. Python versions earlier than Python 3.10 allowed using both ; and & as query parameter separator. This has been changed to allow only a single separator key, with & as the default separator.

有些應該是有安全意識時會去翻 spec 看看就可以避開的,但有些就真的是蠻雷的 XDDD

Leave a Reply

Your email address will not be published.